@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.
Files changed (55) hide show
  1. package/README.md +349 -62
  2. package/dist/bin/duckdb-introspect.d.ts +2 -0
  3. package/dist/client.d.ts +42 -0
  4. package/dist/columns.d.ts +100 -9
  5. package/dist/dialect.d.ts +27 -2
  6. package/dist/driver.d.ts +53 -37
  7. package/dist/duckdb-introspect.mjs +2890 -0
  8. package/dist/helpers.d.ts +1 -0
  9. package/dist/helpers.mjs +360 -0
  10. package/dist/index.d.ts +7 -0
  11. package/dist/index.mjs +3015 -228
  12. package/dist/introspect.d.ts +74 -0
  13. package/dist/migrator.d.ts +3 -2
  14. package/dist/olap.d.ts +46 -0
  15. package/dist/operators.d.ts +8 -0
  16. package/dist/options.d.ts +7 -0
  17. package/dist/pool.d.ts +30 -0
  18. package/dist/select-builder.d.ts +31 -0
  19. package/dist/session.d.ts +33 -8
  20. package/dist/sql/ast-transformer.d.ts +33 -0
  21. package/dist/sql/result-mapper.d.ts +9 -0
  22. package/dist/sql/selection.d.ts +2 -0
  23. package/dist/sql/visitors/array-operators.d.ts +5 -0
  24. package/dist/sql/visitors/column-qualifier.d.ts +10 -0
  25. package/dist/sql/visitors/generate-series-alias.d.ts +13 -0
  26. package/dist/sql/visitors/union-with-hoister.d.ts +11 -0
  27. package/dist/utils.d.ts +2 -5
  28. package/dist/value-wrappers-core.d.ts +42 -0
  29. package/dist/value-wrappers.d.ts +8 -0
  30. package/package.json +53 -16
  31. package/src/bin/duckdb-introspect.ts +181 -0
  32. package/src/client.ts +528 -0
  33. package/src/columns.ts +420 -65
  34. package/src/dialect.ts +111 -15
  35. package/src/driver.ts +266 -180
  36. package/src/helpers.ts +18 -0
  37. package/src/index.ts +8 -1
  38. package/src/introspect.ts +935 -0
  39. package/src/migrator.ts +10 -5
  40. package/src/olap.ts +190 -0
  41. package/src/operators.ts +27 -0
  42. package/src/options.ts +25 -0
  43. package/src/pool.ts +274 -0
  44. package/src/select-builder.ts +110 -0
  45. package/src/session.ts +306 -66
  46. package/src/sql/ast-transformer.ts +170 -0
  47. package/src/sql/result-mapper.ts +303 -0
  48. package/src/sql/selection.ts +60 -0
  49. package/src/sql/visitors/array-operators.ts +214 -0
  50. package/src/sql/visitors/column-qualifier.ts +586 -0
  51. package/src/sql/visitors/generate-series-alias.ts +291 -0
  52. package/src/sql/visitors/union-with-hoister.ts +106 -0
  53. package/src/utils.ts +2 -222
  54. package/src/value-wrappers-core.ts +168 -0
  55. package/src/value-wrappers.ts +165 -0
