@flowblade/sqlduck 0.9.0 → 0.11.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.
package/README.md CHANGED
@@ -4,6 +4,74 @@
4
4
 
5
5
  ## Quick start
6
6
 
7
+ ### Create a database connection
8
+
9
+ ```typescript
10
+ import { DuckDBInstance } from '@duckdb/node-api';
11
+ DuckDBInstance.create(undefined, {
12
+ access_mode: 'READ_WRITE',
13
+ max_memory: '512M',
14
+ });
15
+ export const conn = await instance.connect();
16
+ ```
17
+
18
+ ### Append data to a database
19
+
20
+ ```typescript
21
+ import { SqlDuck, DuckDatabaseManager } from "@flowblade/sqlduck";
22
+ import * as z from "zod";
23
+ import { conn } from "./db.config.ts";
24
+
25
+ const dbManager = new DuckDatabaseManager(conn);
26
+ const database = await dbManager.attach({
27
+ type: ':memory:', // can be 'duckdb', ...
28
+ alias: 'mydb',
29
+ options: { COMPRESS: 'false' },
30
+ });
31
+
32
+ const sqlDuck = new SqlDuck({ conn });
33
+
34
+ // Define a zod schema, it will be used to create the table
35
+ const userSchema = z.object({
36
+ id: z.int32().min(1).meta({ primaryKey: true }),
37
+ name: z.string(),
38
+ });
39
+
40
+ // Example of a datasource (can be generator, async generator, async iterable)
41
+ async function* getUsers(): AsyncIterableIterator<
42
+ z.infer<typeof userSchema>
43
+ > {
44
+ // database or api call
45
+ yield { id: 1, name: 'John' };
46
+ yield { id: 2, name: 'Jane' };
47
+ }
48
+
49
+ // Create a table from the schema and the datasource
50
+ const result = await sqlDuck.toTable({
51
+ table: new Table({ name: 'user', database: database.alias }),
52
+ schema: userSchema, // The schema to use to create the table
53
+ rowStream: getUsers(), // The async iterable that yields rows
54
+ // 👇Optional:
55
+ chunkSize: 2048, // Number of rows to append when using duckdb appender. Default is 2048
56
+ onDataAppended: ({ timeMs, totalRows, rowsPerSecond }) => {
57
+ console.log(
58
+ `Appended ${totalRows} in time ${timeMs}ms, est: ${rowsPerSecond} rows/s`
59
+ );
60
+ },
61
+ // Optional table creation options
62
+ createOptions: {
63
+ create: 'CREATE_OR_REPLACE',
64
+ },
65
+ });
66
+
67
+ console.log(`Inserted ${result.totalRows} rows in ${result.timeMs}ms`);
68
+ console.log(`Table created with DDL: ${result.createTableDDL}`);
69
+
70
+ const reader = await conn.runAndReadAll('select * from mydb.user');
71
+ const rows = reader.getRowObjectsJS();
72
+ // [{id: 1, name: 'John'}, {id: 2, name: 'Jane'}]]
73
+ ```
74
+
7
75
  ### Create a memory table
8
76
 
