@duckdbfan/drizzle-duckdb 0.0.7 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +349 -62
- package/dist/bin/duckdb-introspect.d.ts +2 -0
- package/dist/client.d.ts +42 -0
- package/dist/columns.d.ts +100 -9
- package/dist/dialect.d.ts +27 -2
- package/dist/driver.d.ts +53 -37
- package/dist/duckdb-introspect.mjs +2890 -0
- package/dist/helpers.d.ts +1 -0
- package/dist/helpers.mjs +360 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.mjs +3015 -228
- package/dist/introspect.d.ts +74 -0
- package/dist/migrator.d.ts +3 -2
- package/dist/olap.d.ts +46 -0
- package/dist/operators.d.ts +8 -0
- package/dist/options.d.ts +7 -0
- package/dist/pool.d.ts +30 -0
- package/dist/select-builder.d.ts +31 -0
- package/dist/session.d.ts +33 -8
- package/dist/sql/ast-transformer.d.ts +33 -0
- package/dist/sql/result-mapper.d.ts +9 -0
- package/dist/sql/selection.d.ts +2 -0
- package/dist/sql/visitors/array-operators.d.ts +5 -0
- package/dist/sql/visitors/column-qualifier.d.ts +10 -0
- package/dist/sql/visitors/generate-series-alias.d.ts +13 -0
- package/dist/sql/visitors/union-with-hoister.d.ts +11 -0
- package/dist/utils.d.ts +2 -5
- package/dist/value-wrappers-core.d.ts +42 -0
- package/dist/value-wrappers.d.ts +8 -0
- package/package.json +53 -16
- package/src/bin/duckdb-introspect.ts +181 -0
- package/src/client.ts +528 -0
- package/src/columns.ts +420 -65
- package/src/dialect.ts +111 -15
- package/src/driver.ts +266 -180
- package/src/helpers.ts +18 -0
- package/src/index.ts +8 -1
- package/src/introspect.ts +935 -0
- package/src/migrator.ts +10 -5
- package/src/olap.ts +190 -0
- package/src/operators.ts +27 -0
- package/src/options.ts +25 -0
- package/src/pool.ts +274 -0
- package/src/select-builder.ts +110 -0
- package/src/session.ts +306 -66
- package/src/sql/ast-transformer.ts +170 -0
- package/src/sql/result-mapper.ts +303 -0
- package/src/sql/selection.ts +60 -0
- package/src/sql/visitors/array-operators.ts +214 -0
- package/src/sql/visitors/column-qualifier.ts +586 -0
- package/src/sql/visitors/generate-series-alias.ts +291 -0
- package/src/sql/visitors/union-with-hoister.ts +106 -0
- package/src/utils.ts +2 -222
- package/src/value-wrappers-core.ts +168 -0
- package/src/value-wrappers.ts +165 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { RowData } from './client.ts';
|
|
2
|
+
import type { DuckDBDatabase } from './driver.ts';
|
|
3
|
+
export interface IntrospectOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Database/catalog to introspect. If not specified, uses the current database
|
|
6
|
+
* (via `SELECT current_database()`). This prevents returning tables from all
|
|
7
|
+
* attached databases in MotherDuck workspaces.
|
|
8
|
+
*/
|
|
9
|
+
database?: string;
|
|
10
|
+
/**
|
|
11
|
+
* When true, introspects all attached databases instead of just the current one.
|
|
12
|
+
* Ignored if `database` is explicitly set.
|
|
13
|
+
* @default false
|
|
14
|
+
*/
|
|
15
|
+
allDatabases?: boolean;
|
|
16
|
+
schemas?: string[];
|
|
17
|
+
includeViews?: boolean;
|
|
18
|
+
useCustomTimeTypes?: boolean;
|
|
19
|
+
mapJsonAsDuckDbJson?: boolean;
|
|
20
|
+
importBasePath?: string;
|
|
21
|
+
}
|
|
22
|
+
interface DuckDbIndexRow extends RowData {
|
|
23
|
+
schema_name: string;
|
|
24
|
+
table_name: string;
|
|
25
|
+
index_name: string;
|
|
26
|
+
is_unique: boolean | null;
|
|
27
|
+
expressions: string | null;
|
|
28
|
+
}
|
|
29
|
+
export interface IntrospectedColumn {
|
|
30
|
+
name: string;
|
|
31
|
+
dataType: string;
|
|
32
|
+
columnDefault: string | null;
|
|
33
|
+
nullable: boolean;
|
|
34
|
+
characterLength: number | null;
|
|
35
|
+
numericPrecision: number | null;
|
|
36
|
+
numericScale: number | null;
|
|
37
|
+
}
|
|
38
|
+
export interface IntrospectedConstraint {
|
|
39
|
+
name: string;
|
|
40
|
+
type: string;
|
|
41
|
+
columns: string[];
|
|
42
|
+
referencedTable?: {
|
|
43
|
+
name: string;
|
|
44
|
+
schema: string;
|
|
45
|
+
columns: string[];
|
|
46
|
+
};
|
|
47
|
+
rawExpression?: string | null;
|
|
48
|
+
}
|
|
49
|
+
export interface IntrospectedTable {
|
|
50
|
+
schema: string;
|
|
51
|
+
name: string;
|
|
52
|
+
kind: 'table' | 'view';
|
|
53
|
+
columns: IntrospectedColumn[];
|
|
54
|
+
constraints: IntrospectedConstraint[];
|
|
55
|
+
indexes: DuckDbIndexRow[];
|
|
56
|
+
}
|
|
57
|
+
export interface IntrospectResult {
|
|
58
|
+
files: {
|
|
59
|
+
schemaTs: string;
|
|
60
|
+
metaJson: IntrospectedTable[];
|
|
61
|
+
relationsTs?: string;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export declare const DEFAULT_IMPORT_BASE = "@leonardovida-md/drizzle-neo-duckdb/helpers";
|
|
65
|
+
export declare function introspect(db: DuckDBDatabase, opts?: IntrospectOptions): Promise<IntrospectResult>;
|
|
66
|
+
export declare function buildDefault(defaultValue: string | null): string;
|
|
67
|
+
export declare function parseStructFields(inner: string): Array<{
|
|
68
|
+
name: string;
|
|
69
|
+
type: string;
|
|
70
|
+
}>;
|
|
71
|
+
export declare function parseMapValue(raw: string): string;
|
|
72
|
+
export declare function splitTopLevel(input: string, delimiter: string): string[];
|
|
73
|
+
export declare function toIdentifier(name: string): string;
|
|
74
|
+
export {};
|
package/dist/migrator.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { MigrationConfig } from 'drizzle-orm/migrator';
|
|
2
|
-
import type { DuckDBDatabase } from './driver';
|
|
3
|
-
export
|
|
2
|
+
import type { DuckDBDatabase } from './driver.ts';
|
|
3
|
+
export type DuckDbMigrationConfig = MigrationConfig | string;
|
|
4
|
+
export declare function migrate<TSchema extends Record<string, unknown>>(db: DuckDBDatabase<TSchema>, config: DuckDbMigrationConfig): Promise<void>;
|
package/dist/olap.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Subquery, type SQLWrapper } from 'drizzle-orm';
|
|
2
|
+
import type { AnyPgColumn, PgTable } from 'drizzle-orm/pg-core';
|
|
3
|
+
import type { PgViewBase } from 'drizzle-orm/pg-core/view-base';
|
|
4
|
+
import { SQL } from 'drizzle-orm/sql/sql';
|
|
5
|
+
import type { DuckDBDatabase } from './driver.ts';
|
|
6
|
+
export declare const countN: (expr?: SQLWrapper) => SQL<number>;
|
|
7
|
+
export declare const sumN: (expr: SQLWrapper) => SQL<number>;
|
|
8
|
+
export declare const avgN: (expr: SQLWrapper) => SQL<number>;
|
|
9
|
+
export declare const sumDistinctN: (expr: SQLWrapper) => SQL<number>;
|
|
10
|
+
export declare const percentileCont: (p: number, expr: SQLWrapper) => SQL<number>;
|
|
11
|
+
export declare const median: (expr: SQLWrapper) => SQL<number>;
|
|
12
|
+
export declare const anyValue: <T = unknown>(expr: SQLWrapper) => SQL<T>;
|
|
13
|
+
type PartitionOrder = {
|
|
14
|
+
partitionBy?: SQLWrapper | SQLWrapper[];
|
|
15
|
+
orderBy?: SQLWrapper | SQLWrapper[];
|
|
16
|
+
} | undefined;
|
|
17
|
+
export declare const rowNumber: (options?: PartitionOrder) => SQL<number>;
|
|
18
|
+
export declare const rank: (options?: PartitionOrder) => SQL<number>;
|
|
19
|
+
export declare const denseRank: (options?: PartitionOrder) => SQL<number>;
|
|
20
|
+
export declare const lag: <T = unknown>(expr: SQLWrapper, offset?: number, defaultValue?: SQLWrapper, options?: PartitionOrder) => SQL<T>;
|
|
21
|
+
export declare const lead: <T = unknown>(expr: SQLWrapper, offset?: number, defaultValue?: SQLWrapper, options?: PartitionOrder) => SQL<T>;
|
|
22
|
+
type ValueExpr = SQL | SQL.Aliased | AnyPgColumn;
|
|
23
|
+
type GroupKey = ValueExpr;
|
|
24
|
+
type MeasureMap = Record<string, ValueExpr>;
|
|
25
|
+
type NonAggMap = Record<string, ValueExpr>;
|
|
26
|
+
export declare class OlapBuilder {
|
|
27
|
+
private db;
|
|
28
|
+
private source?;
|
|
29
|
+
private keys;
|
|
30
|
+
private measureMap;
|
|
31
|
+
private nonAggregates;
|
|
32
|
+
private wrapNonAggWithAnyValue;
|
|
33
|
+
private orderByClauses;
|
|
34
|
+
constructor(db: DuckDBDatabase);
|
|
35
|
+
from(source: PgTable | Subquery | PgViewBase | SQL): this;
|
|
36
|
+
groupBy(keys: GroupKey[]): this;
|
|
37
|
+
measures(measures: MeasureMap): this;
|
|
38
|
+
selectNonAggregates(fields: NonAggMap, options?: {
|
|
39
|
+
anyValue?: boolean;
|
|
40
|
+
}): this;
|
|
41
|
+
orderBy(...clauses: ValueExpr[]): this;
|
|
42
|
+
build(): any;
|
|
43
|
+
run(): any;
|
|
44
|
+
}
|
|
45
|
+
export declare const olap: (db: DuckDBDatabase) => OlapBuilder;
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DuckDB-native array operators. Generate DuckDB-compatible SQL directly
|
|
3
|
+
* without query rewriting.
|
|
4
|
+
*/
|
|
5
|
+
import { type SQL, type SQLWrapper } from 'drizzle-orm';
|
|
6
|
+
export declare function arrayHasAll<T>(column: SQLWrapper, values: T[] | SQLWrapper): SQL;
|
|
7
|
+
export declare function arrayHasAny<T>(column: SQLWrapper, values: T[] | SQLWrapper): SQL;
|
|
8
|
+
export declare function arrayContainedBy<T>(column: SQLWrapper, values: T[] | SQLWrapper): SQL;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type PrepareCacheOption = boolean | number | {
|
|
2
|
+
size?: number;
|
|
3
|
+
};
|
|
4
|
+
export interface PreparedStatementCacheConfig {
|
|
5
|
+
size: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function resolvePrepareCacheOption(option?: PrepareCacheOption): PreparedStatementCacheConfig | undefined;
|
package/dist/pool.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { DuckDBInstance } from '@duckdb/node-api';
|
|
2
|
+
import { type DuckDBConnectionPool } from './client.ts';
|
|
3
|
+
/** Pool size presets for different MotherDuck instance types */
|
|
4
|
+
export type PoolPreset = 'pulse' | 'standard' | 'jumbo' | 'mega' | 'giga' | 'local' | 'memory';
|
|
5
|
+
/** Pool sizes optimized for each MotherDuck instance type */
|
|
6
|
+
export declare const POOL_PRESETS: Record<PoolPreset, number>;
|
|
7
|
+
export interface DuckDBPoolConfig {
|
|
8
|
+
/** Maximum concurrent connections. Defaults to 4. */
|
|
9
|
+
size?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Resolve pool configuration to a concrete size.
|
|
13
|
+
* Returns false if pooling is disabled.
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolvePoolSize(pool: DuckDBPoolConfig | PoolPreset | false | undefined): number | false;
|
|
16
|
+
export interface DuckDBConnectionPoolOptions {
|
|
17
|
+
/** Maximum concurrent connections. Defaults to 4. */
|
|
18
|
+
size?: number;
|
|
19
|
+
/** Timeout in milliseconds to wait for a connection. Defaults to 30000 (30s). */
|
|
20
|
+
acquireTimeout?: number;
|
|
21
|
+
/** Maximum number of requests waiting for a connection. Defaults to 100. */
|
|
22
|
+
maxWaitingRequests?: number;
|
|
23
|
+
/** Max time (ms) a connection may live before being recycled. */
|
|
24
|
+
maxLifetimeMs?: number;
|
|
25
|
+
/** Max idle time (ms) before an idle connection is discarded. */
|
|
26
|
+
idleTimeoutMs?: number;
|
|
27
|
+
}
|
|
28
|
+
export declare function createDuckDBConnectionPool(instance: DuckDBInstance, options?: DuckDBConnectionPoolOptions): DuckDBConnectionPool & {
|
|
29
|
+
size: number;
|
|
30
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { PgSelectBuilder, type CreatePgSelectFromBuilderMode, type SelectedFields, type TableLikeHasEmptySelection } from 'drizzle-orm/pg-core/query-builders';
|
|
2
|
+
import { PgColumn, PgTable, type PgSession } from 'drizzle-orm/pg-core';
|
|
3
|
+
import { Subquery, ViewBaseConfig, type SQLWrapper } from 'drizzle-orm';
|
|
4
|
+
import { PgViewBase } from 'drizzle-orm/pg-core/view-base';
|
|
5
|
+
import type { GetSelectTableName, GetSelectTableSelection } from 'drizzle-orm/query-builders/select.types';
|
|
6
|
+
import { SQL, type ColumnsSelection } from 'drizzle-orm/sql/sql';
|
|
7
|
+
import type { DuckDBDialect } from './dialect.ts';
|
|
8
|
+
import { type DrizzleTypeError } from 'drizzle-orm/utils';
|
|
9
|
+
interface PgViewBaseInternal<TName extends string = string, TExisting extends boolean = boolean, TSelectedFields extends ColumnsSelection = ColumnsSelection> extends PgViewBase<TName, TExisting, TSelectedFields> {
|
|
10
|
+
[ViewBaseConfig]?: {
|
|
11
|
+
selectedFields: SelectedFields;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export declare class DuckDBSelectBuilder<TSelection extends SelectedFields | undefined, TBuilderMode extends 'db' | 'qb' = 'db'> extends PgSelectBuilder<TSelection, TBuilderMode> {
|
|
15
|
+
private _fields;
|
|
16
|
+
private _session;
|
|
17
|
+
private _dialect;
|
|
18
|
+
private _withList;
|
|
19
|
+
private _distinct;
|
|
20
|
+
constructor(config: {
|
|
21
|
+
fields: TSelection;
|
|
22
|
+
session: PgSession | undefined;
|
|
23
|
+
dialect: DuckDBDialect;
|
|
24
|
+
withList?: Subquery[];
|
|
25
|
+
distinct?: boolean | {
|
|
26
|
+
on: (PgColumn | SQLWrapper)[];
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
from<TFrom extends PgTable | Subquery | PgViewBaseInternal | SQL>(source: TableLikeHasEmptySelection<TFrom> extends true ? DrizzleTypeError<"Cannot reference a data-modifying statement subquery if it doesn't contain a `returning` clause"> : TFrom): CreatePgSelectFromBuilderMode<TBuilderMode, GetSelectTableName<TFrom>, TSelection extends undefined ? GetSelectTableSelection<TFrom> : TSelection, TSelection extends undefined ? 'single' : 'partial'>;
|
|
30
|
+
}
|
|
31
|
+
export {};
|
package/dist/session.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type { Connection, Database, RowData } from 'duckdb-async';
|
|
2
1
|
import { entityKind } from 'drizzle-orm/entity';
|
|
3
|
-
import {
|
|
2
|
+
import type { Logger } from 'drizzle-orm/logger';
|
|
4
3
|
import { PgTransaction } from 'drizzle-orm/pg-core';
|
|
5
4
|
import type { SelectedFieldsOrdered } from 'drizzle-orm/pg-core/query-builders/select.types';
|
|
6
5
|
import type { PgTransactionConfig, PreparedQueryConfig, PgQueryResultHKT } from 'drizzle-orm/pg-core/session';
|
|
@@ -8,41 +7,67 @@ import { PgPreparedQuery, PgSession } from 'drizzle-orm/pg-core/session';
|
|
|
8
7
|
import type { RelationalSchemaConfig, TablesRelationalConfig } from 'drizzle-orm/relations';
|
|
9
8
|
import { type Query, SQL } from 'drizzle-orm/sql/sql';
|
|
10
9
|
import type { Assume } from 'drizzle-orm/utils';
|
|
11
|
-
import type { DuckDBDialect } from './dialect';
|
|
12
|
-
|
|
10
|
+
import type { DuckDBDialect } from './dialect.ts';
|
|
11
|
+
import type { DuckDBClientLike, RowData } from './client.ts';
|
|
12
|
+
import { type ExecuteBatchesRawChunk, type ExecuteInBatchesOptions } from './client.ts';
|
|
13
|
+
import type { PreparedStatementCacheConfig } from './options.ts';
|
|
14
|
+
export type { DuckDBClientLike, RowData } from './client.ts';
|
|
13
15
|
export declare class DuckDBPreparedQuery<T extends PreparedQueryConfig> extends PgPreparedQuery<T> {
|
|
14
16
|
private client;
|
|
17
|
+
private dialect;
|
|
15
18
|
private queryString;
|
|
16
19
|
private params;
|
|
17
20
|
private logger;
|
|
18
21
|
private fields;
|
|
19
22
|
private _isResponseInArrayMode;
|
|
20
|
-
private customResultMapper
|
|
23
|
+
private customResultMapper;
|
|
24
|
+
private rejectStringArrayLiterals;
|
|
25
|
+
private prepareCache;
|
|
26
|
+
private warnOnStringArrayLiteral?;
|
|
21
27
|
static readonly [entityKind]: string;
|
|
22
|
-
constructor(client:
|
|
28
|
+
constructor(client: DuckDBClientLike, dialect: DuckDBDialect, queryString: string, params: unknown[], logger: Logger, fields: SelectedFieldsOrdered | undefined, _isResponseInArrayMode: boolean, customResultMapper: ((rows: unknown[][]) => T['execute']) | undefined, rejectStringArrayLiterals: boolean, prepareCache: PreparedStatementCacheConfig | undefined, warnOnStringArrayLiteral?: ((sql: string) => void) | undefined);
|
|
23
29
|
execute(placeholderValues?: Record<string, unknown> | undefined): Promise<T['execute']>;
|
|
24
30
|
all(placeholderValues?: Record<string, unknown> | undefined): Promise<T['all']>;
|
|
25
31
|
isResponseInArrayMode(): boolean;
|
|
26
32
|
}
|
|
27
33
|
export interface DuckDBSessionOptions {
|
|
28
34
|
logger?: Logger;
|
|
35
|
+
rejectStringArrayLiterals?: boolean;
|
|
36
|
+
prepareCache?: PreparedStatementCacheConfig;
|
|
29
37
|
}
|
|
30
38
|
export declare class DuckDBSession<TFullSchema extends Record<string, unknown> = Record<string, never>, TSchema extends TablesRelationalConfig = Record<string, never>> extends PgSession<DuckDBQueryResultHKT, TFullSchema, TSchema> {
|
|
31
39
|
private client;
|
|
32
40
|
private schema;
|
|
33
41
|
private options;
|
|
34
42
|
static readonly [entityKind]: string;
|
|
43
|
+
protected dialect: DuckDBDialect;
|
|
35
44
|
private logger;
|
|
36
|
-
|
|
45
|
+
private rejectStringArrayLiterals;
|
|
46
|
+
private prepareCache;
|
|
47
|
+
private hasWarnedArrayLiteral;
|
|
48
|
+
private rollbackOnly;
|
|
49
|
+
constructor(client: DuckDBClientLike, dialect: DuckDBDialect, schema: RelationalSchemaConfig<TSchema> | undefined, options?: DuckDBSessionOptions);
|
|
37
50
|
prepareQuery<T extends PreparedQueryConfig = PreparedQueryConfig>(query: Query, fields: SelectedFieldsOrdered | undefined, name: string | undefined, isResponseInArrayMode: boolean, customResultMapper?: (rows: unknown[][]) => T['execute']): PgPreparedQuery<T>;
|
|
38
|
-
|
|
51
|
+
execute<T>(query: SQL): Promise<T>;
|
|
52
|
+
all<T = unknown>(query: SQL): Promise<T[]>;
|
|
53
|
+
transaction<T>(transaction: (tx: DuckDBTransaction<TFullSchema, TSchema>) => Promise<T>, config?: PgTransactionConfig): Promise<T>;
|
|
54
|
+
private warnOnStringArrayLiteral;
|
|
55
|
+
executeBatches<T extends RowData = RowData>(query: SQL, options?: ExecuteInBatchesOptions): AsyncGenerator<GenericRowData<T>[], void, void>;
|
|
56
|
+
executeBatchesRaw(query: SQL, options?: ExecuteInBatchesOptions): AsyncGenerator<ExecuteBatchesRawChunk, void, void>;
|
|
57
|
+
executeArrow(query: SQL): Promise<unknown>;
|
|
58
|
+
markRollbackOnly(): void;
|
|
59
|
+
isRollbackOnly(): boolean;
|
|
39
60
|
}
|
|
40
61
|
export declare class DuckDBTransaction<TFullSchema extends Record<string, unknown>, TSchema extends TablesRelationalConfig> extends PgTransaction<DuckDBQueryResultHKT, TFullSchema, TSchema> {
|
|
41
62
|
static readonly [entityKind]: string;
|
|
42
63
|
rollback(): never;
|
|
43
64
|
getTransactionConfigSQL(config: PgTransactionConfig): SQL;
|
|
44
65
|
setTransaction(config: PgTransactionConfig): Promise<void>;
|
|
66
|
+
executeBatches<T extends RowData = RowData>(query: SQL, options?: ExecuteInBatchesOptions): AsyncGenerator<GenericRowData<T>[], void, void>;
|
|
67
|
+
executeBatchesRaw(query: SQL, options?: ExecuteInBatchesOptions): AsyncGenerator<ExecuteBatchesRawChunk, void, void>;
|
|
68
|
+
executeArrow(query: SQL): Promise<unknown>;
|
|
45
69
|
transaction<T>(transaction: (tx: DuckDBTransaction<TFullSchema, TSchema>) => Promise<T>): Promise<T>;
|
|
70
|
+
private runNestedWithoutSavepoint;
|
|
46
71
|
}
|
|
47
72
|
export type GenericRowData<T extends RowData = RowData> = T;
|
|
48
73
|
export type GenericTableData<T = RowData> = T[];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AST-based SQL transformer for DuckDB compatibility.
|
|
3
|
+
*
|
|
4
|
+
* Transforms:
|
|
5
|
+
* - Array operators: @>, <@, && -> array_has_all(), array_has_any()
|
|
6
|
+
* - JOIN column qualification: "col" = "col" -> "left"."col" = "right"."col"
|
|
7
|
+
*
|
|
8
|
+
* Performance optimizations:
|
|
9
|
+
* - LRU cache for transformed queries (avoids re-parsing identical queries)
|
|
10
|
+
* - Smart heuristics to skip JOIN qualification when not needed
|
|
11
|
+
* - Early exit when no transformation is required
|
|
12
|
+
*/
|
|
13
|
+
export type TransformResult = {
|
|
14
|
+
sql: string;
|
|
15
|
+
transformed: boolean;
|
|
16
|
+
};
|
|
17
|
+
export declare function transformSQL(query: string): TransformResult;
|
|
18
|
+
/**
|
|
19
|
+
* Clear the transformation cache. Useful for testing or memory management.
|
|
20
|
+
*/
|
|
21
|
+
export declare function clearTransformCache(): void;
|
|
22
|
+
/**
|
|
23
|
+
* Get current cache statistics for monitoring.
|
|
24
|
+
*/
|
|
25
|
+
export declare function getTransformCacheStats(): {
|
|
26
|
+
size: number;
|
|
27
|
+
maxSize: number;
|
|
28
|
+
};
|
|
29
|
+
export declare function needsTransformation(query: string): boolean;
|
|
30
|
+
export { transformArrayOperators } from './visitors/array-operators.ts';
|
|
31
|
+
export { qualifyJoinColumns } from './visitors/column-qualifier.ts';
|
|
32
|
+
export { rewriteGenerateSeriesAliases } from './visitors/generate-series-alias.ts';
|
|
33
|
+
export { hoistUnionWith } from './visitors/union-with-hoister.ts';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type AnyColumn, type SelectedFieldsOrdered } from 'drizzle-orm';
|
|
2
|
+
export declare function normalizeInet(value: unknown): unknown;
|
|
3
|
+
export declare function normalizeTimestampString(value: unknown, withTimezone: boolean): string | unknown;
|
|
4
|
+
export declare function normalizeTimestamp(value: unknown, withTimezone: boolean): Date | unknown;
|
|
5
|
+
export declare function normalizeDateString(value: unknown): string | unknown;
|
|
6
|
+
export declare function normalizeDateValue(value: unknown): Date | unknown;
|
|
7
|
+
export declare function normalizeTime(value: unknown): string | unknown;
|
|
8
|
+
export declare function normalizeInterval(value: unknown): string | unknown;
|
|
9
|
+
export declare function mapResultRow<TResult>(columns: SelectedFieldsOrdered<AnyColumn>, row: unknown[], joinsNotNullableMap: Record<string, boolean> | undefined): TResult;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AST visitor to qualify unqualified column references in JOIN ON clauses.
|
|
3
|
+
*
|
|
4
|
+
* Performance optimizations:
|
|
5
|
+
* - Early exit when no unqualified columns found in ON clause
|
|
6
|
+
* - Skip processing if all columns are already qualified
|
|
7
|
+
* - Minimal tree traversal when possible
|
|
8
|
+
*/
|
|
9
|
+
import type { AST } from 'node-sql-parser';
|
|
10
|
+
export declare function qualifyJoinColumns(ast: AST | AST[]): boolean;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AST visitor to rewrite Postgres style generate_series aliases.
|
|
3
|
+
*
|
|
4
|
+
* Postgres lets you reference a generate_series alias as a column:
|
|
5
|
+
* FROM generate_series(...) AS gs
|
|
6
|
+
* SELECT gs::date
|
|
7
|
+
*
|
|
8
|
+
* DuckDB treats gs as a table alias, and the column is generate_series.
|
|
9
|
+
* This visitor rewrites unqualified column refs that match a
|
|
10
|
+
* generate_series alias to gs.generate_series.
|
|
11
|
+
*/
|
|
12
|
+
import type { AST } from 'node-sql-parser';
|
|
13
|
+
export declare function rewriteGenerateSeriesAliases(ast: AST | AST[]): boolean;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AST visitor to hoist WITH clauses out of UNION and other set operations.
|
|
3
|
+
*
|
|
4
|
+
* Drizzle can emit SQL like:
|
|
5
|
+
* (with a as (...) select ...) union (with b as (...) select ...)
|
|
6
|
+
*
|
|
7
|
+
* DuckDB 1.4.x has an internal binder bug for this pattern.
|
|
8
|
+
* We merge per arm CTEs into a single top level WITH when names do not collide.
|
|
9
|
+
*/
|
|
10
|
+
import type { AST } from 'node-sql-parser';
|
|
11
|
+
export declare function hoistUnionWith(ast: AST | AST[]): boolean;
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export declare function mapResultRow<TResult>(columns: SelectedFieldsOrdered<AnyColumn>, row: unknown[], joinsNotNullableMap: Record<string, boolean> | undefined): TResult;
|
|
4
|
-
export declare function aliasFields(fields: SelectedFields, fullJoin?: boolean): SelectedFields;
|
|
5
|
-
export declare function queryAdapter(query: string): string;
|
|
1
|
+
export { aliasFields } from './sql/selection.ts';
|
|
2
|
+
export { mapResultRow } from './sql/result-mapper.ts';
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DuckDB wrapper value helpers that are safe for client-side bundles.
|
|
3
|
+
* These utilities only tag values; conversion to native bindings lives
|
|
4
|
+
* in value-wrappers.ts to avoid pulling @duckdb/node-api into browsers.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DUCKDB_VALUE_MARKER: unique symbol;
|
|
7
|
+
export type DuckDBValueKind = 'list' | 'array' | 'struct' | 'map' | 'timestamp' | 'blob' | 'json';
|
|
8
|
+
export interface DuckDBValueWrapper<TKind extends DuckDBValueKind = DuckDBValueKind, TData = unknown> {
|
|
9
|
+
readonly [DUCKDB_VALUE_MARKER]: true;
|
|
10
|
+
readonly kind: TKind;
|
|
11
|
+
readonly data: TData;
|
|
12
|
+
}
|
|
13
|
+
export interface ListValueWrapper extends DuckDBValueWrapper<'list', unknown[]> {
|
|
14
|
+
readonly elementType?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ArrayValueWrapper extends DuckDBValueWrapper<'array', unknown[]> {
|
|
17
|
+
readonly elementType?: string;
|
|
18
|
+
readonly fixedLength?: number;
|
|
19
|
+
}
|
|
20
|
+
export interface StructValueWrapper extends DuckDBValueWrapper<'struct', Record<string, unknown>> {
|
|
21
|
+
readonly schema?: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
export interface MapValueWrapper extends DuckDBValueWrapper<'map', Record<string, unknown>> {
|
|
24
|
+
readonly valueType?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface TimestampValueWrapper extends DuckDBValueWrapper<'timestamp', Date | string | number | bigint> {
|
|
27
|
+
readonly withTimezone: boolean;
|
|
28
|
+
readonly precision?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface BlobValueWrapper extends DuckDBValueWrapper<'blob', Buffer | Uint8Array> {
|
|
31
|
+
}
|
|
32
|
+
export interface JsonValueWrapper extends DuckDBValueWrapper<'json', unknown> {
|
|
33
|
+
}
|
|
34
|
+
export type AnyDuckDBValueWrapper = ListValueWrapper | ArrayValueWrapper | StructValueWrapper | MapValueWrapper | TimestampValueWrapper | BlobValueWrapper | JsonValueWrapper;
|
|
35
|
+
export declare function isDuckDBWrapper(value: unknown): value is AnyDuckDBValueWrapper;
|
|
36
|
+
export declare function wrapList(data: unknown[], elementType?: string): ListValueWrapper;
|
|
37
|
+
export declare function wrapArray(data: unknown[], elementType?: string, fixedLength?: number): ArrayValueWrapper;
|
|
38
|
+
export declare function wrapStruct(data: Record<string, unknown>, schema?: Record<string, string>): StructValueWrapper;
|
|
39
|
+
export declare function wrapMap(data: Record<string, unknown>, valueType?: string): MapValueWrapper;
|
|
40
|
+
export declare function wrapTimestamp(data: Date | string | number | bigint, withTimezone: boolean, precision?: number): TimestampValueWrapper;
|
|
41
|
+
export declare function wrapBlob(data: Buffer | Uint8Array): BlobValueWrapper;
|
|
42
|
+
export declare function wrapJson(data: unknown): JsonValueWrapper;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type DuckDBValue } from '@duckdb/node-api';
|
|
2
|
+
import { type AnyDuckDBValueWrapper } from './value-wrappers-core.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Convert a wrapper to a DuckDB Node API value.
|
|
5
|
+
* Uses exhaustive switch for compile-time safety.
|
|
6
|
+
*/
|
|
7
|
+
export declare function wrapperToNodeApiValue(wrapper: AnyDuckDBValueWrapper, toValue: (v: unknown) => DuckDBValue): DuckDBValue;
|
|
8
|
+
export { DUCKDB_VALUE_MARKER, isDuckDBWrapper, wrapArray, wrapBlob, wrapJson, wrapList, wrapMap, wrapStruct, wrapTimestamp, type AnyDuckDBValueWrapper, type DuckDBValueWrapper, type ArrayValueWrapper, type BlobValueWrapper, type JsonValueWrapper, type ListValueWrapper, type MapValueWrapper, type StructValueWrapper, type TimestampValueWrapper, type DuckDBValueKind, } from './value-wrappers-core.ts';
|
package/package.json
CHANGED
|
@@ -1,36 +1,70 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@duckdbfan/drizzle-duckdb",
|
|
3
|
-
"module": "index.
|
|
4
|
-
"main": "dist/index.mjs",
|
|
5
|
-
"types": "dist/index.d.ts",
|
|
6
|
-
"version": "
|
|
3
|
+
"module": "./dist/index.mjs",
|
|
4
|
+
"main": "./dist/index.mjs",
|
|
5
|
+
"types": "./dist/index.d.ts",
|
|
6
|
+
"version": "1.3.2",
|
|
7
7
|
"description": "A drizzle ORM client for use with DuckDB. Based on drizzle's Postgres client.",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"scripts": {
|
|
10
|
-
"build": "bun build --target=node ./src/index.ts --outfile=./dist/index.mjs --packages=external && bun run build:declarations",
|
|
10
|
+
"build": "bun build --target=node ./src/index.ts --outfile=./dist/index.mjs --packages=external && bun build --target=node ./src/helpers.ts --outfile=./dist/helpers.mjs --packages=external && bun build --target=node ./src/bin/duckdb-introspect.ts --outfile=./dist/duckdb-introspect.mjs --packages=external && bun run build:declarations",
|
|
11
11
|
"build:declarations": "tsc --emitDeclarationOnly --project tsconfig.types.json",
|
|
12
12
|
"test": "vitest",
|
|
13
|
-
"t": "vitest --watch --ui"
|
|
13
|
+
"t": "vitest --watch --ui",
|
|
14
|
+
"bench": "vitest bench --run test/perf --pool=threads --poolOptions.threads.singleThread=true --no-file-parallelism",
|
|
15
|
+
"perf:run": "bun run scripts/run-perf.ts",
|
|
16
|
+
"perf:compare": "bun run scripts/compare-perf.ts",
|
|
17
|
+
"publish:dual": "bun run scripts/publish-dual.ts",
|
|
18
|
+
"publish:dual:dry": "bun run scripts/publish-dual.ts --dry-run"
|
|
19
|
+
},
|
|
20
|
+
"bin": {
|
|
21
|
+
"duckdb-introspect": "dist/duckdb-introspect.mjs"
|
|
14
22
|
},
|
|
15
23
|
"peerDependencies": {
|
|
16
|
-
"
|
|
17
|
-
"
|
|
24
|
+
"@duckdb/node-api": "1.4.4-r.1",
|
|
25
|
+
"drizzle-orm": "^0.40.0"
|
|
26
|
+
},
|
|
27
|
+
"peerDependenciesMeta": {
|
|
28
|
+
"@duckdb/node-api": {
|
|
29
|
+
"optional": true
|
|
30
|
+
}
|
|
18
31
|
},
|
|
19
32
|
"devDependencies": {
|
|
33
|
+
"@duckdb/node-api": "1.4.4-r.1",
|
|
20
34
|
"@types/bun": "^1.2.5",
|
|
21
35
|
"@types/uuid": "^10.0.0",
|
|
22
36
|
"@vitest/ui": "^1.6.0",
|
|
23
37
|
"drizzle-orm": "0.40.0",
|
|
24
|
-
"duckdb-async": "^1.2.0",
|
|
25
38
|
"prettier": "^3.5.3",
|
|
26
39
|
"typescript": "^5.8.2",
|
|
27
40
|
"uuid": "^10.0.0",
|
|
28
|
-
"vitest": "^1.6.0"
|
|
41
|
+
"vitest": "^1.6.0",
|
|
42
|
+
"tinybench": "^2.7.1"
|
|
29
43
|
},
|
|
30
44
|
"repository": {
|
|
31
45
|
"type": "git",
|
|
32
|
-
"url": "git+https://github.com/
|
|
46
|
+
"url": "git+https://github.com/leonardovida/drizzle-duckdb.git"
|
|
47
|
+
},
|
|
48
|
+
"exports": {
|
|
49
|
+
".": {
|
|
50
|
+
"types": "./dist/index.d.ts",
|
|
51
|
+
"import": "./dist/index.mjs"
|
|
52
|
+
},
|
|
53
|
+
"./helpers": {
|
|
54
|
+
"types": "./dist/helpers.d.ts",
|
|
55
|
+
"import": "./dist/helpers.mjs"
|
|
56
|
+
},
|
|
57
|
+
"./package.json": "./package.json"
|
|
33
58
|
},
|
|
59
|
+
"sideEffects": false,
|
|
60
|
+
"publishConfig": {
|
|
61
|
+
"access": "public",
|
|
62
|
+
"registry": "https://registry.npmjs.org"
|
|
63
|
+
},
|
|
64
|
+
"engines": {
|
|
65
|
+
"node": ">=18.17"
|
|
66
|
+
},
|
|
67
|
+
"packageManager": "bun@1.3.6",
|
|
34
68
|
"keywords": [
|
|
35
69
|
"drizzle",
|
|
36
70
|
"duckdb"
|
|
@@ -38,12 +72,15 @@
|
|
|
38
72
|
"author": "M L",
|
|
39
73
|
"license": "Apache-2.0",
|
|
40
74
|
"bugs": {
|
|
41
|
-
"url": "https://github.com/
|
|
75
|
+
"url": "https://github.com/leonardovida/drizzle-duckdb/issues"
|
|
42
76
|
},
|
|
43
|
-
"homepage": "https://github.com/
|
|
77
|
+
"homepage": "https://github.com/leonardovida/drizzle-duckdb#readme",
|
|
44
78
|
"files": [
|
|
45
|
-
"src
|
|
79
|
+
"src/**/*.ts",
|
|
46
80
|
"dist/*.mjs",
|
|
47
|
-
"dist
|
|
48
|
-
]
|
|
81
|
+
"dist/**/*.d.ts"
|
|
82
|
+
],
|
|
83
|
+
"dependencies": {
|
|
84
|
+
"node-sql-parser": "^5.3.13"
|
|
85
|
+
}
|
|
49
86
|
}
|