@@ -0,0 +1,168 @@
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 const DUCKDB_VALUE_MARKER = Symbol.for('drizzle-duckdb:value');
7
+
8
+ export type DuckDBValueKind =
9
+ | 'list'
10
+ | 'array'
11
+ | 'struct'
12
+ | 'map'
13
+ | 'timestamp'
14
+ | 'blob'
15
+ | 'json';
16
+
17
+ export interface DuckDBValueWrapper<
18
+ TKind extends DuckDBValueKind = DuckDBValueKind,
19
+ TData = unknown,
20
+ > {
21
+ readonly [DUCKDB_VALUE_MARKER]: true;
22
+ readonly kind: TKind;
23
+ readonly data: TData;
24
+ }
25
+
26
+ export interface ListValueWrapper extends DuckDBValueWrapper<
27
+ 'list',
28
+ unknown[]
29
+ > {
30
+ readonly elementType?: string;
31
+ }
32
+
33
+ export interface ArrayValueWrapper extends DuckDBValueWrapper<
34
+ 'array',
35
+ unknown[]
36
+ > {
37
+ readonly elementType?: string;
38
+ readonly fixedLength?: number;
39
+ }
40
+
41
+ export interface StructValueWrapper extends DuckDBValueWrapper<
42
+ 'struct',
43
+ Record<string, unknown>
44
+ > {
45
+ readonly schema?: Record<string, string>;
46
+ }
47
+
48
+ export interface MapValueWrapper extends DuckDBValueWrapper<
49
+ 'map',
50
+ Record<string, unknown>
51
+ > {
52
+ readonly valueType?: string;
53
+ }
54
+
55
+ export interface TimestampValueWrapper extends DuckDBValueWrapper<
56
+ 'timestamp',
57
+ Date | string | number | bigint
58
+ > {
59
+ readonly withTimezone: boolean;
60
+ readonly precision?: number;
61
+ }
62
+
63
+ export interface BlobValueWrapper extends DuckDBValueWrapper<
64
+ 'blob',
65
+ Buffer | Uint8Array
66
+ > {}
67
+
68
+ export interface JsonValueWrapper extends DuckDBValueWrapper<'json', unknown> {}
69
+
70
+ export type AnyDuckDBValueWrapper =
71
+ | ListValueWrapper
72
+ | ArrayValueWrapper
73
+ | StructValueWrapper
74
+ | MapValueWrapper
75
+ | TimestampValueWrapper
76
+ | BlobValueWrapper
77
+ | JsonValueWrapper;
78
+
79
+ export function isDuckDBWrapper(
80
+ value: unknown
81
+ ): value is AnyDuckDBValueWrapper {
82
+ return (
83
+ value !== null &&
84
+ typeof value === 'object' &&
85
+ DUCKDB_VALUE_MARKER in value &&
86
+ (value as DuckDBValueWrapper)[DUCKDB_VALUE_MARKER] === true
87
+ );
88
+ }
89
+
90
+ export function wrapList(
91
+ data: unknown[],
92
+ elementType?: string
93
+ ): ListValueWrapper {
94
+ return {
95
+ [DUCKDB_VALUE_MARKER]: true,
96
+ kind: 'list',
97
+ data,
98
+ elementType,
99
+ };
100
+ }
101
+
102
+ export function wrapArray(
103
+ data: unknown[],
104
+ elementType?: string,
105
+ fixedLength?: number
106
+ ): ArrayValueWrapper {
107
+ return {
108
+ [DUCKDB_VALUE_MARKER]: true,
109
+ kind: 'array',
110
+ data,
111
+ elementType,
112
+ fixedLength,
113
+ };
114
+ }
115
+
116
+ export function wrapStruct(
117
+ data: Record<string, unknown>,
118
+ schema?: Record<string, string>
119
+ ): StructValueWrapper {
120
+ return {
121
+ [DUCKDB_VALUE_MARKER]: true,
122
+ kind: 'struct',
123
+ data,
124
+ schema,
125
+ };
126
+ }
127
+
128
+ export function wrapMap(
129
+ data: Record<string, unknown>,
130
+ valueType?: string
131
+ ): MapValueWrapper {
132
+ return {
133
+ [DUCKDB_VALUE_MARKER]: true,
134
+ kind: 'map',
135
+ data,
136
+ valueType,
137
+ };
138
+ }
139
+
140
+ export function wrapTimestamp(
141
+ data: Date | string | number | bigint,
142
+ withTimezone: boolean,
143
+ precision?: number
144
+ ): TimestampValueWrapper {
145
+ return {
146
+ [DUCKDB_VALUE_MARKER]: true,
147
+ kind: 'timestamp',
148
+ data,
149
+ withTimezone,
150
+ precision,
151
+ };
152
+ }
153
+
154
+ export function wrapBlob(data: Buffer | Uint8Array): BlobValueWrapper {
155
+ return {
156
+ [DUCKDB_VALUE_MARKER]: true,
157
+ kind: 'blob',
158
+ data,
159
+ };
160
+ }
161
+
162
+ export function wrapJson(data: unknown): JsonValueWrapper {
163
+ return {
164
+ [DUCKDB_VALUE_MARKER]: true,
165
+ kind: 'json',
166
+ data,
167
+ };
168
+ }
@@ -0,0 +1,165 @@
1
+ import {
2
+ listValue,
3
+ arrayValue,
4
+ structValue,
5
+ mapValue,
6
+ blobValue,
7
+ timestampValue,
8
+ timestampTZValue,
9
+ type DuckDBValue,
10
+ type DuckDBMapEntry,
11
+ } from '@duckdb/node-api';
12
+ import {
13
+ DUCKDB_VALUE_MARKER,
14
+ isDuckDBWrapper,
15
+ wrapArray,
16
+ wrapBlob,
17
+ wrapJson,
18
+ wrapList,
19
+ wrapMap,
20
+ wrapStruct,
21
+ wrapTimestamp,
22
+ type AnyDuckDBValueWrapper,
23
+ type DuckDBValueWrapper,
24
+ type ArrayValueWrapper,
25
+ type BlobValueWrapper,
26
+ type JsonValueWrapper,
27
+ type ListValueWrapper,
28
+ type MapValueWrapper,
29
+ type StructValueWrapper,
30
+ type TimestampValueWrapper,
31
+ type DuckDBValueKind,
32
+ } from './value-wrappers-core.ts';
33
+
34
+ /**
35
+ * Convert a Date/string/epoch number to microseconds since Unix epoch.
36
+ * Handles Date objects, ISO-like strings, bigint, and millisecond numbers.
37
+ */
38
+ function dateToMicros(value: Date | string | number | bigint): bigint {
39
+ if (value instanceof Date) {
40
+ return BigInt(value.getTime()) * 1000n;
41
+ }
42
+
43
+ if (typeof value === 'bigint') {
44
+ // Assume bigint already in microseconds (DuckDB default)
45
+ return value;
46
+ }
47
+
48
+ if (typeof value === 'number') {
49
+ // Assume JS milliseconds
50
+ return BigInt(Math.trunc(value)) * 1000n;
51
+ }
52
+
53
+ // For strings, normalize the format for reliable parsing
54
+ // Handle both 'YYYY-MM-DD HH:MM:SS' and 'YYYY-MM-DDTHH:MM:SS' formats
55
+ let normalized = value;
56
+ if (!value.includes('T') && value.includes(' ')) {
57
+ // Convert 'YYYY-MM-DD HH:MM:SS' to ISO format
58
+ normalized = value.replace(' ', 'T');
59
+ }
60
+ // Add 'Z' suffix if no timezone offset to treat as UTC
61
+ if (!normalized.endsWith('Z') && !/[+-]\d{2}:?\d{2}$/.test(normalized)) {
62
+ normalized += 'Z';
63
+ }
64
+
65
+ const date = new Date(normalized);
66
+ if (isNaN(date.getTime())) {
67
+ throw new Error(`Invalid timestamp string: ${value}`);
68
+ }
69
+ return BigInt(date.getTime()) * 1000n;
70
+ }
71
+
72
+ /**
73
+ * Convert Buffer or Uint8Array to Uint8Array.
74
+ */
75
+ function toUint8Array(data: Buffer | Uint8Array): Uint8Array {
76
+ return data instanceof Uint8Array && !(data instanceof Buffer)
77
+ ? data
78
+ : new Uint8Array(data);
79
+ }
80
+
81
+ /**
82
+ * Convert struct entries to DuckDB struct value entries.
83
+ */
84
+ function convertStructEntries(
85
+ data: Record<string, unknown>,
86
+ toValue: (v: unknown) => DuckDBValue
87
+ ): Record<string, DuckDBValue> {
88
+ const entries: Record<string, DuckDBValue> = {};
89
+ for (const [key, val] of Object.entries(data)) {
90
+ entries[key] = toValue(val);
91
+ }
92
+ return entries;
93
+ }
94
+
95
+ /**
96
+ * Convert map entries to DuckDB map entry format.
97
+ */
98
+ function convertMapEntries(
99
+ data: Record<string, unknown>,
100
+ toValue: (v: unknown) => DuckDBValue
101
+ ): DuckDBMapEntry[] {
102
+ return Object.entries(data).map(([key, val]) => ({
103
+ key: key as DuckDBValue,
104
+ value: toValue(val),
105
+ }));
106
+ }
107
+
108
+ /**
109
+ * Convert a wrapper to a DuckDB Node API value.
110
+ * Uses exhaustive switch for compile-time safety.
111
+ */
112
+ export function wrapperToNodeApiValue(
113
+ wrapper: AnyDuckDBValueWrapper,
114
+ toValue: (v: unknown) => DuckDBValue
115
+ ): DuckDBValue {
116
+ switch (wrapper.kind) {
117
+ case 'list':
118
+ return listValue(wrapper.data.map(toValue));
119
+ case 'array':
120
+ return arrayValue(wrapper.data.map(toValue));
121
+ case 'struct':
122
+ return structValue(convertStructEntries(wrapper.data, toValue));
123
+ case 'map':
124
+ return mapValue(convertMapEntries(wrapper.data, toValue));
125
+ case 'timestamp':
126
+ return wrapper.withTimezone
127
+ ? timestampTZValue(dateToMicros(wrapper.data))
128
+ : timestampValue(dateToMicros(wrapper.data));
129
+ case 'blob':
130
+ return blobValue(toUint8Array(wrapper.data));
131
+ case 'json':
132
+ // JSON is stored as VARCHAR in DuckDB - stringify at binding time
133
+ return JSON.stringify(wrapper.data);
134
+ default: {
135
+ // Exhaustive check - TypeScript will error if a case is missing
136
+ const _exhaustive: never = wrapper;
137
+ throw new Error(
138
+ `Unknown wrapper kind: ${(_exhaustive as AnyDuckDBValueWrapper).kind}`
139
+ );
140
+ }
141
+ }
142
+ }
143
+
144
+ // Re-export core helpers for convenience and backward compatibility.
145
+ export {
146
+ DUCKDB_VALUE_MARKER,
147
+ isDuckDBWrapper,
148
+ wrapArray,
149
+ wrapBlob,
150
+ wrapJson,
151
+ wrapList,
152
+ wrapMap,
153
+ wrapStruct,
154
+ wrapTimestamp,
155
+ type AnyDuckDBValueWrapper,
156
+ type DuckDBValueWrapper,
157
+ type ArrayValueWrapper,
158
+ type BlobValueWrapper,
159
+ type JsonValueWrapper,
160
+ type ListValueWrapper,
161
+ type MapValueWrapper,
162
+ type StructValueWrapper,
163
+ type TimestampValueWrapper,
164
+ type DuckDBValueKind,
165
+ } from './value-wrappers-core.ts';