Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
129 commits
Select commit Hold shift + click to select a range
17525b4
Renamed db to database
roll Sep 2, 2025
af4a3a8
Added dependencies
roll Sep 2, 2025
207a035
Implemented inferResourceProtocol
roll Sep 2, 2025
7922a09
Implemented database plugin
roll Sep 2, 2025
51586e1
Implemented dialect creation
roll Sep 2, 2025
b5e448a
Implemented loadTable from database
roll Sep 2, 2025
4107b19
Bootstrapped load tests
roll Sep 2, 2025
e57e4f2
Added notes
roll Sep 2, 2025
cab4f11
Implemented Sqlite driver
roll Sep 3, 2025
db3b7e1
Implemented postgres driver
roll Sep 3, 2025
4471ef0
Implemented mysql driver
roll Sep 3, 2025
543b1f6
Added overwrite flag to save
roll Sep 3, 2025
9be0b41
Bootstrapped saveTable
roll Sep 3, 2025
2d72c69
Make BaseDriver to be interface
roll Sep 3, 2025
8d76f8b
Fixed import
roll Sep 3, 2025
94f022d
Fixed sampleRows consistency
roll Sep 3, 2025
c8f1ac6
Use inferSchema
roll Sep 3, 2025
da1c663
Updated database drivers
roll Sep 3, 2025
8f89657
Implemented saveTable
roll Sep 3, 2025
c9cca7e
Initial sqlite tests
roll Sep 3, 2025
c9c9141
Started data types testing
roll Sep 4, 2025
bf0616c
Added csv save data types test
roll Sep 4, 2025
36f079c
Simplify denormalize process
roll Sep 4, 2025
bbc644b
Rebased csv on full-functional load
roll Sep 4, 2025
3f4a585
Full-functional load to arrow
roll Sep 4, 2025
90097c0
Full-functional load to json
roll Sep 4, 2025
0311ba9
Full-functional load to ods
roll Sep 4, 2025
6d714a1
Full-functional parquet table load
roll Sep 4, 2025
190a61e
Full-functional xlsx load
roll Sep 4, 2025
9830ddf
Added options to plugins
roll Sep 4, 2025
8d5b58b
Removed readTable
roll Sep 4, 2025
bc6ab94
Updated docs
roll Sep 4, 2025
5342b72
Merged validateTable/Resource
roll Sep 4, 2025
7970269
Renamed inspectTable to validateTable
roll Sep 4, 2025
a9d3ca3
Renamed normalizeTable
roll Sep 4, 2025
8f17d6a
Fixed table users
roll Sep 4, 2025
484b23b
Restructured load/save table
roll Sep 5, 2025
80cab08
Implemented parseField options
roll Sep 5, 2025
f31dcae
Rebased on inferOptions
roll Sep 5, 2025
6932f8f
Updated inferSchema
roll Sep 5, 2025
6c975e1
Merged normalize functions in table
roll Sep 5, 2025
a32561d
Bootstrapped denormalizeTable
roll Sep 5, 2025
b2aa335
Fixed type errors
roll Sep 5, 2025
c1cdef6
Rebased on reflectTable
roll Sep 5, 2025
5518e6b
Updated plugins
roll Sep 5, 2025
971b9d7
Added denormalized option
roll Sep 5, 2025
f4762af
Added inferSchema to plugin
roll Sep 6, 2025
f14f5ee
Fixed tests
roll Sep 6, 2025
bc85d62
Implemented inferSchema
roll Sep 6, 2025
d9311e2
Bootstrapped inferDatabaseSchema
roll Sep 6, 2025
88de5d5
Improved json plugin
roll Sep 6, 2025
89de668
Split json/jsonl specs
roll Sep 6, 2025
a604aa0
Revert "Split json/jsonl specs"
roll Sep 6, 2025
68dc57c
Simplified useRecording
roll Sep 6, 2025
fd99421
Added tsv support
roll Sep 6, 2025
c0d3626
Fixed resource functions in all
roll Sep 6, 2025
39e7cfe
Simplified database plugin
roll Sep 6, 2025
468c16e
Bootstrapped inferDatabaseSchema
roll Sep 6, 2025
041c1dc
Fixed database.destroy call
roll Sep 6, 2025
1502a7d
Update .gitignore
roll Sep 9, 2025
e3aa97d
Make BaseDriver an abstract class
roll Sep 9, 2025
935dec0
Implemented inferDatabaseSchema
roll Sep 9, 2025
0f7da10
Rebased on inferDatabaseSchema
roll Sep 9, 2025
6af5ed6
Moved infer test to drivers
roll Sep 9, 2025
923de81
Added infer tests
roll Sep 9, 2025
b8fd37b
Added load/save exceptions tests
roll Sep 9, 2025
3ff452f
Removed DatabasePackage
roll Sep 9, 2025
8575b05
Bootstrapped denormalizeTable
roll Sep 9, 2025
8bf7514
Bootstrapped stringifyField
roll Sep 9, 2025
717dcf1
Stringify boolean value
roll Sep 9, 2025
04d73c1
Implemented stringify for DateTime/Date/Time
roll Sep 9, 2025
a01408b
Implemented year/yearmonth stringify
roll Sep 9, 2025
57eded0
Implemented stringifyListField
roll Sep 9, 2025
23512ed
Stringify geojson/object fields
roll Sep 9, 2025
0219a9d
Added stringify support for duration
roll Sep 9, 2025
10bec82
Implemented stringify missingValues test
roll Sep 9, 2025
ef194b6
Fixed types
roll Sep 9, 2025
8f3e858
Implemented fieldNames/Types in inferSchema
roll Sep 10, 2025
17d96aa
Implemented convertTypes
roll Sep 10, 2025
c46f62c
Added yearmonth issue
roll Sep 10, 2025
914ff62
Fixed yearmonth formatting
roll Sep 10, 2025
3b577f8
Fixed year formatting
roll Sep 10, 2025
af9261a
Enabled geojson/object tests
roll Sep 10, 2025
7b3c804
Improved geopoint support
roll Sep 10, 2025
4144de7
Fixed types
roll Sep 10, 2025
f53ca97
Improved schema options
roll Sep 11, 2025
e5924fc
Added arrayType option
roll Sep 11, 2025
22baf16
Finished csv save tests
roll Sep 11, 2025
baf10c4
Use denormalize tabel in arrow
roll Sep 11, 2025
35d88de
Enabled stringify time specs
roll Sep 11, 2025
7f6771a
Enabled stringifyListField with ints
roll Sep 11, 2025
bd80077
Improved the way to write tests for types
roll Sep 11, 2025
ce35ebc
Enabled categorical test
roll Sep 11, 2025
08675f7
Added categories validation
roll Sep 11, 2025
6e0b3d0
Added support for uuid parsing
roll Sep 11, 2025
3cc30b6
Added email validation
roll Sep 11, 2025
40e726c
Added uri/binary validation
roll Sep 11, 2025
7ba3692
Support object categories
roll Sep 11, 2025
49f8d53
Support categoreis for integer
roll Sep 11, 2025
27b58c4
Finished arrow tests
roll Sep 11, 2025
281c4b9
Added json denormalization
roll Sep 11, 2025
ad164a9
Added ods denormalization
roll Sep 11, 2025
84ba0a3
Added parquet denormalization
roll Sep 11, 2025
b85c293
Added xlsx denormalization
roll Sep 11, 2025
a06ba88
Implemented driver.denormalizeSchema
roll Sep 11, 2025
6c913d4
Reworked defineTable
roll Sep 11, 2025
ff3167c
Simplified populate table
roll Sep 11, 2025
c6df007
Finished sqlite type testing
roll Sep 11, 2025
6bfde45
Fixed type errors
roll Sep 11, 2025
00e9033
Created db connection cache
roll Sep 12, 2025
313b93a
Bootstrapped loadPackageFromDatabase
roll Sep 12, 2025
31832f7
Renamed inferSchemaFromTable
roll Sep 12, 2025
dcb6105
Rebased on lru-cache
roll Sep 12, 2025
24341ba
Bootstrapped load tests
roll Sep 12, 2025
059f941
Added loadPackageFromDatabase test
roll Sep 12, 2025
0dd97b4
Extended database plugin
roll Sep 12, 2025
777c0e1
Added database plugin to all
roll Sep 12, 2025
d88409c
Added postgresql tests
roll Sep 12, 2025
0f378b3
Added mysql tests
roll Sep 12, 2025
52c10eb
Added db tests to CI
roll Sep 12, 2025
730db94
Added changesets
roll Sep 12, 2025
f9a15b8
Fixed env file usage
roll Sep 12, 2025
260d976
Fixed infer tests
roll Sep 12, 2025
af24c64
Pin sqlite version
roll Sep 12, 2025
c92634d
Updated dependencies
roll Sep 12, 2025
812bca3
Fixed building sqlite
roll Sep 12, 2025
16ddbf8
Skip sqlite on ci
roll Sep 12, 2025
ef8da54
Fixed tests
roll Sep 12, 2025
a14d988
Added database guide
roll Sep 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .changeset/clear-colts-prove.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
"@dpkit/database": minor
"@dpkit/camtrap": minor
"@dpkit/datahub": minor
"@dpkit/parquet": minor
"@dpkit/folder": minor
"@dpkit/github": minor
"@dpkit/inline": minor
"@dpkit/zenodo": minor
"@dpkit/arrow": minor
"@dpkit/table": minor
"@dpkit/ckan": minor
"@dpkit/core": minor
"@dpkit/file": minor
"@dpkit/json": minor
"@dpkit/test": minor
"@dpkit/xlsx": minor
"@dpkit/all": minor
"@dpkit/csv": minor
"@dpkit/ods": minor
"@dpkit/zip": minor
---

