feat: fs support with drizzle and duckdb-wasm (#30)

* feat: fs support with drizzle and duckdb-wasm

* docs: fix lint errors

* fix: apply suggestions

* fix: lockfile
This commit is contained in:
Makito
2025-02-22 21:44:13 +08:00
committed by Neko Ayaka
parent 9011d3e4ac
commit aeb17c7a7c
18 changed files with 1429 additions and 152 deletions
+1 -1
View File
@@ -63,7 +63,7 @@
},
"dependencies": {
"@date-fns/tz": "^1.2.0",
"@duckdb/duckdb-wasm": "^1.29.0",
"@duckdb/duckdb-wasm": "1.29.1-dev68.0",
"apache-arrow": "^19.0.1",
"date-fns": "^4.1.0",
"defu": "^6.1.4",
+44
View File
@@ -1,16 +1,19 @@
import type { AsyncDuckDBConnection, DuckDBBundle, DuckDBBundles, Logger } from '@duckdb/duckdb-wasm'
import type { DBStorage } from './storage'
import { AsyncDuckDB, ConsoleLogger, selectBundle, VoidLogger } from '@duckdb/duckdb-wasm'
import { defu } from 'defu'
import { getEnvironment } from './common'
import { mapStructRowData } from './format'
import { DBStorageType } from './storage'
export type ConnectOptions = ConnectRequiredOptions & ConnectOptionalOptions
export interface ConnectOptionalOptions {
bundles?: DuckDBBundles | Promise<DuckDBBundles>
logger?: boolean | Logger
storage?: DBStorage
}
export interface ConnectRequiredOptions {
@@ -75,6 +78,47 @@ export async function connect(options: ConnectOptions): Promise<DuckDBWasmClient
const db = new AsyncDuckDB(logger, worker)
await db.instantiate(bundle.mainModule, bundle.pthreadWorker)
if (opts.storage) {
switch (opts.storage.type) {
case DBStorageType.ORIGIN_PRIVATE_FS: {
try {
let strippedPath = opts.storage.path
if (strippedPath.startsWith('/')) {
// We will strip the only leading slash as it is not needed
strippedPath = strippedPath.slice(1)
}
await db.open({
path: `opfs://${strippedPath}`,
accessMode: opts.storage.accessMode,
// OPFS already uses direct IO
})
}
catch (e) {
await db.terminate()
await worker.terminate()
throw e
}
break
}
case DBStorageType.NODE_FS: {
try {
await db.open({
path: opts.storage.path,
accessMode: opts.storage.accessMode,
useDirectIO: true, // Important! Otherwise the file will be created without DB init
})
}
catch (e) {
await db.terminate()
await worker.terminate()
throw e
}
break
}
}
}
const conn = await db.connect()
return {
+1
View File
@@ -1,4 +1,5 @@
export * from './common'
export * from './duckdb'
export * from './format'
export * from './storage'
export * from './types'
+37
View File
@@ -0,0 +1,37 @@
import type { DuckDBAccessMode } from '@duckdb/duckdb-wasm'
export enum DBStorageType {
ORIGIN_PRIVATE_FS = 'origin-private-fs',
NODE_FS = 'node-fs',
}
interface PathBasedFS {
path: string
/**
* DuckDB will use {@link DuckDBAccessMode.READ_ONLY} if omitted.
*/
accessMode?: DuckDBAccessMode
}
/**
* Origin Private FS storage.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/File_System_API/Origin_private_file_system
*/
export interface DBOriginPrivateFS extends PathBasedFS {
type: DBStorageType.ORIGIN_PRIVATE_FS
/**
* Path of the file in the Origin Private FS.
*
* Leading slash is not necessary and will be omitted if provided.
*/
path: PathBasedFS['path']
}
export interface DBNodeFS extends PathBasedFS {
type: DBStorageType.NODE_FS
}
export type DBStorage = DBOriginPrivateFS | DBNodeFS