9
77
  ```typescript
@@ -35,7 +103,6 @@ const result = sqlDuck.toTable({
35
103
  onDataAppended: ({ total }) => {
36
104
  console.log(`Appended ${total} rows so far`);
37
105
  },
38
- onDataAppendedBatchSize: 4096, // Call onDataAppended every 4096 rows
39
106
  // Optional table creation options
40
107
  createOptions: {
41
108
  create: "CREATE_OR_REPLACE",
package/dist/index.cjs CHANGED
@@ -22,8 +22,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
22
22
  }) : target, mod));
23
23
  //#endregion
24
24
  let _duckdb_node_api = require("@duckdb/node-api");
25
+ let _logtape_logtape = require("@logtape/logtape");
25
26
  let zod = require("zod");
26
27
  zod = __toESM(zod);
28
+ let _httpx_assert = require("@httpx/assert");
29
+ let _httpx_plain_object = require("@httpx/plain-object");
27
30
  //#region src/helpers/duck-exec.ts
28
31
  var DuckExec = class {
29
32
  #conn;
@@ -141,6 +144,12 @@ const createOnDataAppendedCollector = () => {
141
144
  };
142
145
  };
143
146
  //#endregion
147
+ //#region src/config/flowblade-logtape-sqlduck.config.ts
148
+ const flowbladeLogtapeSqlduckConfig = { categories: ["flowblade", "sqlduck"] };
149
+ //#endregion
150
+ //#region src/logger/sqlduck-default-logtape-logger.ts
151
+ const sqlduckDefaultLogtapeLogger = (0, _logtape_logtape.getLogger)(flowbladeLogtapeSqlduckConfig.categories);
152
+ //#endregion
144
153
  //#region src/table/get-duckdb-number-column-type.ts
145
154
  const isFloatValue = (value) => {
146
155
  if (!Number.isFinite(value)) return true;
@@ -174,6 +183,16 @@ const createOptions = {
174
183
  CREATE_OR_REPLACE: "CREATE OR REPLACE TABLE",
175
184
  IF_NOT_EXISTS: "CREATE TABLE IF NOT EXISTS"
176
185
  };
186
+ const duckDbTypesMap = new Map([
187
+ ["VARCHAR", _duckdb_node_api.VARCHAR],
188
+ ["BIGINT", _duckdb_node_api.BIGINT],
189
+ ["TIMESTAMP", _duckdb_node_api.TIMESTAMP],
190
+ ["UUID", _duckdb_node_api.UUID],
191
+ ["BOOLEAN", _duckdb_node_api.BOOLEAN],
192
+ ["INTEGER", _duckdb_node_api.INTEGER],
193
+ ["DOUBLE", _duckdb_node_api.DOUBLE],
194
+ ["FLOAT", _duckdb_node_api.FLOAT]
195
+ ]);
177
196
  const getTableCreateFromZod = (params) => {
178
197
  const { table, schema, options } = params;
179
198
  const { create = "CREATE" } = options ?? {};
@@ -186,9 +205,10 @@ const getTableCreateFromZod = (params) => {
186
205
  if (json.properties === void 0) throw new TypeError("Schema must have at least one property");
187
206
  const columnTypesMap = /* @__PURE__ */ new Map();
188
207
  for (const [columnName, def] of Object.entries(json.properties)) {
189
- const { type, nullable, format, primaryKey, minimum, maximum } = def;
208
+ const { type, duckdbType, nullable, format, primaryKey, minimum, maximum } = def;
190
209
  const c = { name: columnName };
191
- switch (type) {
210
+ if (duckdbType !== void 0 && duckDbTypesMap.has(duckdbType)) c.duckdbType = duckDbTypesMap.get(duckdbType);
211
+ else switch (type) {
192
212
  case "string":
193
213
  switch (format) {
194
214
  case "date-time":
@@ -244,15 +264,18 @@ const getTableCreateFromZod = (params) => {
244
264
  //#endregion
245
265
  //#region src/table/create-table-from-zod.ts
246
266
  const createTableFromZod = async (params) => {
247
- const { conn, table, schema, options } = params;
267
+ const { conn, table, schema, options, logger = sqlduckDefaultLogtapeLogger } = params;
248
268
  const { ddl, columnTypes } = getTableCreateFromZod({
249
269
  table,
250
270
  schema,
251
271
  options
252
272
  });
273
+ logger.debug(`Generate DDL for table '${table.getFullName()}'`, { ddl });
253
274
  try {
254
275
  await conn.run(ddl);
276
+ logger.info(`Table '${table.getFullName()}' successfully created`, { ddl });
255
277
  } catch (e) {
278
+ logger.error(`Failed to create table '${table.getFullName()}': ${e.message}`, { ddl });
256
279
  throw new Error(`Failed to create table '${table.getFullName()}': ${e.message}`, { cause: e });
257
280
  }
258
281
  return {
@@ -305,11 +328,11 @@ async function* rowsToColumnsChunks(params) {
305
328
  //#endregion
306
329
  //#region src/sql-duck.ts
307
330
  var SqlDuck = class {
308
- #duck;
331
+ #conn;
309
332
  #logger;
310
333
  constructor(params) {
311
- this.#duck = params.conn;
312
- this.#logger = params.logger;
334
+ this.#conn = params.conn;
335
+ this.#logger = params.logger ?? sqlduckDefaultLogtapeLogger;
313
336
  }
314
337
  /**
315
338
  * Create a table from a Zod schema and fill it with data from a row stream.
@@ -353,12 +376,12 @@ var SqlDuck = class {
353
376
  if (!Number.isSafeInteger(chunkSize) || chunkSize < 1 || chunkSize > 2048) throw new Error("chunkSize must be a number between 1 and 2048");
354
377
  const timeStart = Date.now();
355
378
  const { columnTypes, ddl } = await createTableFromZod({
356
- conn: this.#duck,
379
+ conn: this.#conn,
357
380
  schema,
358
381
  table,
359
382
  options: createOptions
360
383
  });
361
- const appender = await this.#duck.createAppender(table.tableName, table.schemaName, table.databaseName);
384
+ const appender = await this.#conn.createAppender(table.tableName, table.schemaName, table.databaseName);
362
385
  const chunkTypes = Array.from(columnTypes.values());
363
386
  let totalRows = 0;
364
387
  const dataAppendedCollector = createOnDataAppendedCollector();
@@ -366,29 +389,74 @@ var SqlDuck = class {
366
389
  rows: rowStream,
367
390
  chunkSize
368
391
  });
369
- for await (const dataChunk of columnStream) {
370
- const chunk = _duckdb_node_api.DuckDBDataChunk.create(chunkTypes);
371
- if (this.#logger) this.#logger(`Inserting chunk of ${dataChunk.length} rows`);
372
- totalRows += dataChunk?.[0]?.length ?? 0;
373
- chunk.setColumns(dataChunk);
374
- appender.appendDataChunk(chunk);
375
- appender.flushSync();
376
- if (onDataAppended !== void 0) {
377
- const payload = dataAppendedCollector(totalRows);
378
- if (isOnDataAppendedAsyncCb(onDataAppended)) await onDataAppended(payload);
379
- else onDataAppended(payload);
392
+ try {
393
+ for await (const dataChunk of columnStream) {
394
+ const chunk = _duckdb_node_api.DuckDBDataChunk.create(chunkTypes);
395
+ this.#logger.debug(`Inserting chunk of ${dataChunk.length} rows`, { table: table.getFullName() });
396
+ totalRows += dataChunk?.[0]?.length ?? 0;
397
+ chunk.setColumns(dataChunk);
398
+ appender.appendDataChunk(chunk);
399
+ appender.flushSync();
400
+ if (onDataAppended !== void 0) {
401
+ const payload = dataAppendedCollector(totalRows);
402
+ if (isOnDataAppendedAsyncCb(onDataAppended)) await onDataAppended(payload);
403
+ else onDataAppended(payload);
404
+ }
380
405
  }
406
+ appender.closeSync();
407
+ const timeMs = Math.round(Date.now() - timeStart);
408
+ this.#logger.info(`Successfully appended ${totalRows} rows into '${table.getFullName()}' in ${timeMs}ms`, {
409
+ table: table.getFullName(),
410
+ timeMs,
411
+ totalRows
412
+ });
413
+ return {
414
+ timeMs,
415
+ totalRows,
416
+ createTableDDL: ddl
417
+ };
418
+ } catch (e) {
419
+ appender.closeSync();
420
+ const msg = `Failed to append data into table '${table.getFullName()}' - ${e?.message ?? ""}`;
421
+ this.#logger.error(msg, { table: table.getFullName() });
422
+ throw new Error(msg, { cause: e });
381
423
  }
382
- appender.closeSync();
424
+ };
425
+ };
426
+ //#endregion
427
+ //#region src/utils/zod-codecs.ts
428
+ const zodCodecs = {
429
+ dateToString: zod.codec(zod.date(), zod.iso.datetime(), {
430
+ decode: (date) => date.toISOString(),
431
+ encode: (isoString) => new Date(isoString)
432
+ }),
433
+ bigintToString: zod.codec(zod.bigint(), zod.string().meta({ format: "int64" }), {
434
+ decode: (bigint) => bigint.toString(),
435
+ encode: BigInt
436
+ })
437
+ };
438
+ //#endregion
439
+ //#region src/objects/database.ts
440
+ var Database = class {
441
+ #params;
442
+ get alias() {
443
+ return this.#params.alias;
444
+ }
445
+ constructor(params) {
446
+ this.#params = params;
447
+ }
448
+ toJson() {
383
449
  return {
384
- timeMs: Math.round(Date.now() - timeStart),
385
- totalRows,
386
- createTableDDL: ddl
450
+ type: "database",
451
+ params: { alias: this.#params.alias }
387
452
  };
388
- };
453
+ }
454
+ [Symbol.toStringTag]() {
455
+ return this.alias;
456
+ }
389
457
  };
390
458
  //#endregion
391
- //#region src/table/table.ts
459
+ //#region src/objects/table.ts
392
460
  var Table = class Table {
393
461
  #fqTable;
394
462
  get tableName() {
@@ -430,20 +498,273 @@ var Table = class Table {
430
498
  };
431
499
  };
432
500
  //#endregion
433
- //#region src/utils/zod-codecs.ts
434
- const zodCodecs = {
435
- dateToString: zod.codec(zod.date(), zod.iso.datetime(), {
436
- decode: (date) => date.toISOString(),
437
- encode: (isoString) => new Date(isoString)
438
- }),
439
- bigintToString: zod.codec(zod.bigint(), zod.string().meta({ format: "int64" }), {
440
- decode: (bigint) => bigint.toString(),
441
- encode: BigInt
442
- })
501
+ //#region src/validation/core/duckdb-reserved-keywords.ts
502
+ /**
503
+ * DuckDB reserved keywords that cannot be used as unquoted identifiers.
504
+ * @see https://duckdb.org/docs/sql/keywords-and-identifiers.html
505
+ */
506
+ const duckdbReservedKeywords = [
507
+ "ALL",
508
+ "ANALYSE",
509
+ "ANALYZE",
510
+ "AND",
511
+ "ANY",
512
+ "ARRAY",
513
+ "AS",
514
+ "ASC",
515
+ "ASYMMETRIC",
516
+ "BOTH",
517
+ "CASE",
518
+ "CAST",
519
+ "CHECK",
520
+ "COLLATE",
521
+ "COLUMN",
522
+ "CONSTRAINT",
523
+ "CREATE",
524
+ "CROSS",
525
+ "CURRENT_CATALOG",
526
+ "CURRENT_DATE",
527
+ "CURRENT_ROLE",
528
+ "CURRENT_SCHEMA",
529
+ "CURRENT_TIME",
530
+ "CURRENT_TIMESTAMP",
531
+ "CURRENT_USER",
532
+ "DEFAULT",
533
+ "DEFERRABLE",
534
+ "DESC",
535
+ "DISTINCT",
536
+ "DO",
537
+ "ELSE",
538
+ "END",
539
+ "EXCEPT",
540
+ "EXISTS",
541
+ "EXTRACT",
542
+ "FALSE",
543
+ "FETCH",
544
+ "FOR",
545
+ "FOREIGN",
546
+ "FROM",
547
+ "GRANT",
548
+ "GROUP",
549
+ "HAVING",
550
+ "IF",
551
+ "ILIKE",
552
+ "IN",
553
+ "INITIALLY",
554
+ "INNER",
555
+ "INTERSECT",
556
+ "INTO",
557
+ "IS",
558
+ "ISNULL",
559
+ "JOIN",
560
+ "LATERAL",
561
+ "LEADING",
562
+ "LEFT",
563
+ "LIKE",
564
+ "LIMIT",
565
+ "LOCALTIME",
566
+ "LOCALTIMESTAMP",
567
+ "NATURAL",
568
+ "NOT",
569
+ "NOTNULL",
570
+ "NULL",
571
+ "OFFSET",
572
+ "ON",
573
+ "ONLY",
574
+ "OR",
575
+ "ORDER",
576
+ "OUTER",
577
+ "OVERLAPS",
578
+ "PLACING",
579
+ "PRIMARY",
580
+ "REFERENCES",
581
+ "RETURNING",
582
+ "RIGHT",
583
+ "ROW",
584
+ "SELECT",
585
+ "SESSION_USER",
586
+ "SIMILAR",
587
+ "SOME",
588
+ "SYMMETRIC",
589
+ "TABLE",
590
+ "THEN",
591
+ "TO",
592
+ "TRAILING",
593
+ "TRUE",
594
+ "UNION",
595
+ "UNIQUE",
596
+ "USING",
597
+ "VARIADIC",
598
+ "VERBOSE",
599
+ "WHEN",
600
+ "WHERE",
601
+ "WINDOW",
602
+ "WITH"
603
+ ];
604
+ //#endregion
605
+ //#region src/validation/zod/duckdb-valid-names.schemas.ts
606
+ const duckdbMaximumObjectNameLength = 120;
607
+ const duckDbObjectNameRegex = /^[a-z_]\w*$/i;
608
+ const duckdbReservedKeywordsSet = new Set(duckdbReservedKeywords.map((k) => k.toUpperCase()));
609
+ const duckTableNameSchema = zod.string().min(1).max(duckdbMaximumObjectNameLength).regex(duckDbObjectNameRegex, "Table name must start with a letter or underscore, and contain only letters, numbers and underscores").refine((value) => !duckdbReservedKeywordsSet.has(value.toUpperCase()), { error: `Value is a DuckDB reserved keyword and cannot be used as a table name` });
610
+ const duckTableAliasSchema = duckTableNameSchema;
611
+ //#endregion
612
+ //#region src/manager/database/duck-database-manager.schemas.ts
613
+ const duckdbAttachOptionsSchema = zod.strictObject({
614
+ ACCESS_MODE: zod.optional(zod.enum([
615
+ "READ_ONLY",
616
+ "READ_WRITE",
617
+ "AUTOMATIC"
618
+ ])),
619
+ COMPRESS: zod.optional(zod.enum(["true", "false"])),
620
+ TYPE: zod.optional(zod.enum(["DUCKDB", "SQLITE"])),
621
+ BLOCK_SIZE: zod.optional(zod.int32().min(16384).max(262144)),
622
+ ROW_GROUP_SIZE: zod.optional(zod.int32().positive()),
623
+ STORAGE_VERSION: zod.optional(zod.string().startsWith("v").regex(/^v?\d{1,4}\.\d{1,4}\.\d{1,4}$/)),
624
+ ENCRYPTION_KEY: zod.optional(zod.string().min(8)),
625
+ ENCRYPTION_CIPHER: zod.optional(zod.enum([
626
+ "CBC",
627
+ "CTR",
628
+ "GCM"
629
+ ]))
630
+ });
631
+ const duckDatabaseManagerDbParamsSchema = zod.discriminatedUnion("type", [zod.strictObject({
632
+ type: zod.literal(":memory:"),
633
+ alias: duckTableAliasSchema,
634
+ options: zod.optional(duckdbAttachOptionsSchema)
635
+ }), zod.strictObject({
636
+ type: zod.literal("duckdb"),
637
+ path: zod.string().min(4).endsWith(".db"),
638
+ alias: duckTableAliasSchema,
639
+ options: zod.optional(duckdbAttachOptionsSchema)
640
+ })]);
641
+ //#endregion
642
+ //#region src/manager/database/commands/duck-database-attach-command.ts
643
+ var DuckDatabaseAttachCommand = class {
644
+ options;
645
+ dbParams;
646
+ constructor(dbParams, options) {
647
+ this.dbParams = dbParams;
648
+ this.options = options ?? {};
649
+ }
650
+ getRawSql = () => {
651
+ const dbParams = this.dbParams;
652
+ const parts = ["ATTACH", this.options.behaviour].filter(Boolean);
653
+ const { type, alias } = dbParams;
654
+ switch (type) {
655
+ case ":memory:":
656
+ parts.push("':memory:'");
657
+ break;
658
+ case "duckdb":
659
+ parts.push(`'${dbParams.path}'`);
660
+ break;
661
+ default: (0, _httpx_assert.assertNever)(type);
662
+ }
663
+ if (alias !== null) parts.push("AS", `${alias}`);
664
+ const options = (0, _httpx_plain_object.isPlainObject)(dbParams.options) ? Object.entries(dbParams.options).map(([key, value]) => {
665
+ return key === "ACCESS_MODE" ? value : `${key} '${value}'`;
666
+ }) : [];
667
+ if (options.length > 0) parts.push(`(${options.join(", ")})`);
668
+ return parts.filter(Boolean).join(" ");
669
+ };
670
+ };
671
+ //#endregion
672
+ //#region src/manager/database/duck-database-manager.ts
673
+ var DuckDatabaseManager = class {
674
+ #conn;
675
+ #logger;
676
+ constructor(conn, params) {
677
+ this.#conn = conn;
678
+ this.#logger = params?.logger ?? sqlduckDefaultLogtapeLogger.with({ source: "DuckDatabaseManager" });
679
+ }
680
+ /**
681
+ * Attach a database to the current connection
682
+ *
683
+ * @example
684
+ * ```typescript
685
+ * const dbManager = new DuckDatabaseManager(conn);
686
+ * const database = dbManager.attach({
687
+ * type: ':memory:', // can be 'duckdb', 's3'...
688
+ * alias: 'mydb',
689
+ * options: { COMPRESS: 'true' }
690
+ * });
691
+ *
692
+ * console.log(database.alias); // 'mydb'
693
+ * ```
694
+ */
695
+ attach = async (dbParams, options) => {
696
+ const params = zod.parse(duckDatabaseManagerDbParamsSchema, dbParams);
697
+ const rawSql = new DuckDatabaseAttachCommand(params, options).getRawSql();
698
+ await this.#executeRawSqlCommand(`attach(${params.alias})`, rawSql);
699
+ return new Database({ alias: params.alias });
700
+ };
701
+ attachOrReplace = async (dbParams) => {
702
+ return this.attach(dbParams, { behaviour: "OR REPLACE" });
703
+ };
704
+ attachIfNotExists = async (dbParams) => {
705
+ return this.attach(dbParams, { behaviour: "IF NOT EXISTS" });
706
+ };
707
+ showDatabases = async () => {
708
+ return await this.#executeRawSqlCommand("showDatabases()", `SHOW DATABASES`);
709
+ };
710
+ detach = async (dbAlias) => {
711
+ const safeAlias = zod.parse(duckTableAliasSchema, dbAlias);
712
+ await this.#executeRawSqlCommand(`detach(${safeAlias})`, `DETACH ${safeAlias}`);
713
+ return true;
714
+ };
715
+ detachIfExists = async (dbAlias) => {
716
+ const safeAlias = zod.parse(duckTableAliasSchema, dbAlias);
717
+ await this.#executeRawSqlCommand(`detachIfExists(${safeAlias})`, `DETACH IF EXISTS ${safeAlias}`);
718
+ return true;
719
+ };
720
+ /**
721
+ * The statistics recomputed by the ANALYZE statement are only used for join order optimization.
722
+ *
723
+ * It is therefore recommended to recompute these statistics for improved join orders,
724
+ * especially after performing large updates (inserts and/or deletes).
725
+ *
726
+ * @link https://duckdb.org/docs/stable/sql/statements/analyze
727
+ */
728
+ analyze = async () => {
729
+ await this.#executeRawSqlCommand("analyze()", "ANALYZE");
730
+ return true;
731
+ };
732
+ checkpoint = async (dbAlias) => {
733
+ const safeAlias = zod.parse(duckTableAliasSchema, dbAlias);
734
+ await this.#executeRawSqlCommand(`checkpoint(${safeAlias})`, `CHECKPOINT ${safeAlias}`);
735
+ return true;
736
+ };
737
+ #executeRawSqlCommand = async (name, rawSql) => {
738
+ const startTime = Date.now();
739
+ try {
740
+ const result = await this.#conn.runAndReadAll(rawSql);
741
+ const timeMs = Math.round(Date.now() - startTime);
742
+ const data = result.getRowObjectsJS();
743
+ this.#logger.info(`DuckDatabaseManager.${name} in ${timeMs}ms`, { timeMs });
744
+ return data;
745
+ } catch (e) {
746
+ const msg = `DuckDatabaseManager: failed to run "${name}" - ${e?.message ?? ""}`;
747
+ const timeMs = Math.round(Date.now() - startTime);
748
+ this.#logger.error(msg, {
749
+ name,
750
+ sql: rawSql,
751
+ timeMs
752
+ });
753
+ throw new Error(msg, { cause: e });
754
+ }
755
+ };
443
756
  };
444
757
  //#endregion
758
+ exports.Database = Database;
759
+ exports.DuckDatabaseManager = DuckDatabaseManager;
445
760
  exports.DuckMemory = DuckMemory;
446
761
  exports.SqlDuck = SqlDuck;
447
762
  exports.Table = Table;
763
+ exports.duckDatabaseManagerDbParamsSchema = duckDatabaseManagerDbParamsSchema;
764
+ exports.duckTableAliasSchema = duckTableAliasSchema;
765
+ exports.duckTableNameSchema = duckTableNameSchema;
766
+ exports.duckdbReservedKeywords = duckdbReservedKeywords;
767
+ exports.flowbladeLogtapeSqlduckConfig = flowbladeLogtapeSqlduckConfig;
448
768
  exports.getTableCreateFromZod = getTableCreateFromZod;
769
+ exports.sqlduckDefaultLogtapeLogger = sqlduckDefaultLogtapeLogger;
449
770
  exports.zodCodecs = zodCodecs;