Added database support
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DPKIT_MYSQL_URL='<url>'
DPKIT_POSTGRESQL_URL='<url>'
23 changes: 23 additions & 0 deletions .github/workflows/general.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,26 @@ on:
jobs:
test:
runs-on: ubuntu-latest

services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: test
POSTGRES_USER: test
POSTGRES_DB: test
ports:
- 5432:5432
mysql:
image: mysql:8
env:
MYSQL_ROOT_PASSWORD: test
MYSQL_DATABASE: test
MYSQL_USER: test
MYSQL_PASSWORD: test
ports:
- 3306:3306

steps:
- name: Checkout Repo
uses: actions/checkout@v4
Expand All @@ -27,6 +47,9 @@ jobs:
run: pnpm build
- name: Test Packages
run: pnpm test
env:
DPKIT_MYSQL_URL: mysql://test:test@localhost:3306/test
DPKIT_POSTGRESQL_URL: postgresql://test:test@localhost:5432/test
- name: Upload Coverage
uses: codecov/codecov-action@v5
with:
Expand Down
7 changes: 4 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ compile/
dist/
.astro/
/docs/content/docs/reference/
**/.claude/settings.local.json
AGENTS.md
CLAUDE.md
.cursor/
.claude/
.serena/
.mcp.json
.env
2 changes: 1 addition & 1 deletion all/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# @dpkit/all

