@leonardovida-md/drizzle-neo-duckdb 1.0.3 → 1.1.0

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.
@@ -1,13 +1,3 @@
1
- const selectionRegex = /select\s+(.+)\s+from/i;
2
- const tableIdPropSelectionRegex = new RegExp(
3
- [
4
- `("(.+)"\\."(.+)")`, // table identifier + property
5
- `(\\s+as\\s+'?(.+?)'?\\.'?(.+?)'?)?`, // optional AS clause
6
- ].join(''),
7
- 'i'
8
- );
9
- const noTableIdPropSelectionRegex = /"(.+)"(\s+as\s+'?\1'?)?/i;
10
-
11
1
  export function adaptArrayOperators(query: string): string {
12
2
  type ArrayOperator = {
13
3
  token: '@>' | '<@' | '&&';
@@ -34,6 +24,7 @@ export function adaptArrayOperators(query: string): string {
34
24
  let inString = false;
35
25
  for (; idx >= 0; idx--) {
36
26
  const ch = source[idx];
27
+ if (ch === undefined) break;
37
28
  if (ch === "'" && source[idx - 1] !== '\\') {
38
29
  inString = !inString;
39
30
  }
@@ -62,6 +53,7 @@ export function adaptArrayOperators(query: string): string {
62
53
  let inString = false;
63
54
  for (; idx < source.length; idx++) {
64
55
  const ch = source[idx];
56
+ if (ch === undefined) break;
65
57
  if (ch === "'" && source[idx - 1] !== '\\') {
66
58
  inString = !inString;
67
59
  }
@@ -103,42 +95,3 @@ export function adaptArrayOperators(query: string): string {
103
95
 
104
96
  return rewritten;
105
97
  }
106
-
107
- export function queryAdapter(query: string): string {
108
- const selection = selectionRegex.exec(query);
109
-
110
- if (selection?.length !== 2) {
111
- return query;
112
- }
113
-
114
- const fields = selection[1]
115
- .split(',')
116
- .map((field) => {
117
- const trimmedField = field.trim();
118
- const tableProp = tableIdPropSelectionRegex.exec(trimmedField);
119
- if (tableProp) {
120
- const [, identifier, table, column, , aliasTable, aliasColumn] =
121
- tableProp;
122
-
123
- const asAlias = `'${aliasTable ?? table}.${aliasColumn ?? column}'`;
124
- if (tableProp[4]) {
125
- return trimmedField.replace(tableProp[4], ` as ${asAlias}`);
126
- }
127
- return `${identifier} as ${asAlias}`;
128
- }
129
-
130
- const noTableProp = noTableIdPropSelectionRegex.exec(trimmedField);
131
- if (noTableProp) {
132
- const [, column, alias] = noTableProp;
133
- const asAlias = ` as '${column}'`;
134
- return alias
135
- ? trimmedField.replace(alias, asAlias)
136
- : `${trimmedField}${asAlias}`;
137
- }
138
-
139
- return trimmedField;
140
- })
141
- .filter(Boolean) as string[];
142
-
143
- return query.replace(selection[1], fields.join(', '));
144
- }
package/src/utils.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { aliasFields } from './sql/selection.ts';
2
- export { adaptArrayOperators, queryAdapter } from './sql/query-rewriters.ts';
2
+ export { adaptArrayOperators } from './sql/query-rewriters.ts';
3
3
  export { mapResultRow } from './sql/result-mapper.ts';
@@ -0,0 +1,156 @@
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
27
+ extends DuckDBValueWrapper<'list', unknown[]> {
28
+ readonly elementType?: string;
29
+ }
30
+
31
+ export interface ArrayValueWrapper
32
+ extends DuckDBValueWrapper<'array', unknown[]> {
33
+ readonly elementType?: string;
34
+ readonly fixedLength?: number;
35
+ }
36
+
37
+ export interface StructValueWrapper
38
+ extends DuckDBValueWrapper<'struct', Record<string, unknown>> {
39
+ readonly schema?: Record<string, string>;
40
+ }
41
+
42
+ export interface MapValueWrapper
43
+ extends DuckDBValueWrapper<'map', Record<string, unknown>> {
44
+ readonly valueType?: string;
45
+ }
46
+
47
+ export interface TimestampValueWrapper
48
+ extends DuckDBValueWrapper<'timestamp', Date | string> {
49
+ readonly withTimezone: boolean;
50
+ readonly precision?: number;
51
+ }
52
+
53
+ export interface BlobValueWrapper
54
+ extends DuckDBValueWrapper<'blob', Buffer | Uint8Array> {}
55
+
56
+ export interface JsonValueWrapper extends DuckDBValueWrapper<'json', unknown> {}
57
+
58
+ export type AnyDuckDBValueWrapper =
59
+ | ListValueWrapper
60
+ | ArrayValueWrapper
61
+ | StructValueWrapper
62
+ | MapValueWrapper
63
+ | TimestampValueWrapper
64
+ | BlobValueWrapper
65
+ | JsonValueWrapper;
66
+
67
+ export function isDuckDBWrapper(
68
+ value: unknown
69
+ ): value is AnyDuckDBValueWrapper {
70
+ return (
71
+ value !== null &&
72
+ typeof value === 'object' &&
73
+ DUCKDB_VALUE_MARKER in value &&
74
+ (value as DuckDBValueWrapper)[DUCKDB_VALUE_MARKER] === true
75
+ );
76
+ }
77
+
78
+ export function wrapList(
79
+ data: unknown[],
80
+ elementType?: string
81
+ ): ListValueWrapper {
82
+ return {
83
+ [DUCKDB_VALUE_MARKER]: true,
84
+ kind: 'list',
85
+ data,
86
+ elementType,
87
+ };
88
+ }
89
+
90
+ export function wrapArray(
91
+ data: unknown[],
92
+ elementType?: string,
93
+ fixedLength?: number
94
+ ): ArrayValueWrapper {
95
+ return {
96
+ [DUCKDB_VALUE_MARKER]: true,
97
+ kind: 'array',
98
+ data,
99
+ elementType,
100
+ fixedLength,
101
+ };
102
+ }
103
+
104
+ export function wrapStruct(
105
+ data: Record<string, unknown>,
106
+ schema?: Record<string, string>
107
+ ): StructValueWrapper {
108
+ return {
109
+ [DUCKDB_VALUE_MARKER]: true,
110
+ kind: 'struct',
111
+ data,
112
+ schema,
113
+ };
114
+ }
115
+
116
+ export function wrapMap(
117
+ data: Record<string, unknown>,
118
+ valueType?: string
119
+ ): MapValueWrapper {
120
+ return {
121
+ [DUCKDB_VALUE_MARKER]: true,
122
+ kind: 'map',
123
+ data,
124
+ valueType,
125
+ };
126
+ }
127
+
128
+ export function wrapTimestamp(
129
+ data: Date | string,
130
+ withTimezone: boolean,
131
+ precision?: number
132
+ ): TimestampValueWrapper {
133
+ return {
134
+ [DUCKDB_VALUE_MARKER]: true,
135
+ kind: 'timestamp',
136
+ data,
137
+ withTimezone,
138
+ precision,
139
+ };
140
+ }
141
+
142
+ export function wrapBlob(data: Buffer | Uint8Array): BlobValueWrapper {
143
+ return {
144
+ [DUCKDB_VALUE_MARKER]: true,
145
+ kind: 'blob',
146
+ data,
147
+ };
148
+ }
149
+
150
+ export function wrapJson(data: unknown): JsonValueWrapper {
151
+ return {
152
+ [DUCKDB_VALUE_MARKER]: true,
153
+ kind: 'json',
154
+ data,
155
+ };
156
+ }
@@ -9,219 +9,27 @@ import {
9
9
  type DuckDBValue,
10
10
  type DuckDBMapEntry,
11
11
  } from '@duckdb/node-api';
12
-
13
- /**
14
- * Symbol used to identify wrapped DuckDB values for native binding.
15
- * Uses Symbol.for() to ensure cross-module compatibility.
16
- */
17
- export const DUCKDB_VALUE_MARKER = Symbol.for('drizzle-duckdb:value');
18
-
19
- /**
20
- * Type identifier for each wrapper kind.
21
- */
22
- export type DuckDBValueKind =
23
- | 'list'
24
- | 'array'
25
- | 'struct'
26
- | 'map'
27
- | 'timestamp'
28
- | 'blob'
29
- | 'json';
30
-
31
- /**
32
- * Base interface for all tagged DuckDB value wrappers.
33
- */
34
- export interface DuckDBValueWrapper<
35
- TKind extends DuckDBValueKind = DuckDBValueKind,
36
- TData = unknown,
37
- > {
38
- readonly [DUCKDB_VALUE_MARKER]: true;
39
- readonly kind: TKind;
40
- readonly data: TData;
41
- }
42
-
43
- /**
44
- * List wrapper - maps to DuckDBListValue
45
- */
46
- export interface ListValueWrapper
47
- extends DuckDBValueWrapper<'list', unknown[]> {
48
- readonly elementType?: string;
49
- }
50
-
51
- /**
52
- * Array wrapper (fixed size) - maps to DuckDBArrayValue
53
- */
54
- export interface ArrayValueWrapper
55
- extends DuckDBValueWrapper<'array', unknown[]> {
56
- readonly elementType?: string;
57
- readonly fixedLength?: number;
58
- }
59
-
60
- /**
61
- * Struct wrapper - maps to DuckDBStructValue
62
- */
63
- export interface StructValueWrapper
64
- extends DuckDBValueWrapper<'struct', Record<string, unknown>> {
65
- readonly schema?: Record<string, string>;
66
- }
67
-
68
- /**
69
- * Map wrapper - maps to DuckDBMapValue
70
- */
71
- export interface MapValueWrapper
72
- extends DuckDBValueWrapper<'map', Record<string, unknown>> {
73
- readonly valueType?: string;
74
- }
75
-
76
- /**
77
- * Timestamp wrapper - maps to DuckDBTimestampValue or DuckDBTimestampTZValue
78
- */
79
- export interface TimestampValueWrapper
80
- extends DuckDBValueWrapper<'timestamp', Date | string> {
81
- readonly withTimezone: boolean;
82
- readonly precision?: number;
83
- }
84
-
85
- /**
86
- * Blob wrapper - maps to DuckDBBlobValue
87
- */
88
- export interface BlobValueWrapper
89
- extends DuckDBValueWrapper<'blob', Buffer | Uint8Array> {}
90
-
91
- /**
92
- * JSON wrapper - delays JSON.stringify() to binding time.
93
- * DuckDB stores JSON as VARCHAR internally.
94
- */
95
- export interface JsonValueWrapper extends DuckDBValueWrapper<'json', unknown> {}
96
-
97
- /**
98
- * Union of all wrapper types for exhaustive type checking.
99
- */
100
- export type AnyDuckDBValueWrapper =
101
- | ListValueWrapper
102
- | ArrayValueWrapper
103
- | StructValueWrapper
104
- | MapValueWrapper
105
- | TimestampValueWrapper
106
- | BlobValueWrapper
107
- | JsonValueWrapper;
108
-
109
- /**
110
- * Type guard to check if a value is a tagged DuckDB wrapper.
111
- * Optimized for fast detection in the hot path.
112
- */
113
- export function isDuckDBWrapper(
114
- value: unknown
115
- ): value is AnyDuckDBValueWrapper {
116
- return (
117
- value !== null &&
118
- typeof value === 'object' &&
119
- DUCKDB_VALUE_MARKER in value &&
120
- (value as DuckDBValueWrapper)[DUCKDB_VALUE_MARKER] === true
121
- );
122
- }
123
-
124
- /**
125
- * Create a list wrapper for variable-length lists.
126
- */
127
- export function wrapList(
128
- data: unknown[],
129
- elementType?: string
130
- ): ListValueWrapper {
131
- return {
132
- [DUCKDB_VALUE_MARKER]: true,
133
- kind: 'list',
134
- data,
135
- elementType,
136
- };
137
- }
138
-
139
- /**
140
- * Create an array wrapper for fixed-length arrays.
141
- */
142
- export function wrapArray(
143
- data: unknown[],
144
- elementType?: string,
145
- fixedLength?: number
146
- ): ArrayValueWrapper {
147
- return {
148
- [DUCKDB_VALUE_MARKER]: true,
149
- kind: 'array',
150
- data,
151
- elementType,
152
- fixedLength,
153
- };
154
- }
155
-
156
- /**
157
- * Create a struct wrapper for named field structures.
158
- */
159
- export function wrapStruct(
160
- data: Record<string, unknown>,
161
- schema?: Record<string, string>
162
- ): StructValueWrapper {
163
- return {
164
- [DUCKDB_VALUE_MARKER]: true,
165
- kind: 'struct',
166
- data,
167
- schema,
168
- };
169
- }
170
-
171
- /**
172
- * Create a map wrapper for key-value maps.
173
- */
174
- export function wrapMap(
175
- data: Record<string, unknown>,
176
- valueType?: string
177
- ): MapValueWrapper {
178
- return {
179
- [DUCKDB_VALUE_MARKER]: true,
180
- kind: 'map',
181
- data,
182
- valueType,
183
- };
184
- }
185
-
186
- /**
187
- * Create a timestamp wrapper.
188
- */
189
- export function wrapTimestamp(
190
- data: Date | string,
191
- withTimezone: boolean,
192
- precision?: number
193
- ): TimestampValueWrapper {
194
- return {
195
- [DUCKDB_VALUE_MARKER]: true,
196
- kind: 'timestamp',
197
- data,
198
- withTimezone,
199
- precision,
200
- };
201
- }
202
-
203
- /**
204
- * Create a blob wrapper for binary data.
205
- */
206
- export function wrapBlob(data: Buffer | Uint8Array): BlobValueWrapper {
207
- return {
208
- [DUCKDB_VALUE_MARKER]: true,
209
- kind: 'blob',
210
- data,
211
- };
212
- }
213
-
214
- /**
215
- * Create a JSON wrapper that delays JSON.stringify() to binding time.
216
- * This ensures consistent handling with other wrapped types.
217
- */
218
- export function wrapJson(data: unknown): JsonValueWrapper {
219
- return {
220
- [DUCKDB_VALUE_MARKER]: true,
221
- kind: 'json',
222
- data,
223
- };
224
- }
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';
225
33
 
226
34
  /**
227
35
  * Convert a Date or string to microseconds since Unix epoch.
@@ -322,3 +130,26 @@ export function wrapperToNodeApiValue(
322
130
  }
323
131
  }
324
132
  }
133
+
134
+ // Re-export core helpers for convenience and backward compatibility.
135
+ export {
136
+ DUCKDB_VALUE_MARKER,
137
+ isDuckDBWrapper,
138
+ wrapArray,
139
+ wrapBlob,
140
+ wrapJson,
141
+ wrapList,
142
+ wrapMap,
143
+ wrapStruct,
144
+ wrapTimestamp,
145
+ type AnyDuckDBValueWrapper,
146
+ type DuckDBValueWrapper,
147
+ type ArrayValueWrapper,
148
+ type BlobValueWrapper,
149
+ type JsonValueWrapper,
150
+ type ListValueWrapper,
151
+ type MapValueWrapper,
152
+ type StructValueWrapper,
153
+ type TimestampValueWrapper,
154
+ type DuckDBValueKind,
155
+ } from './value-wrappers-core.ts';