@flowblade/sqlduck 0.4.0 → 0.5.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/dist/index.cjs CHANGED
@@ -50,6 +50,25 @@ async function* rowsToColumnsChunks(rows, chunkSize) {
50
50
  }
51
51
  if (rowsInChunk > 0) yield columns;
52
52
  }
53
+ const isOnDataAppendedAsyncCb = (v) => {
54
+ return v.constructor.name === "AsyncFunction";
55
+ };
56
+ const createOnDataAppendedCollector = () => {
57
+ let lastCallbackTimeStart = Date.now();
58
+ let appendedTotalRows = 0;
59
+ return (currentTotalRows) => {
60
+ const cbTimeMs = Math.round(Date.now() - lastCallbackTimeStart);
61
+ const cbTotalRows = currentTotalRows - appendedTotalRows;
62
+ const payload = {
63
+ rowsCount: cbTotalRows,
64
+ timeMs: cbTimeMs,
65
+ rowsPerSecond: Math.round(cbTotalRows / cbTimeMs * 1e3)
66
+ };
67
+ appendedTotalRows = currentTotalRows;
68
+ lastCallbackTimeStart = Date.now();
69
+ return payload;
70
+ };
71
+ };
53
72
  const createMap = {
54
73
  CREATE: "CREATE TABLE",
55
74
  CREATE_OR_REPLACE: "CREATE OR REPLACE TABLE",
@@ -124,10 +143,8 @@ var SqlDuck = class {
124
143
  this.#logger = params.logger;
125
144
  }
126
145
  toTable = async (params) => {
127
- const { table, schema, chunkSize = 2048, rowStream, createOptions, onDataAppended, onDataAppendedBatchSize } = params;
146
+ const { table, schema, chunkSize = 2048, rowStream, createOptions, onDataAppended } = params;
128
147
  if (!Number.isSafeInteger(chunkSize) || chunkSize < 1 || chunkSize > 2048) throw new Error("chunkSize must be a number between 1 and 2048");
129
- const callbackBatchSize = onDataAppendedBatchSize ?? chunkSize;
130
- if (!Number.isSafeInteger(callbackBatchSize) || callbackBatchSize < 1) throw new Error("onDataAppendedBatchSize must be a number greater than 0");
131
148
  const timeStart = Date.now();
132
149
  const { columnTypes, ddl } = await createTableFromZod({
133
150
  conn: this.#duck,
@@ -138,6 +155,7 @@ var SqlDuck = class {
138
155
  const appender = await this.#duck.createAppender(table.tableName, table.schemaName, table.databaseName);
139
156
  const chunkTypes = columnTypes.map((v) => v[1]);
140
157
  let totalRows = 0;
158
+ const dataAppendedCollector = createOnDataAppendedCollector();
141
159
  const columnStream = rowsToColumnsChunks(rowStream, chunkSize);
142
160
  for await (const dataChunk of columnStream) {
143
161
  const chunk = _duckdb_node_api.DuckDBDataChunk.create(chunkTypes);
@@ -146,9 +164,12 @@ var SqlDuck = class {
146
164
  chunk.setColumns(dataChunk);
147
165
  appender.appendDataChunk(chunk);
148
166
  appender.flushSync();
149
- if (onDataAppended !== void 0 && totalRows % callbackBatchSize === 0) onDataAppended({ total: totalRows });
167
+ if (onDataAppended !== void 0) {
168
+ const payload = dataAppendedCollector(totalRows);
169
+ if (isOnDataAppendedAsyncCb(onDataAppended)) await onDataAppended(payload);
170
+ else onDataAppended(payload);
171
+ }
150
172
  }
151
- if (onDataAppended !== void 0 && totalRows % callbackBatchSize !== 0) onDataAppended({ total: totalRows });
152
173
  return {
153
174
  timeMs: Math.round(Date.now() - timeStart),
154
175
  totalRows,
package/dist/index.d.cts CHANGED
@@ -2,6 +2,25 @@ import { DuckDBConnection, DuckDBType } from "@duckdb/node-api";
2
2
  import * as z from "zod";
3
3
  import { ZodObject } from "zod";
4
4
 
5
+ //#region src/appender/data-appender-callback.d.ts
6
+ type OnDataAppendedParams = {
7
+ /**
8
+ * Total number of rows appended so far
9
+ */
10
+ rowsCount: number;
11
+ /**
12
+ * Time taken to append the last batch in milliseconds
13
+ */
14
+ timeMs: number;
15
+ /**
16
+ * Estimated rows per seconds
17
+ */
18
+ rowsPerSecond: number;
19
+ };
20
+ type OnDataAppendedSyncCb = (params: OnDataAppendedParams) => void;
21
+ type OnDataAppendedAsyncCb = (params: OnDataAppendedParams) => Promise<void>;
22
+ type OnDataAppendedCb = OnDataAppendedSyncCb | OnDataAppendedAsyncCb;
23
+ //#endregion
5
24
  //#region src/table/table.d.ts
6
25
  /**
7
26
  * Fully qualified table information
@@ -71,21 +90,9 @@ type ToTableParams<TSchema extends TableSchemaZod> = {
71
90
  */
72
91
  createOptions?: TableCreateOptions;
73
92
  /**
74
- * Callback called each time data is appended to the table
75
- * See also `onDataAppendedBatchSize` to limit the number of calls
76
- * when appending a lot of data
77
- */
78
- onDataAppended?: (params: {
79
- /**
80
- * Total number of rows appended so far
81
- */
82
- total: number;
83
- }) => void;
84
- /**
85
- * Number of rows appended before calling `onDataAppended` callback
86
- * @default chunkSize
93
+ * Callback called each time a datachunk is appended to the table
87
94
  */
88
- onDataAppendedBatchSize?: number;
95
+ onDataAppended?: OnDataAppendedCb;
89
96
  };
90
97
  type ToTableResult = {
91
98
  /**
package/dist/index.d.mts CHANGED
@@ -2,6 +2,25 @@ import { DuckDBConnection, DuckDBType } from "@duckdb/node-api";
2
2
  import * as z from "zod";
3
3
  import { ZodObject } from "zod";
4
4
 
5
+ //#region src/appender/data-appender-callback.d.ts
6
+ type OnDataAppendedParams = {
7
+ /**
8
+ * Total number of rows appended so far
9
+ */
10
+ rowsCount: number;
11
+ /**
12
+ * Time taken to append the last batch in milliseconds
13
+ */
14
+ timeMs: number;
15
+ /**
16
+ * Estimated rows per seconds
17
+ */
18
+ rowsPerSecond: number;
19
+ };
20
+ type OnDataAppendedSyncCb = (params: OnDataAppendedParams) => void;
21
+ type OnDataAppendedAsyncCb = (params: OnDataAppendedParams) => Promise<void>;
22
+ type OnDataAppendedCb = OnDataAppendedSyncCb | OnDataAppendedAsyncCb;
23
+ //#endregion
5
24
  //#region src/table/table.d.ts
6
25
  /**
7
26
  * Fully qualified table information
@@ -71,21 +90,9 @@ type ToTableParams<TSchema extends TableSchemaZod> = {
71
90
  */
72
91
  createOptions?: TableCreateOptions;
73
92
  /**
74
- * Callback called each time data is appended to the table
75
- * See also `onDataAppendedBatchSize` to limit the number of calls
76
- * when appending a lot of data
77
- */
78
- onDataAppended?: (params: {
79
- /**
80
- * Total number of rows appended so far
81
- */
82
- total: number;
83
- }) => void;
84
- /**
85
- * Number of rows appended before calling `onDataAppended` callback
86
- * @default chunkSize
93
+ * Callback called each time a datachunk is appended to the table
87
94
  */
88
- onDataAppendedBatchSize?: number;
95
+ onDataAppended?: OnDataAppendedCb;
89
96
  };
90
97
  type ToTableResult = {
91
98
  /**
package/dist/index.mjs CHANGED
@@ -29,6 +29,25 @@ async function* rowsToColumnsChunks(rows, chunkSize) {
29
29
  }
30
30
  if (rowsInChunk > 0) yield columns;
31
31
  }
32
+ const isOnDataAppendedAsyncCb = (v) => {
33
+ return v.constructor.name === "AsyncFunction";
34
+ };
35
+ const createOnDataAppendedCollector = () => {
36
+ let lastCallbackTimeStart = Date.now();
37
+ let appendedTotalRows = 0;
38
+ return (currentTotalRows) => {
39
+ const cbTimeMs = Math.round(Date.now() - lastCallbackTimeStart);
40
+ const cbTotalRows = currentTotalRows - appendedTotalRows;
41
+ const payload = {
42
+ rowsCount: cbTotalRows,
43
+ timeMs: cbTimeMs,
44
+ rowsPerSecond: Math.round(cbTotalRows / cbTimeMs * 1e3)
45
+ };
46
+ appendedTotalRows = currentTotalRows;
47
+ lastCallbackTimeStart = Date.now();
48
+ return payload;
49
+ };
50
+ };
32
51
  const createMap = {
33
52
  CREATE: "CREATE TABLE",
34
53
  CREATE_OR_REPLACE: "CREATE OR REPLACE TABLE",
@@ -103,10 +122,8 @@ var SqlDuck = class {
103
122
  this.#logger = params.logger;
104
123
  }
105
124
  toTable = async (params) => {
106
- const { table, schema, chunkSize = 2048, rowStream, createOptions, onDataAppended, onDataAppendedBatchSize } = params;
125
+ const { table, schema, chunkSize = 2048, rowStream, createOptions, onDataAppended } = params;
107
126
  if (!Number.isSafeInteger(chunkSize) || chunkSize < 1 || chunkSize > 2048) throw new Error("chunkSize must be a number between 1 and 2048");
108
- const callbackBatchSize = onDataAppendedBatchSize ?? chunkSize;
109
- if (!Number.isSafeInteger(callbackBatchSize) || callbackBatchSize < 1) throw new Error("onDataAppendedBatchSize must be a number greater than 0");
110
127
  const timeStart = Date.now();
111
128
  const { columnTypes, ddl } = await createTableFromZod({
112
129
  conn: this.#duck,
@@ -117,6 +134,7 @@ var SqlDuck = class {
117
134
  const appender = await this.#duck.createAppender(table.tableName, table.schemaName, table.databaseName);
118
135
  const chunkTypes = columnTypes.map((v) => v[1]);
119
136
  let totalRows = 0;
137
+ const dataAppendedCollector = createOnDataAppendedCollector();
120
138
  const columnStream = rowsToColumnsChunks(rowStream, chunkSize);
121
139
  for await (const dataChunk of columnStream) {
122
140
  const chunk = DuckDBDataChunk.create(chunkTypes);
@@ -125,9 +143,12 @@ var SqlDuck = class {
125
143
  chunk.setColumns(dataChunk);
126
144
  appender.appendDataChunk(chunk);
127
145
  appender.flushSync();
128
- if (onDataAppended !== void 0 && totalRows % callbackBatchSize === 0) onDataAppended({ total: totalRows });
146
+ if (onDataAppended !== void 0) {
147
+ const payload = dataAppendedCollector(totalRows);
148
+ if (isOnDataAppendedAsyncCb(onDataAppended)) await onDataAppended(payload);
149
+ else onDataAppended(payload);
150
+ }
129
151
  }
130
- if (onDataAppended !== void 0 && totalRows % callbackBatchSize !== 0) onDataAppended({ total: totalRows });
131
152
  return {
132
153
  timeMs: Math.round(Date.now() - timeStart),
133
154
  totalRows,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowblade/sqlduck",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "exports": {
@@ -96,7 +96,7 @@
96
96
  "tarn": "3.0.2",
97
97
  "tedious": "19.2.0",
98
98
  "testcontainers": "11.11.0",
99
- "tsdown": "0.18.3",
99
+ "tsdown": "0.18.4",
100
100
  "tsx": "4.21.0",
101
101
  "typedoc": "0.28.15",
102
102
  "typedoc-plugin-markdown": "4.9.0",