dpkit is a fast TypeScript data management framework built on top of the Data Package standard and Polars DataFrames. It supports various formats like CSV, JSON, and Parquet and integrates with data platforms such as CKAN, Zenodo, and GitHub. For more information, please visit the [documentation portal](https://dpkit.datist.io).
dpkit is a fast data management framework built on top of the Data Package standard and Polars DataFrames. It supports various formats like CSV, JSON, and Parquet and integrates with data platforms such as CKAN, Zenodo, and GitHub. For more information, please visit the [documentation portal](https://dpkit.datist.io).
1 change: 1 addition & 0 deletions all/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ export * from "@dpkit/zip"
export * from "./dialect/index.ts"
export * from "./package/index.ts"
export * from "./resource/index.ts"
export * from "./schema/index.ts"
export * from "./table/index.ts"
export * from "./plugin.ts"
1 change: 1 addition & 0 deletions all/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@dpkit/ckan": "workspace:*",
"@dpkit/core": "workspace:*",
"@dpkit/csv": "workspace:*",
"@dpkit/database": "workspace:*",
"@dpkit/datahub": "workspace:*",
"@dpkit/file": "workspace:*",
"@dpkit/folder": "workspace:*",
Expand Down
4 changes: 4 additions & 0 deletions all/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ArrowPlugin } from "@dpkit/arrow"
import { CkanPlugin } from "@dpkit/ckan"
import { CsvPlugin } from "@dpkit/csv"
import { DatabasePlugin } from "@dpkit/database"
import { DatahubPlugin } from "@dpkit/datahub"
import { FolderPlugin } from "@dpkit/folder"
import { GithubPlugin } from "@dpkit/github"
Expand Down Expand Up @@ -39,3 +40,6 @@ dpkit.register(JsonPlugin)
dpkit.register(OdsPlugin)
dpkit.register(ParquetPlugin)
dpkit.register(XlsxPlugin)

// Mixed functions
dpkit.register(DatabasePlugin)
16 changes: 10 additions & 6 deletions all/resource/infer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import type { Resource } from "@dpkit/core"
import { inferResourceFormat, inferResourceName } from "@dpkit/core"
import { prefetchFile } from "@dpkit/file"
import { inferFileBytes, inferFileEncoding, inferFileHash } from "@dpkit/file"
import { inferTable } from "../table/index.ts"
import { inferDialect } from "../dialect/index.ts"
import { inferSchema } from "../schema/index.ts"

// TODO: Support multipart resources? (clarify on the specs level)

Expand All @@ -18,6 +19,7 @@ export async function inferResource(resource: Partial<Resource>) {

if (typeof resource.path === "string") {
const localPath = await prefetchFile(resource.path)
const localResource = { ...resource, path: localPath }

if (!result.encoding) {
const encoding = await inferFileEncoding(localPath)
Expand All @@ -34,13 +36,15 @@ export async function inferResource(resource: Partial<Resource>) {
result.hash = await inferFileHash(localPath)
}

if (!result.schema) {
if (!result.dialect) {
try {
const localResource = { ...resource, path: localPath }
const { dialect, schema } = await inferTable(localResource)
result.dialect = await inferDialect(localResource)
} catch {}
}

result.dialect = dialect
result.schema = schema
if (!result.schema) {
try {
result.schema = await inferSchema(localResource)
} catch {}
}
}
Expand Down
18 changes: 14 additions & 4 deletions all/resource/validate.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import type { Descriptor, Resource } from "@dpkit/core"
import { loadResourceSchema } from "@dpkit/core"
import { loadDescriptor, validateResourceDescriptor } from "@dpkit/core"
import { validateFile } from "@dpkit/file"
import { validateTable } from "../table/index.ts"
import { validateTable } from "@dpkit/table"
import { inferSchema } from "../schema/index.ts"
import { loadTable } from "../table/index.ts"

// TODO: Support multipart resources? (clarify on the specs level)

export async function validateResource(
pathOrDescriptorOrResource: string | Descriptor | Partial<Resource>,
source: string | Descriptor | Partial<Resource>,
options?: { basepath?: string },
) {
let descriptor = pathOrDescriptorOrResource
let descriptor = source
let basepath = options?.basepath

if (typeof descriptor === "string") {
Expand Down Expand Up @@ -39,7 +42,14 @@ export async function validateResource(
try {
// TODO: rebase on not-rasing?
// It will raise if the resource is not a table
return await validateTable(resource)
let schema = await loadResourceSchema(resource.schema)
if (!schema) schema = await inferSchema(resource)

const table = await loadTable(resource, { denormalized: true })
const errors = await validateTable(table, { schema })

const valid = errors.length === 0
return { valid, errors }
} catch {}

return { valid: true, errors: [] }
Expand Down
1 change: 1 addition & 0 deletions all/schema/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { inferSchema } from "./infer.ts"
21 changes: 21 additions & 0 deletions all/schema/infer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Resource, Schema } from "@dpkit/core"
import type { InferSchemaOptions } from "@dpkit/table"
import { inferSchemaFromTable } from "@dpkit/table"
import { dpkit } from "../plugin.ts"
import { loadTable } from "../table/index.ts"

export async function inferSchema(
resource: Partial<Resource>,
options?: InferSchemaOptions,
): Promise<Schema> {
for (const plugin of dpkit.plugins) {
const schema = await plugin.inferSchema?.(resource, options)
if (schema) {
return schema
}
}

const table = await loadTable(resource, { denormalized: true })
const schema = await inferSchemaFromTable(table, options)
return schema
}
3 changes: 0 additions & 3 deletions all/table/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
export { loadTable } from "./load.ts"
export { readTable } from "./read.ts"
export { saveTable } from "./save.ts"
export { inferTable } from "./infer.ts"
export { validateTable } from "./validate.ts"
9 changes: 6 additions & 3 deletions all/table/infer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Dialect, Resource, Schema } from "@dpkit/core"
import { loadResourceDialect, loadResourceSchema } from "@dpkit/core"
import type { Table } from "@dpkit/table"
import { inferSchema } from "@dpkit/table"
import { inferSchemaFromTable } from "@dpkit/table"
import { inferDialect } from "../dialect/index.ts"
import { loadTable } from "./load.ts"

Expand All @@ -15,11 +15,14 @@ export async function inferTable(
dialect = await inferDialect(resource)
}

const table = await loadTable({ ...resource, dialect })
const table = await loadTable(
{ ...resource, dialect },
{ denormalized: true },
)

let schema = await loadResourceSchema(resource.schema)
if (!schema) {
schema = await inferSchema(table)
schema = await inferSchemaFromTable(table)
}

return { dialect, schema, table }
Expand Down
9 changes: 6 additions & 3 deletions all/table/load.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import type { Resource } from "@dpkit/core"
import type { Table } from "@dpkit/table"
import type { LoadTableOptions, Table } from "@dpkit/table"
import { dpkit } from "../plugin.ts"

export async function loadTable(resource: Partial<Resource>): Promise<Table> {
export async function loadTable(
resource: Partial<Resource>,
options?: LoadTableOptions,
): Promise<Table> {
for (const plugin of dpkit.plugins) {
const table = await plugin.loadTable?.(resource)
const table = await plugin.loadTable?.(resource, options)
if (table) {
return table
}
Expand Down
9 changes: 0 additions & 9 deletions all/table/read.ts

This file was deleted.

11 changes: 0 additions & 11 deletions all/table/validate.ts

This file was deleted.

2 changes: 1 addition & 1 deletion arrow/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# @dpkit/arrow

dpkit is a fast TypeScript data management framework built on top of the Data Package standard and Polars DataFrames. It supports various formats like CSV, JSON, and Parquet and integrates with data platforms such as CKAN, Zenodo, and GitHub. For more information, please visit the [documentation portal](https://dpkit.datist.io).
dpkit is a fast data management framework built on top of the Data Package standard and Polars DataFrames. It supports various formats like CSV, JSON, and Parquet and integrates with data platforms such as CKAN, Zenodo, and GitHub. For more information, please visit the [documentation portal](https://dpkit.datist.io).
2 changes: 1 addition & 1 deletion arrow/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"@dpkit/file": "workspace:*",
"@dpkit/table": "workspace:*",
"csv-sniffer": "^0.1.1",
"nodejs-polars": "^0.21.0"
"nodejs-polars": "^0.21.1"
},
"devDependencies": {
"@dpkit/test": "workspace:*"
Expand Down
9 changes: 6 additions & 3 deletions arrow/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import type { Resource } from "@dpkit/core"
import { inferResourceFormat } from "@dpkit/core"
import type { LoadTableOptions } from "@dpkit/table"
import type { TablePlugin } from "@dpkit/table"
import type { SaveTableOptions, Table } from "@dpkit/table"
import { loadArrowTable, saveArrowTable } from "./table/index.ts"

export class ArrowPlugin implements TablePlugin {
async loadTable(resource: Partial<Resource>) {
async loadTable(resource: Partial<Resource>, options?: LoadTableOptions) {
const isArrow = getIsArrow(resource)
if (!isArrow) return undefined

return await loadArrowTable(resource)
return await loadArrowTable(resource, options)
}

async saveTable(table: Table, options: SaveTableOptions) {
const isArrow = getIsArrow(options)
const { path, format } = options

const isArrow = getIsArrow({ path, format })
if (!isArrow) return undefined

return await saveArrowTable(table, options)
Expand Down
Binary file removed arrow/table.arrow
Binary file not shown.
4 changes: 2 additions & 2 deletions arrow/table/load.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { DataFrame } from "nodejs-polars"
import { describe, expect, it } from "vitest"
import { loadArrowTable } from "./load.ts"

describe("loadArrowTable", () => {
useRecording()
useRecording()

describe("loadArrowTable", () => {
describe("file variations", () => {
it("should load local file", async () => {
const path = getTempFilePath()
Expand Down
17 changes: 14 additions & 3 deletions arrow/table/load.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
import type { Resource } from "@dpkit/core"
import { loadResourceSchema } from "@dpkit/core"
import { prefetchFiles } from "@dpkit/file"
import type { LoadTableOptions } from "@dpkit/table"
import { inferSchemaFromTable, normalizeTable } from "@dpkit/table"
import { concat } from "nodejs-polars"
import { DataFrame } from "nodejs-polars"
import { scanIPC } from "nodejs-polars"

export async function loadArrowTable(resource: Partial<Resource>) {
export async function loadArrowTable(
resource: Partial<Resource>,
options?: LoadTableOptions,
) {
const [firstPath, ...restPaths] = await prefetchFiles(resource.path)
if (!firstPath) {
return DataFrame().lazy()
throw new Error("Resource path is not defined")
}

let table = scanIPC(firstPath)
if (restPaths.length) {
table = concat([table, ...restPaths.map(path => scanIPC(path))])
}

if (!options?.denormalized) {
let schema = await loadResourceSchema(resource.schema)
if (!schema) schema = await inferSchemaFromTable(table, options)
table = await normalizeTable(table, schema)
}

return table
}
Loading