@leonardovida-md/drizzle-neo-duckdb 1.0.2 → 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.
@@ -0,0 +1,319 @@
1
+ // src/columns.ts
2
+ import { sql } from "drizzle-orm";
3
+ import { customType } from "drizzle-orm/pg-core";
4
+
5
+ // src/value-wrappers-core.ts
6
+ var DUCKDB_VALUE_MARKER = Symbol.for("drizzle-duckdb:value");
7
+ function wrapList(data, elementType) {
8
+ return {
9
+ [DUCKDB_VALUE_MARKER]: true,
10
+ kind: "list",
11
+ data,
12
+ elementType
13
+ };
14
+ }
15
+ function wrapArray(data, elementType, fixedLength) {
16
+ return {
17
+ [DUCKDB_VALUE_MARKER]: true,
18
+ kind: "array",
19
+ data,
20
+ elementType,
21
+ fixedLength
22
+ };
23
+ }
24
+ function wrapMap(data, valueType) {
25
+ return {
26
+ [DUCKDB_VALUE_MARKER]: true,
27
+ kind: "map",
28
+ data,
29
+ valueType
30
+ };
31
+ }
32
+ function wrapBlob(data) {
33
+ return {
34
+ [DUCKDB_VALUE_MARKER]: true,
35
+ kind: "blob",
36
+ data
37
+ };
38
+ }
39
+ function wrapJson(data) {
40
+ return {
41
+ [DUCKDB_VALUE_MARKER]: true,
42
+ kind: "json",
43
+ data
44
+ };
45
+ }
46
+
47
+ // src/columns.ts
48
+ function coerceArrayString(value) {
49
+ const trimmed = value.trim();
50
+ if (!trimmed) {
51
+ return [];
52
+ }
53
+ if (trimmed.startsWith("[")) {
54
+ try {
55
+ return JSON.parse(trimmed);
56
+ } catch {
57
+ return;
58
+ }
59
+ }
60
+ if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
61
+ try {
62
+ const json = trimmed.replace(/{/g, "[").replace(/}/g, "]");
63
+ return JSON.parse(json);
64
+ } catch {
65
+ return;
66
+ }
67
+ }
68
+ return;
69
+ }
70
+ function formatLiteral(value, typeHint) {
71
+ if (value === null || value === undefined) {
72
+ return "NULL";
73
+ }
74
+ const upperType = typeHint?.toUpperCase() ?? "";
75
+ if (value instanceof Date) {
76
+ return `'${value.toISOString()}'`;
77
+ }
78
+ if (typeof value === "number" || typeof value === "bigint") {
79
+ return value.toString();
80
+ }
81
+ if (typeof value === "boolean") {
82
+ return value ? "TRUE" : "FALSE";
83
+ }
84
+ const str = typeof value === "string" ? value : JSON.stringify(value) ?? String(value);
85
+ const escaped = str.replace(/'/g, "''");
86
+ if (upperType.includes("CHAR") || upperType.includes("TEXT") || upperType.includes("STRING") || upperType.includes("VARCHAR")) {
87
+ return `'${escaped}'`;
88
+ }
89
+ return `'${escaped}'`;
90
+ }
91
+ function buildListLiteral(values, elementType) {
92
+ if (values.length === 0) {
93
+ return sql`[]`;
94
+ }
95
+ const chunks = values.map((v) => typeof v === "object" && !Array.isArray(v) ? sql`${v}` : sql.raw(formatLiteral(v, elementType)));
96
+ return sql`list_value(${sql.join(chunks, sql.raw(", "))})`;
97
+ }
98
+ function buildStructLiteral(value, schema) {
99
+ const parts = Object.entries(value).map(([key, val]) => {
100
+ const typeHint = schema?.[key];
101
+ if (Array.isArray(val)) {
102
+ const inner = typeof typeHint === "string" && typeHint.endsWith("[]") ? typeHint.slice(0, -2) : undefined;
103
+ return sql`${sql.identifier(key)} := ${buildListLiteral(val, inner)}`;
104
+ }
105
+ return sql`${sql.identifier(key)} := ${val}`;
106
+ });
107
+ return sql`struct_pack(${sql.join(parts, sql.raw(", "))})`;
108
+ }
109
+ var duckDbList = (name, elementType) => customType({
110
+ dataType() {
111
+ return `${elementType}[]`;
112
+ },
113
+ toDriver(value) {
114
+ return wrapList(value, elementType);
115
+ },
116
+ fromDriver(value) {
117
+ if (Array.isArray(value)) {
118
+ return value;
119
+ }
120
+ if (typeof value === "string") {
121
+ const parsed = coerceArrayString(value);
122
+ if (parsed) {
123
+ return parsed;
124
+ }
125
+ }
126
+ return [];
127
+ }
128
+ })(name);
129
+ var duckDbArray = (name, elementType, fixedLength) => customType({
130
+ dataType() {
131
+ return fixedLength ? `${elementType}[${fixedLength}]` : `${elementType}[]`;
132
+ },
133
+ toDriver(value) {
134
+ return wrapArray(value, elementType, fixedLength);
135
+ },
136
+ fromDriver(value) {
137
+ if (Array.isArray(value)) {
138
+ return value;
139
+ }
140
+ if (typeof value === "string") {
141
+ const parsed = coerceArrayString(value);
142
+ if (parsed) {
143
+ return parsed;
144
+ }
145
+ }
146
+ return [];
147
+ }
148
+ })(name);
149
+ var duckDbMap = (name, valueType) => customType({
150
+ dataType() {
151
+ return `MAP (STRING, ${valueType})`;
152
+ },
153
+ toDriver(value) {
154
+ return wrapMap(value, valueType);
155
+ },
156
+ fromDriver(value) {
157
+ return value;
158
+ }
159
+ })(name);
160
+ var duckDbStruct = (name, schema) => customType({
161
+ dataType() {
162
+ const fields = Object.entries(schema).map(([key, type]) => `${key} ${type}`);
163
+ return `STRUCT (${fields.join(", ")})`;
164
+ },
165
+ toDriver(value) {
166
+ return buildStructLiteral(value, schema);
167
+ },
168
+ fromDriver(value) {
169
+ if (typeof value === "string") {
170
+ try {
171
+ return JSON.parse(value);
172
+ } catch {
173
+ return value;
174
+ }
175
+ }
176
+ return value;
177
+ }
178
+ })(name);
179
+ var duckDbJson = (name) => customType({
180
+ dataType() {
181
+ return "JSON";
182
+ },
183
+ toDriver(value) {
184
+ if (typeof value === "string") {
185
+ return value;
186
+ }
187
+ if (value !== null && typeof value === "object" && "queryChunks" in value) {
188
+ return value;
189
+ }
190
+ return wrapJson(value);
191
+ },
192
+ fromDriver(value) {
193
+ if (typeof value !== "string") {
194
+ return value;
195
+ }
196
+ const trimmed = value.trim();
197
+ if (!trimmed) {
198
+ return value;
199
+ }
200
+ try {
201
+ return JSON.parse(trimmed);
202
+ } catch {
203
+ return value;
204
+ }
205
+ }
206
+ })(name);
207
+ var duckDbBlob = customType({
208
+ dataType() {
209
+ return "BLOB";
210
+ },
211
+ toDriver(value) {
212
+ return wrapBlob(value);
213
+ }
214
+ });
215
+ var duckDbInet = (name) => customType({
216
+ dataType() {
217
+ return "INET";
218
+ },
219
+ toDriver(value) {
220
+ return value;
221
+ }
222
+ })(name);
223
+ var duckDbInterval = (name) => customType({
224
+ dataType() {
225
+ return "INTERVAL";
226
+ },
227
+ toDriver(value) {
228
+ return value;
229
+ }
230
+ })(name);
231
+ var duckDbTimestamp = (name, options = {}) => customType({
232
+ dataType() {
233
+ if (options.withTimezone) {
234
+ return "TIMESTAMPTZ";
235
+ }
236
+ const precision = options.precision ? `(${options.precision})` : "";
237
+ return `TIMESTAMP${precision}`;
238
+ },
239
+ toDriver(value) {
240
+ const iso = value instanceof Date ? value.toISOString() : value;
241
+ const normalized = iso.replace("T", " ").replace("Z", "+00");
242
+ const typeKeyword = options.withTimezone ? "TIMESTAMPTZ" : "TIMESTAMP";
243
+ return sql.raw(`${typeKeyword} '${normalized}'`);
244
+ },
245
+ fromDriver(value) {
246
+ if (options.mode === "string") {
247
+ if (value instanceof Date) {
248
+ return value.toISOString().replace("T", " ").replace("Z", "+00");
249
+ }
250
+ return typeof value === "string" ? value : value.toString();
251
+ }
252
+ if (value instanceof Date) {
253
+ return value;
254
+ }
255
+ const stringValue = typeof value === "string" ? value : value.toString();
256
+ const hasOffset = stringValue.endsWith("Z") || /[+-]\d{2}:?\d{2}$/.test(stringValue);
257
+ const normalized = hasOffset ? stringValue.replace(" ", "T") : `${stringValue.replace(" ", "T")}Z`;
258
+ return new Date(normalized);
259
+ }
260
+ })(name);
261
+ var duckDbDate = (name) => customType({
262
+ dataType() {
263
+ return "DATE";
264
+ },
265
+ toDriver(value) {
266
+ return value;
267
+ },
268
+ fromDriver(value) {
269
+ const str = value instanceof Date ? value.toISOString().slice(0, 10) : value;
270
+ return str;
271
+ }
272
+ })(name);
273
+ var duckDbTime = (name) => customType({
274
+ dataType() {
275
+ return "TIME";
276
+ },
277
+ toDriver(value) {
278
+ return value;
279
+ },
280
+ fromDriver(value) {
281
+ if (typeof value === "bigint") {
282
+ const totalMillis = Number(value) / 1000;
283
+ const date = new Date(totalMillis);
284
+ return date.toISOString().split("T")[1].replace("Z", "");
285
+ }
286
+ return value;
287
+ }
288
+ })(name);
289
+ function toListValue(values) {
290
+ return buildListLiteral(values);
291
+ }
292
+ function duckDbArrayContains(column, values) {
293
+ const rhs = Array.isArray(values) ? toListValue(values) : values;
294
+ return sql`array_has_all(${column}, ${rhs})`;
295
+ }
296
+ function duckDbArrayContained(column, values) {
297
+ const rhs = Array.isArray(values) ? toListValue(values) : values;
298
+ return sql`array_has_all(${rhs}, ${column})`;
299
+ }
300
+ function duckDbArrayOverlaps(column, values) {
301
+ const rhs = Array.isArray(values) ? toListValue(values) : values;
302
+ return sql`array_has_any(${column}, ${rhs})`;
303
+ }
304
+ export {
305
+ duckDbTimestamp,
306
+ duckDbTime,
307
+ duckDbStruct,
308
+ duckDbMap,
309
+ duckDbList,
310
+ duckDbJson,
311
+ duckDbInterval,
312
+ duckDbInet,
313
+ duckDbDate,
314
+ duckDbBlob,
315
+ duckDbArrayOverlaps,
316
+ duckDbArrayContains,
317
+ duckDbArrayContained,
318
+ duckDbArray
319
+ };
package/dist/index.d.ts CHANGED
@@ -3,3 +3,7 @@ export * from './session.ts';
3
3
  export * from './columns.ts';
4
4
  export * from './migrator.ts';
5
5
  export * from './introspect.ts';
6
+ export * from './client.ts';
7
+ export * from './pool.ts';
8
+ export * from './olap.ts';
9
+ export * from './value-wrappers.ts';