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:
@@ -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",
|
||||
|
||||
@@ -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,4 +1,5 @@
|
||||
export * from './common'
|
||||
export * from './duckdb'
|
||||
export * from './format'
|
||||
export * from './storage'
|
||||
export * from './types'
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user