@nshiab/simple-data-analysis-core 2.0.5 → 2.0.7
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 +118 -12
- package/esm/class/Simple.d.ts +8 -2
- package/esm/class/Simple.d.ts.map +1 -1
- package/esm/class/Simple.js +9 -3
- package/esm/class/SimpleDB.d.ts +72 -1
- package/esm/class/SimpleDB.d.ts.map +1 -1
- package/esm/class/SimpleDB.js +81 -1
- package/esm/class/SimpleTable.d.ts +271 -288
- package/esm/class/SimpleTable.d.ts.map +1 -1
- package/esm/class/SimpleTable.js +269 -340
- package/esm/helpers/LogValue.d.ts +8 -0
- package/esm/helpers/LogValue.d.ts.map +1 -0
- package/esm/helpers/LogValue.js +23 -0
- package/esm/helpers/cacheTableDependencies.d.ts +9 -0
- package/esm/helpers/cacheTableDependencies.d.ts.map +1 -1
- package/esm/helpers/cacheTableDependencies.js +131 -21
- package/esm/helpers/cleanSQL.d.ts +1 -1
- package/esm/helpers/cleanSQL.d.ts.map +1 -1
- package/esm/helpers/cleanSQL.js +268 -23
- package/esm/helpers/flushAllTables.d.ts.map +1 -1
- package/esm/helpers/flushAllTables.js +23 -28
- package/esm/helpers/foldIdentifier.d.ts +3 -0
- package/esm/helpers/foldIdentifier.d.ts.map +1 -0
- package/esm/helpers/foldIdentifier.js +4 -0
- package/esm/helpers/geometryFromJSON.d.ts +3 -0
- package/esm/helpers/geometryFromJSON.d.ts.map +1 -0
- package/esm/helpers/geometryFromJSON.js +4 -0
- package/esm/helpers/index.d.ts +1 -0
- package/esm/helpers/index.d.ts.map +1 -1
- package/esm/helpers/index.js +1 -0
- package/esm/helpers/logData.d.ts.map +1 -1
- package/esm/helpers/logData.js +45 -44
- package/esm/helpers/makeLogConverter.d.ts +5 -0
- package/esm/helpers/makeLogConverter.d.ts.map +1 -0
- package/esm/helpers/makeLogConverter.js +64 -0
- package/esm/helpers/osmFiles.d.ts.map +1 -1
- package/esm/helpers/parseTypes.d.ts +1 -1
- package/esm/helpers/parseTypes.d.ts.map +1 -1
- package/esm/helpers/parseTypes.js +4 -0
- package/esm/helpers/pendingOps.d.ts +4 -2
- package/esm/helpers/pendingOps.d.ts.map +1 -1
- package/esm/helpers/prepareGeometry.d.ts +3 -0
- package/esm/helpers/prepareGeometry.d.ts.map +1 -0
- package/esm/helpers/prepareGeometry.js +99 -0
- package/esm/helpers/prepareJSON.d.ts +3 -0
- package/esm/helpers/prepareJSON.d.ts.map +1 -0
- package/esm/helpers/prepareJSON.js +50 -0
- package/esm/helpers/printTable.d.ts +5 -4
- package/esm/helpers/printTable.d.ts.map +1 -1
- package/esm/helpers/printTable.js +32 -36
- package/esm/helpers/queryDB.js +1 -1
- package/esm/helpers/queueAsyncBarrier.d.ts +4 -0
- package/esm/helpers/queueAsyncBarrier.d.ts.map +1 -1
- package/esm/helpers/queueAsyncBarrier.js +4 -0
- package/esm/helpers/queueOp.d.ts.map +1 -1
- package/esm/helpers/queueOp.js +5 -3
- package/esm/helpers/readMutationRows.d.ts +9 -0
- package/esm/helpers/readMutationRows.d.ts.map +1 -0
- package/esm/helpers/readMutationRows.js +94 -0
- package/esm/helpers/referencedTables.d.ts +9 -0
- package/esm/helpers/referencedTables.d.ts.map +1 -0
- package/esm/helpers/referencedTables.js +22 -0
- package/esm/helpers/runQuery.d.ts.map +1 -1
- package/esm/helpers/runQuery.js +11 -13
- package/esm/helpers/scanSQL.d.ts +7 -0
- package/esm/helpers/scanSQL.d.ts.map +1 -0
- package/esm/helpers/scanSQL.js +71 -0
- package/esm/helpers/tableRegistry.d.ts +2 -0
- package/esm/helpers/tableRegistry.d.ts.map +1 -1
- package/esm/helpers/tableRegistry.js +12 -4
- package/esm/helpers/updateColumnsWithJS.d.ts +52 -0
- package/esm/helpers/updateColumnsWithJS.d.ts.map +1 -0
- package/esm/helpers/updateColumnsWithJS.js +139 -0
- package/esm/methods/addColumn.d.ts +1 -1
- package/esm/methods/addColumn.d.ts.map +1 -1
- package/esm/methods/bins.d.ts +1 -1
- package/esm/methods/bins.d.ts.map +1 -1
- package/esm/methods/bins.js +45 -29
- package/esm/methods/bm25.d.ts.map +1 -1
- package/esm/methods/bm25.js +1 -2
- package/esm/methods/cache.d.ts.map +1 -1
- package/esm/methods/cache.js +4 -6
- package/esm/methods/convert.d.ts +2 -2
- package/esm/methods/convert.d.ts.map +1 -1
- package/esm/methods/convert.js +5 -0
- package/esm/methods/getBottom.d.ts +1 -1
- package/esm/methods/getBottom.d.ts.map +1 -1
- package/esm/methods/getBottom.js +2 -2
- package/esm/methods/getData.d.ts +1 -1
- package/esm/methods/getData.d.ts.map +1 -1
- package/esm/methods/getData.js +2 -2
- package/esm/methods/join.d.ts.map +1 -1
- package/esm/methods/join.js +8 -16
- package/esm/methods/joinGeo.d.ts.map +1 -1
- package/esm/methods/joinGeo.js +10 -19
- package/esm/methods/loadArray.d.ts +1 -1
- package/esm/methods/loadArray.d.ts.map +1 -1
- package/esm/methods/loadArray.js +74 -19
- package/esm/methods/loadData.js +3 -0
- package/esm/methods/log.d.ts +7 -0
- package/esm/methods/log.d.ts.map +1 -0
- package/esm/methods/log.js +63 -0
- package/esm/methods/logBottom.d.ts +5 -0
- package/esm/methods/logBottom.d.ts.map +1 -0
- package/esm/methods/logBottom.js +9 -0
- package/esm/methods/removeTable.d.ts.map +1 -1
- package/esm/methods/removeTable.js +2 -0
- package/esm/methods/removeTables.d.ts.map +1 -1
- package/esm/methods/removeTables.js +7 -0
- package/esm/methods/renameTable.d.ts.map +1 -1
- package/esm/methods/renameTable.js +4 -0
- package/esm/methods/rowToText.js +2 -2
- package/esm/methods/selectTables.d.ts.map +1 -1
- package/esm/methods/selectTables.js +6 -0
- package/esm/methods/setTypes.d.ts +1 -1
- package/esm/methods/setTypes.d.ts.map +1 -1
- package/esm/methods/stream.d.ts.map +1 -1
- package/esm/methods/stream.js +2 -1
- package/esm/methods/updateWithJS.d.ts +1 -3
- package/esm/methods/updateWithJS.d.ts.map +1 -1
- package/esm/methods/updateWithJS.js +123 -37
- package/llm.md +365 -461
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/script/class/Simple.d.ts +8 -2
- package/script/class/Simple.d.ts.map +1 -1
- package/script/class/Simple.js +9 -3
- package/script/class/SimpleDB.d.ts +72 -1
- package/script/class/SimpleDB.d.ts.map +1 -1
- package/script/class/SimpleDB.js +81 -1
- package/script/class/SimpleTable.d.ts +271 -288
- package/script/class/SimpleTable.d.ts.map +1 -1
- package/script/class/SimpleTable.js +269 -340
- package/script/helpers/LogValue.d.ts +8 -0
- package/script/helpers/LogValue.d.ts.map +1 -0
- package/script/helpers/LogValue.js +26 -0
- package/script/helpers/cacheTableDependencies.d.ts +9 -0
- package/script/helpers/cacheTableDependencies.d.ts.map +1 -1
- package/script/helpers/cacheTableDependencies.js +170 -20
- package/script/helpers/cleanSQL.d.ts +1 -1
- package/script/helpers/cleanSQL.d.ts.map +1 -1
- package/script/helpers/cleanSQL.js +271 -23
- package/script/helpers/flushAllTables.d.ts.map +1 -1
- package/script/helpers/flushAllTables.js +24 -29
- package/script/helpers/foldIdentifier.d.ts +3 -0
- package/script/helpers/foldIdentifier.d.ts.map +1 -0
- package/script/helpers/foldIdentifier.js +7 -0
- package/script/helpers/geometryFromJSON.d.ts +3 -0
- package/script/helpers/geometryFromJSON.d.ts.map +1 -0
- package/script/helpers/geometryFromJSON.js +7 -0
- package/script/helpers/index.d.ts +1 -0
- package/script/helpers/index.d.ts.map +1 -1
- package/script/helpers/index.js +3 -1
- package/script/helpers/logData.d.ts.map +1 -1
- package/script/helpers/logData.js +45 -44
- package/script/helpers/makeLogConverter.d.ts +5 -0
- package/script/helpers/makeLogConverter.d.ts.map +1 -0
- package/script/helpers/makeLogConverter.js +70 -0
- package/script/helpers/osmFiles.d.ts.map +1 -1
- package/script/helpers/parseTypes.d.ts +1 -1
- package/script/helpers/parseTypes.d.ts.map +1 -1
- package/script/helpers/parseTypes.js +4 -0
- package/script/helpers/pendingOps.d.ts +4 -2
- package/script/helpers/pendingOps.d.ts.map +1 -1
- package/script/helpers/prepareGeometry.d.ts +3 -0
- package/script/helpers/prepareGeometry.d.ts.map +1 -0
- package/script/helpers/prepareGeometry.js +102 -0
- package/script/helpers/prepareJSON.d.ts +3 -0
- package/script/helpers/prepareJSON.d.ts.map +1 -0
- package/script/helpers/prepareJSON.js +53 -0
- package/script/helpers/printTable.d.ts +5 -4
- package/script/helpers/printTable.d.ts.map +1 -1
- package/script/helpers/printTable.js +32 -36
- package/script/helpers/queryDB.js +1 -1
- package/script/helpers/queueAsyncBarrier.d.ts +4 -0
- package/script/helpers/queueAsyncBarrier.d.ts.map +1 -1
- package/script/helpers/queueAsyncBarrier.js +4 -0
- package/script/helpers/queueOp.d.ts.map +1 -1
- package/script/helpers/queueOp.js +4 -2
- package/script/helpers/readMutationRows.d.ts +9 -0
- package/script/helpers/readMutationRows.d.ts.map +1 -0
- package/script/helpers/readMutationRows.js +97 -0
- package/script/helpers/referencedTables.d.ts +9 -0
- package/script/helpers/referencedTables.d.ts.map +1 -0
- package/script/helpers/referencedTables.js +28 -0
- package/script/helpers/runQuery.d.ts.map +1 -1
- package/script/helpers/runQuery.js +11 -13
- package/script/helpers/scanSQL.d.ts +7 -0
- package/script/helpers/scanSQL.d.ts.map +1 -0
- package/script/helpers/scanSQL.js +74 -0
- package/script/helpers/tableRegistry.d.ts +2 -0
- package/script/helpers/tableRegistry.d.ts.map +1 -1
- package/script/helpers/tableRegistry.js +16 -4
- package/script/helpers/updateColumnsWithJS.d.ts +52 -0
- package/script/helpers/updateColumnsWithJS.d.ts.map +1 -0
- package/script/helpers/updateColumnsWithJS.js +145 -0
- package/script/methods/addColumn.d.ts +1 -1
- package/script/methods/addColumn.d.ts.map +1 -1
- package/script/methods/bins.d.ts +1 -1
- package/script/methods/bins.d.ts.map +1 -1
- package/script/methods/bins.js +45 -29
- package/script/methods/bm25.d.ts.map +1 -1
- package/script/methods/bm25.js +1 -2
- package/script/methods/cache.d.ts.map +1 -1
- package/script/methods/cache.js +3 -5
- package/script/methods/convert.d.ts +2 -2
- package/script/methods/convert.d.ts.map +1 -1
- package/script/methods/convert.js +5 -0
- package/script/methods/getBottom.d.ts +1 -1
- package/script/methods/getBottom.d.ts.map +1 -1
- package/script/methods/getBottom.js +2 -2
- package/script/methods/getData.d.ts +1 -1
- package/script/methods/getData.d.ts.map +1 -1
- package/script/methods/getData.js +2 -2
- package/script/methods/join.d.ts.map +1 -1
- package/script/methods/join.js +8 -16
- package/script/methods/joinGeo.d.ts.map +1 -1
- package/script/methods/joinGeo.js +10 -19
- package/script/methods/loadArray.d.ts +1 -1
- package/script/methods/loadArray.d.ts.map +1 -1
- package/script/methods/loadArray.js +74 -19
- package/script/methods/loadData.js +3 -0
- package/script/methods/log.d.ts +7 -0
- package/script/methods/log.d.ts.map +1 -0
- package/script/methods/log.js +69 -0
- package/script/methods/logBottom.d.ts +5 -0
- package/script/methods/logBottom.d.ts.map +1 -0
- package/script/methods/logBottom.js +15 -0
- package/script/methods/removeTable.d.ts.map +1 -1
- package/script/methods/removeTable.js +2 -0
- package/script/methods/removeTables.d.ts.map +1 -1
- package/script/methods/removeTables.js +7 -0
- package/script/methods/renameTable.d.ts.map +1 -1
- package/script/methods/renameTable.js +4 -0
- package/script/methods/rowToText.js +2 -2
- package/script/methods/selectTables.d.ts.map +1 -1
- package/script/methods/selectTables.js +6 -0
- package/script/methods/setTypes.d.ts +1 -1
- package/script/methods/setTypes.d.ts.map +1 -1
- package/script/methods/stream.d.ts.map +1 -1
- package/script/methods/stream.js +2 -1
- package/script/methods/updateWithJS.d.ts +1 -3
- package/script/methods/updateWithJS.d.ts.map +1 -1
- package/script/methods/updateWithJS.js +122 -36
|
@@ -1,15 +1,17 @@
|
|
|
1
|
+
import LogValue from "./LogValue.js";
|
|
1
2
|
import wrapString from "./wrapString.js";
|
|
2
3
|
/**
|
|
3
4
|
* Prints a formatted table to the console with support for word wrapping
|
|
4
|
-
* within cells. Unlike `console.table()`, this function properly
|
|
5
|
-
* multi-line content
|
|
6
|
-
*
|
|
5
|
+
* within headers and cells. Unlike `console.table()`, this function properly
|
|
6
|
+
* handles multi-line content, making it ideal for displaying data with long
|
|
7
|
+
* column names and text values.
|
|
7
8
|
*
|
|
8
9
|
* @param data - An array of objects representing the rows of the table. Each
|
|
9
10
|
* object should have string keys.
|
|
10
11
|
* @param options - Optional configuration for table rendering.
|
|
11
12
|
* @param options.maxColumnWidth - The maximum width for any column (default:
|
|
12
|
-
* `75`).
|
|
13
|
+
* `75`). Headers and values exceeding this width will be wrapped at word
|
|
14
|
+
* boundaries.
|
|
13
15
|
* @param options.minColumnWidth - The minimum width for any column (default:
|
|
14
16
|
* `3`).
|
|
15
17
|
* @param options.typesRowIndex - The index of a row that contains type
|
|
@@ -47,8 +49,12 @@ export default function printTable(data, options) {
|
|
|
47
49
|
const minColumnWidth = options?.minColumnWidth ?? 3;
|
|
48
50
|
// Helper function to format values for display
|
|
49
51
|
const formatValue = (value) => {
|
|
52
|
+
if (value instanceof LogValue)
|
|
53
|
+
return value.text;
|
|
50
54
|
if (value instanceof Date) {
|
|
51
|
-
return value.
|
|
55
|
+
return Number.isNaN(value.getTime())
|
|
56
|
+
? "Invalid Date"
|
|
57
|
+
: value.toISOString();
|
|
52
58
|
}
|
|
53
59
|
return String(value);
|
|
54
60
|
};
|
|
@@ -62,7 +68,7 @@ export default function printTable(data, options) {
|
|
|
62
68
|
// First, seed widths from header names.
|
|
63
69
|
const columnWidths = {};
|
|
64
70
|
for (const col of columns) {
|
|
65
|
-
columnWidths[col] = col.length;
|
|
71
|
+
columnWidths[col] = Math.max(...col.split("\n").map((line) => line.length));
|
|
66
72
|
}
|
|
67
73
|
// Format every cell, track the longest raw line per column, and
|
|
68
74
|
// store the formatted strings for the wrapping step that follows.
|
|
@@ -90,31 +96,16 @@ export default function printTable(data, options) {
|
|
|
90
96
|
for (const col of columns) {
|
|
91
97
|
columnWidths[col] = Math.min(Math.max(columnWidths[col], minColumnWidth), maxColumnWidth);
|
|
92
98
|
}
|
|
93
|
-
//
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const allWrappedLines = [];
|
|
104
|
-
for (const line of lines) {
|
|
105
|
-
if (line.length <= width) {
|
|
106
|
-
allWrappedLines.push(line);
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
// Wrap long lines at word boundaries
|
|
110
|
-
const wrapped = wrapString(line, width);
|
|
111
|
-
allWrappedLines.push(...wrapped.split("\n"));
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
wrappedRow[col] = allWrappedLines.length > 0 ? allWrappedLines : [""];
|
|
115
|
-
}
|
|
116
|
-
wrappedData.push(wrappedRow);
|
|
117
|
-
}
|
|
99
|
+
// Use the same newline and word wrapping rules for headers and cells.
|
|
100
|
+
const wrapCell = (value, width) => {
|
|
101
|
+
const lines = value.split("\n").flatMap((line) => line.length <= width ? [line] : wrapString(line, width).split("\n"));
|
|
102
|
+
return lines.length > 0 ? lines : [""];
|
|
103
|
+
};
|
|
104
|
+
const wrappedHeaders = columns.map((col) => wrapCell(col, columnWidths[col]));
|
|
105
|
+
const wrappedData = formattedData.map((row) => Object.fromEntries(columns.map((col, c) => [
|
|
106
|
+
col,
|
|
107
|
+
wrapCell(row[c], columnWidths[col]),
|
|
108
|
+
])));
|
|
118
109
|
// ANSI color codes (matching Deno's console colors)
|
|
119
110
|
const colors = {
|
|
120
111
|
reset: "\x1b[0m",
|
|
@@ -130,6 +121,8 @@ export default function printTable(data, options) {
|
|
|
130
121
|
const getColorForValue = (value, isTypeRow) => {
|
|
131
122
|
if (isTypeRow)
|
|
132
123
|
return colors.grey;
|
|
124
|
+
if (value instanceof LogValue)
|
|
125
|
+
return colors[value.category];
|
|
133
126
|
if (value === null || value === undefined)
|
|
134
127
|
return colors.null;
|
|
135
128
|
if (value instanceof Date)
|
|
@@ -157,11 +150,14 @@ export default function printTable(data, options) {
|
|
|
157
150
|
};
|
|
158
151
|
// Print top border
|
|
159
152
|
console.log(createTopBorder());
|
|
160
|
-
// Print header
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
headerParts.
|
|
164
|
-
colors.reset
|
|
153
|
+
// Print each header line in bold, padding shorter headers to the same height.
|
|
154
|
+
const headerHeight = Math.max(...wrappedHeaders.map((lines) => lines.length));
|
|
155
|
+
for (let lineIdx = 0; lineIdx < headerHeight; lineIdx++) {
|
|
156
|
+
const headerParts = columns.map((col, c) => ` ${colors.bold}${pad(wrappedHeaders[c][lineIdx] ?? "", columnWidths[col])}${colors.reset} `);
|
|
157
|
+
console.log(colors.grey + "│" + colors.reset +
|
|
158
|
+
headerParts.join(colors.grey + "│" + colors.reset) + colors.grey + "│" +
|
|
159
|
+
colors.reset);
|
|
160
|
+
}
|
|
165
161
|
// Detect if any row has word wrapping (spans multiple lines)
|
|
166
162
|
let hasWordWrapping = false;
|
|
167
163
|
for (const wrappedRow of wrappedData) {
|
package/esm/helpers/queryDB.js
CHANGED
|
@@ -60,7 +60,7 @@ export default async function queryDB(simple, query, options) {
|
|
|
60
60
|
// operations queued by sync builder methods, preserving program order.
|
|
61
61
|
await flushAllTables(simple instanceof SimpleTable ? simple.sdb : simple);
|
|
62
62
|
if (options.noClean !== true) {
|
|
63
|
-
query = cleanSQL(query);
|
|
63
|
+
query = cleanSQL(query, sdb.expressionSyntax);
|
|
64
64
|
}
|
|
65
65
|
const executionOptions = {
|
|
66
66
|
...options,
|
|
@@ -11,6 +11,10 @@ import type SimpleTable from "../class/SimpleTable.js";
|
|
|
11
11
|
* drained are discarded. Operations drained by an observer inside `execute`
|
|
12
12
|
* remain applied; an asynchronous barrier does not provide database rollback.
|
|
13
13
|
*
|
|
14
|
+
* This differs from a failure while executing queued builders: during replay,
|
|
15
|
+
* the failing table's remaining chain is aborted, but unexecuted work for other
|
|
16
|
+
* tables is requeued for their next observation.
|
|
17
|
+
*
|
|
14
18
|
* @param simpleTable - The table whose chain owns the asynchronous work.
|
|
15
19
|
* @param operation - The asynchronous extension operation to queue.
|
|
16
20
|
* @param operation.method - The public method name used for diagnostics.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queueAsyncBarrier.d.ts","sourceRoot":"","sources":["../../src/helpers/queueAsyncBarrier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAGvD
|
|
1
|
+
{"version":3,"file":"queueAsyncBarrier.d.ts","sourceRoot":"","sources":["../../src/helpers/queueAsyncBarrier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAGvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,MAAM,CAAC,OAAO,UAAU,iBAAiB,CACvC,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE;IACT,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IAC9C,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,GACA,IAAI,CAKN"}
|
|
@@ -11,6 +11,10 @@ import queueOp from "./queueOp.js";
|
|
|
11
11
|
* drained are discarded. Operations drained by an observer inside `execute`
|
|
12
12
|
* remain applied; an asynchronous barrier does not provide database rollback.
|
|
13
13
|
*
|
|
14
|
+
* This differs from a failure while executing queued builders: during replay,
|
|
15
|
+
* the failing table's remaining chain is aborted, but unexecuted work for other
|
|
16
|
+
* tables is requeued for their next observation.
|
|
17
|
+
*
|
|
14
18
|
* @param simpleTable - The table whose chain owns the asynchronous work.
|
|
15
19
|
* @param operation - The asynchronous extension operation to queue.
|
|
16
20
|
* @param operation.method - The public method name used for diagnostics.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queueOp.d.ts","sourceRoot":"","sources":["../../src/helpers/queueOp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,sBAAsB,CAAC;AACjD,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"queueOp.d.ts","sourceRoot":"","sources":["../../src/helpers/queueOp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,sBAAsB,CAAC;AACjD,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAWtD;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,OAAO,CAC7B,WAAW,EAAE,WAAW,EACxB,EAAE,EAAE,cAAc,GACjB,IAAI,CAgDN;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,QAAQ,GACZ;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,EAAE,CAa7C"}
|
package/esm/helpers/queueOp.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ensureTableRegistered, getRegisteredTables } from "./tableRegistry.js";
|
|
2
2
|
import { markTableChanged } from "./tableGeneration.js";
|
|
3
|
-
import { recordCacheTableReferences } from "./cacheTableDependencies.js";
|
|
3
|
+
import { assertCacheTableMutation, captureCacheTableOperation, recordCacheTableOperation, recordCacheTableReferences, } from "./cacheTableDependencies.js";
|
|
4
4
|
import { captureAsyncOperation } from "./asyncOperationContext.js";
|
|
5
5
|
/**
|
|
6
6
|
* Queues an internal relational operation, barrier, or asynchronous barrier.
|
|
@@ -8,14 +8,15 @@ import { captureAsyncOperation } from "./asyncOperationContext.js";
|
|
|
8
8
|
* @internal
|
|
9
9
|
*/
|
|
10
10
|
export default function queueOp(simpleTable, op) {
|
|
11
|
+
assertCacheTableMutation(simpleTable);
|
|
11
12
|
const sdb = simpleTable.sdb;
|
|
12
13
|
if (sdb.lifecycleState !== "open") {
|
|
13
14
|
throw new Error(`${op.method} cannot queue work because its SimpleDB is ${sdb.lifecycleState}.`);
|
|
14
15
|
}
|
|
15
|
-
let capturedOp = {
|
|
16
|
+
let capturedOp = captureCacheTableOperation({
|
|
16
17
|
...op,
|
|
17
18
|
parameters: op.parameters === null ? null : structuredClone(op.parameters),
|
|
18
|
-
};
|
|
19
|
+
});
|
|
19
20
|
if (capturedOp.kind === "fusable" || capturedOp.kind === "source") {
|
|
20
21
|
capturedOp = {
|
|
21
22
|
...capturedOp,
|
|
@@ -44,6 +45,7 @@ export default function queueOp(simpleTable, op) {
|
|
|
44
45
|
...capturedOp,
|
|
45
46
|
sequence: sdb.opSequence++,
|
|
46
47
|
};
|
|
48
|
+
recordCacheTableOperation(simpleTable, queuedOp);
|
|
47
49
|
if (captureAsyncOperation(sdb, { table: simpleTable, op: queuedOp })) {
|
|
48
50
|
return;
|
|
49
51
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type DuckDBConnection, type DuckDBType, type DuckDBValue } from "@duckdb/node-api";
|
|
2
|
+
/** Reads mutation values, optionally keeping a pagination cursor out of rows. */
|
|
3
|
+
export default function readMutationRows(connection: DuckDBConnection, query: string, cursorColumn?: string): Promise<{
|
|
4
|
+
rows: Record<string, unknown>[];
|
|
5
|
+
types: Map<string, DuckDBType>;
|
|
6
|
+
lastCursorValue: DuckDBValue | undefined;
|
|
7
|
+
toNative: (value: unknown, type: DuckDBType) => DuckDBValue;
|
|
8
|
+
}>;
|
|
9
|
+
//# sourceMappingURL=readMutationRows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readMutationRows.d.ts","sourceRoot":"","sources":["../../src/helpers/readMutationRows.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EAKrB,KAAK,UAAU,EACf,KAAK,WAAW,EACjB,MAAM,kBAAkB,CAAC;AAE1B,iFAAiF;AACjF,wBAA8B,gBAAgB,CAC5C,UAAU,EAAE,gBAAgB,EAC5B,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,MAAM;;;;sBAwDI,OAAO,QAAQ,UAAU,KAAG,WAAW;GA0DjE"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { DuckDBArrayValue, DuckDBDateValue, DuckDBListValue, DuckDBStructValue, DuckDBTimestampValue, } from "@duckdb/node-api";
|
|
2
|
+
/** Reads mutation values, optionally keeping a pagination cursor out of rows. */
|
|
3
|
+
export default async function readMutationRows(connection, query, cursorColumn) {
|
|
4
|
+
const result = await connection.run(query);
|
|
5
|
+
const names = result.deduplicatedColumnNames();
|
|
6
|
+
const types = result.columnTypes();
|
|
7
|
+
const cursorIndex = cursorColumn === undefined
|
|
8
|
+
? -1
|
|
9
|
+
: names.indexOf(cursorColumn);
|
|
10
|
+
let lastCursorValue;
|
|
11
|
+
const dates = new WeakMap();
|
|
12
|
+
const convert = (value) => {
|
|
13
|
+
if (value instanceof DuckDBDateValue || value instanceof DuckDBTimestampValue) {
|
|
14
|
+
const millis = value instanceof DuckDBDateValue
|
|
15
|
+
? value.days * 86400000
|
|
16
|
+
: Number(value.micros >= 0n
|
|
17
|
+
? value.micros / 1000n
|
|
18
|
+
: (value.micros - 999n) / 1000n);
|
|
19
|
+
const date = new Date(millis);
|
|
20
|
+
// Infinite/out-of-range dates retain their native representation.
|
|
21
|
+
if (!Number.isFinite(date.getTime()))
|
|
22
|
+
return value;
|
|
23
|
+
dates.set(date, { millis, value });
|
|
24
|
+
return date;
|
|
25
|
+
}
|
|
26
|
+
if (value instanceof DuckDBArrayValue || value instanceof DuckDBListValue) {
|
|
27
|
+
return value.items.map(convert);
|
|
28
|
+
}
|
|
29
|
+
if (value instanceof DuckDBStructValue) {
|
|
30
|
+
return Object.fromEntries(Object.entries(value.entries).map(([key, item]) => [key, convert(item)]));
|
|
31
|
+
}
|
|
32
|
+
// In particular, decimals and high-resolution temporal values stay native.
|
|
33
|
+
return value;
|
|
34
|
+
};
|
|
35
|
+
const rows = [];
|
|
36
|
+
while (true) {
|
|
37
|
+
const chunk = await result.fetchChunk();
|
|
38
|
+
if (!chunk || chunk.rowCount === 0)
|
|
39
|
+
break;
|
|
40
|
+
const offset = rows.length;
|
|
41
|
+
for (let i = 0; i < chunk.rowCount; i++)
|
|
42
|
+
rows.push({});
|
|
43
|
+
for (let i = 0; i < names.length; i++) {
|
|
44
|
+
if (i === cursorIndex) {
|
|
45
|
+
lastCursorValue = chunk.getColumnVector(i).getItem(chunk.rowCount - 1);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
chunk.visitColumnValues(i, (value, row) => {
|
|
49
|
+
rows[offset + row][names[i]] = convert(value);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const toNative = (value, type) => {
|
|
54
|
+
if (value === null || value === undefined)
|
|
55
|
+
return null;
|
|
56
|
+
if (value instanceof Date) {
|
|
57
|
+
const original = dates.get(value);
|
|
58
|
+
if (original && value.getTime() === original.millis &&
|
|
59
|
+
type.toString() ===
|
|
60
|
+
(original.value instanceof DuckDBDateValue ? "DATE" : "TIMESTAMP")) {
|
|
61
|
+
return original.value;
|
|
62
|
+
}
|
|
63
|
+
if (type.toString() === "DATE") {
|
|
64
|
+
if (value.getTime() % 86400000 !== 0) {
|
|
65
|
+
throw new Error("DATE values must represent midnight UTC.");
|
|
66
|
+
}
|
|
67
|
+
return new DuckDBDateValue(value.getTime() / 86400000);
|
|
68
|
+
}
|
|
69
|
+
return new DuckDBTimestampValue(BigInt(value.getTime()) * 1000n);
|
|
70
|
+
}
|
|
71
|
+
if (Array.isArray(value) && "valueType" in type) {
|
|
72
|
+
if ("length" in type && value.length !== type.length) {
|
|
73
|
+
throw new Error(`Expected ${type.length} array elements for ${type}.`);
|
|
74
|
+
}
|
|
75
|
+
const items = value.map((item) => toNative(item, type.valueType));
|
|
76
|
+
return "length" in type
|
|
77
|
+
? new DuckDBArrayValue(items)
|
|
78
|
+
: new DuckDBListValue(items);
|
|
79
|
+
}
|
|
80
|
+
if (typeof value === "object" && "entryNames" in type && "entryTypes" in type) {
|
|
81
|
+
return new DuckDBStructValue(Object.fromEntries(type.entryNames.map((name, i) => [
|
|
82
|
+
name,
|
|
83
|
+
toNative(value[name], type.entryTypes[i]),
|
|
84
|
+
])));
|
|
85
|
+
}
|
|
86
|
+
return value;
|
|
87
|
+
};
|
|
88
|
+
return {
|
|
89
|
+
rows,
|
|
90
|
+
types: new Map(names.flatMap((name, i) => i === cursorIndex ? [] : [[name, types[i]]])),
|
|
91
|
+
lastCursorValue,
|
|
92
|
+
toNative,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type SimpleDB from "../class/SimpleDB.js";
|
|
2
|
+
import type SimpleTable from "../class/SimpleTable.js";
|
|
3
|
+
/**
|
|
4
|
+
* Finds registered table identifiers in SQL, excluding literals and comments.
|
|
5
|
+
* Matching is conservative: column names and aliases also count as references.
|
|
6
|
+
* DuckDB folds ASCII letters in both quoted and unquoted identifiers.
|
|
7
|
+
*/
|
|
8
|
+
export default function referencedTables(sql: readonly string[], sdb: SimpleDB): SimpleTable[];
|
|
9
|
+
//# sourceMappingURL=referencedTables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"referencedTables.d.ts","sourceRoot":"","sources":["../../src/helpers/referencedTables.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,sBAAsB,CAAC;AACjD,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAKvD;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CACtC,GAAG,EAAE,SAAS,MAAM,EAAE,EACtB,GAAG,EAAE,QAAQ,GACZ,WAAW,EAAE,CAkBf"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import scanSQL from "./scanSQL.js";
|
|
2
|
+
import foldIdentifier from "./foldIdentifier.js";
|
|
3
|
+
import { getRegisteredTables } from "./tableRegistry.js";
|
|
4
|
+
/**
|
|
5
|
+
* Finds registered table identifiers in SQL, excluding literals and comments.
|
|
6
|
+
* Matching is conservative: column names and aliases also count as references.
|
|
7
|
+
* DuckDB folds ASCII letters in both quoted and unquoted identifiers.
|
|
8
|
+
*/
|
|
9
|
+
export default function referencedTables(sql, sdb) {
|
|
10
|
+
const identifiers = new Set();
|
|
11
|
+
for (const fragment of sql) {
|
|
12
|
+
for (const token of scanSQL(fragment)) {
|
|
13
|
+
if (token.kind === "quoted" && token.text.startsWith('"')) {
|
|
14
|
+
identifiers.add(foldIdentifier(token.text.slice(1, -1).replaceAll('""', '"')));
|
|
15
|
+
}
|
|
16
|
+
else if (token.kind === "sql" && /^[\p{L}_][\p{L}\p{N}_$]*$/u.test(token.text)) {
|
|
17
|
+
identifiers.add(foldIdentifier(token.text));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return getRegisteredTables(sdb).filter((table) => identifiers.has(foldIdentifier(table.name)));
|
|
22
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runQuery.d.ts","sourceRoot":"","sources":["../../src/helpers/runQuery.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runQuery.d.ts","sourceRoot":"","sources":["../../src/helpers/runQuery.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,gBAAgB,EAIrB,KAAK,UAAU,EAEf,KAAK,WAAW,EAIjB,MAAM,kBAAkB,CAAC;AAI1B,KAAK,eAAe,GAAG;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IAC9C,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AA8CF,wBAAgB,aAAa,CAC3B,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,MAAM,GAAG,IAAW,GAC9B,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAoCjC;AAED,wBAA8B,QAAQ,CACpC,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,gBAAgB,EAC5B,UAAU,EAAE,OAAO,EACnB,OAAO,EAAE,eAAe,GACvB,OAAO,CACN;IACA,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,EAAE,GACD,IAAI,CACP,CAoEA"}
|
package/esm/helpers/runQuery.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import makeLogConverter from "./makeLogConverter.js";
|
|
1
2
|
import quoteIdentifier from "./quoteIdentifier.js";
|
|
2
3
|
import { DuckDBTimestampValue, DuckDBTypeId, JsonDuckDBValueConverter, } from "@duckdb/node-api";
|
|
3
4
|
import SDAError from "../class/SDAError.js";
|
|
@@ -5,20 +6,14 @@ import observeQuery from "./observeQuery.js";
|
|
|
5
6
|
const msPerDay = 24 * 60 * 60 * 1000;
|
|
6
7
|
const maxSafeInteger = BigInt(Number.MAX_SAFE_INTEGER);
|
|
7
8
|
const minSafeInteger = BigInt(Number.MIN_SAFE_INTEGER);
|
|
8
|
-
// Columns already warned about for precision loss (keyed by table and
|
|
9
|
-
// column), so each column warns only once.
|
|
10
|
-
const warnedUnsafeIntegerColumns = new Set();
|
|
11
9
|
function makeIntegerConverter(columnName, tableName) {
|
|
12
|
-
const warnKey = `${tableName ?? ""}\0${columnName}`;
|
|
13
10
|
return (value) => {
|
|
14
11
|
if (value === null) {
|
|
15
12
|
return null;
|
|
16
13
|
}
|
|
17
14
|
const bigintValue = value;
|
|
18
|
-
if (
|
|
19
|
-
|
|
20
|
-
warnedUnsafeIntegerColumns.add(warnKey);
|
|
21
|
-
console.warn(`SDA: Column ${quoteIdentifier(columnName)}${tableName === null ? "" : ` of table ${quoteIdentifier(tableName)}`} has at least one value exceeding Number.MAX_SAFE_INTEGER. Converted numbers may lose precision.`);
|
|
15
|
+
if (bigintValue > maxSafeInteger || bigintValue < minSafeInteger) {
|
|
16
|
+
throw new RangeError(`SDA: Column ${quoteIdentifier(columnName)}${tableName === null ? "" : ` of table ${quoteIdentifier(tableName)}`} contains ${bigintValue} outside JavaScript's safe integer range (Number.MIN_SAFE_INTEGER to Number.MAX_SAFE_INTEGER). Cast the column to VARCHAR to retrieve exact digits.`);
|
|
22
17
|
}
|
|
23
18
|
return Number(bigintValue);
|
|
24
19
|
};
|
|
@@ -41,10 +36,6 @@ export function makeConverter(type, columnName, tableName = null) {
|
|
|
41
36
|
const placeholder = `GEOM(${typeString.replace("GEOMETRY('", "").replace("')", "")})`;
|
|
42
37
|
return (value) => (value === null ? null : placeholder);
|
|
43
38
|
}
|
|
44
|
-
if (typeString.includes("FLOAT[")) {
|
|
45
|
-
const placeholder = `<${typeString}>`;
|
|
46
|
-
return (value) => (value === null ? null : placeholder);
|
|
47
|
-
}
|
|
48
39
|
switch (type.typeId) {
|
|
49
40
|
case DuckDBTypeId.DATE:
|
|
50
41
|
return (value) => value === null
|
|
@@ -65,6 +56,8 @@ export function makeConverter(type, columnName, tableName = null) {
|
|
|
65
56
|
return utcTimestampTzValue;
|
|
66
57
|
case DuckDBTypeId.BIGINT:
|
|
67
58
|
case DuckDBTypeId.HUGEINT:
|
|
59
|
+
case DuckDBTypeId.UBIGINT:
|
|
60
|
+
case DuckDBTypeId.UHUGEINT:
|
|
68
61
|
return makeIntegerConverter(columnName, tableName);
|
|
69
62
|
default:
|
|
70
63
|
return (value) => utcJsonValueConverter(value, type, utcJsonValueConverter);
|
|
@@ -84,7 +77,12 @@ export default async function runQuery(query, connection, returnData, options) {
|
|
|
84
77
|
columnTypes.some((type) => type.toString().toLowerCase().includes("geometry"))) {
|
|
85
78
|
throw new Error("The query returns geometry columns. Use getGeoData() instead.");
|
|
86
79
|
}
|
|
87
|
-
const
|
|
80
|
+
const logging = options.method === "log()" ||
|
|
81
|
+
options.method === "logBottom()";
|
|
82
|
+
const converters = columnTypes.map((type, i) => {
|
|
83
|
+
const converter = makeConverter(type, columnNames[i], options.table ?? null);
|
|
84
|
+
return logging ? makeLogConverter(type, converter) : converter;
|
|
85
|
+
});
|
|
88
86
|
const columnCount = columnNames.length;
|
|
89
87
|
// The result is converted chunk by chunk, so no intermediate row-major
|
|
90
88
|
// copy of the whole result is materialized.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanSQL.d.ts","sourceRoot":"","sources":["../../src/helpers/scanSQL.ts"],"names":[],"mappings":"AAAA,KAAK,KAAK,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAA;CAAE,CAAC;AAIjE,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE,CA0DtD"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Keep opaque SQL regions byte-for-byte intact. Only SQL tokens participate in
|
|
2
|
+
// normalization; parameter values never enter this module.
|
|
3
|
+
export default function scanSQL(query) {
|
|
4
|
+
const tokens = [];
|
|
5
|
+
let i = 0;
|
|
6
|
+
while (i < query.length) {
|
|
7
|
+
const start = i;
|
|
8
|
+
let kind = "sql";
|
|
9
|
+
const rest = query.slice(i);
|
|
10
|
+
if (/\s/.test(query[i])) {
|
|
11
|
+
kind = "trivia";
|
|
12
|
+
while (i < query.length && /\s/.test(query[i]))
|
|
13
|
+
i++;
|
|
14
|
+
}
|
|
15
|
+
else if (rest.startsWith("--")) {
|
|
16
|
+
kind = "trivia";
|
|
17
|
+
while (i < query.length && !/[\r\n]/.test(query[i]))
|
|
18
|
+
i++;
|
|
19
|
+
}
|
|
20
|
+
else if (rest.startsWith("/*")) {
|
|
21
|
+
kind = "trivia";
|
|
22
|
+
i += 2;
|
|
23
|
+
let depth = 1;
|
|
24
|
+
while (i < query.length && depth > 0) {
|
|
25
|
+
if (query.startsWith("/*", i)) {
|
|
26
|
+
depth++;
|
|
27
|
+
i += 2;
|
|
28
|
+
}
|
|
29
|
+
else if (query.startsWith("*/", i)) {
|
|
30
|
+
depth--;
|
|
31
|
+
i += 2;
|
|
32
|
+
}
|
|
33
|
+
else
|
|
34
|
+
i++;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else if (/^[eE]'/.test(rest) || query[i] === "'" || query[i] === '"') {
|
|
38
|
+
kind = "quoted";
|
|
39
|
+
const escaped = /^[eE]'/.test(rest);
|
|
40
|
+
if (escaped)
|
|
41
|
+
i++;
|
|
42
|
+
const quote = query[i++];
|
|
43
|
+
while (i < query.length) {
|
|
44
|
+
if (escaped && query[i] === "\\")
|
|
45
|
+
i = Math.min(i + 2, query.length);
|
|
46
|
+
else if (query[i++] === quote) {
|
|
47
|
+
if (query[i] === quote)
|
|
48
|
+
i++;
|
|
49
|
+
else
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
// DuckDB permits non-ASCII characters in dollar tags, including
|
|
56
|
+
// combining marks and characters outside the Unicode letter categories.
|
|
57
|
+
const dollar = rest.match(/^\$(?:[A-Za-z_\u0080-\uFFFF][A-Za-z_0-9\u0080-\uFFFF]*)?\$/)?.[0];
|
|
58
|
+
if (dollar) {
|
|
59
|
+
kind = "quoted";
|
|
60
|
+
const end = query.indexOf(dollar, i + dollar.length);
|
|
61
|
+
i = end === -1 ? query.length : end + dollar.length;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
const token = rest.match(/^(?:[\p{L}_][\p{L}\p{N}_$]*|\$(?:[0-9]+|[\p{L}_][\p{L}\p{N}_]*)|!==|===|==|!=|<>|<=|>=|&&|\|\||::)/u)?.[0];
|
|
65
|
+
i += token?.length ?? 1;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
tokens.push({ text: query.slice(start, i), kind });
|
|
69
|
+
}
|
|
70
|
+
return tokens;
|
|
71
|
+
}
|
|
@@ -5,5 +5,7 @@ export declare function getRegisteredTables<Table extends SimpleTable>(simpleDB:
|
|
|
5
5
|
export declare function listRegisteredTables<Table extends SimpleTable>(simpleDB: SimpleDB<Table>): readonly Table[];
|
|
6
6
|
export declare function registerTable<Table extends SimpleTable>(simpleDB: SimpleDB<Table>, table: Table): void;
|
|
7
7
|
export declare function ensureTableRegistered<Table extends SimpleTable>(simpleDB: SimpleDB<Table>, table: Table): void;
|
|
8
|
+
/** Prevents distinct handles from owning the same DuckDB table name. */
|
|
9
|
+
export declare function assertTableNameAvailable(simpleDB: SimpleDB, name: string, renamedTable?: SimpleTable): void;
|
|
8
10
|
export declare function retainRegisteredTables<Table extends SimpleTable>(simpleDB: SimpleDB<Table>, predicate: (table: Table) => boolean): void;
|
|
9
11
|
//# sourceMappingURL=tableRegistry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tableRegistry.d.ts","sourceRoot":"","sources":["../../src/helpers/tableRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,sBAAsB,CAAC;AACjD,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"tableRegistry.d.ts","sourceRoot":"","sources":["../../src/helpers/tableRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,sBAAsB,CAAC;AACjD,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAiBvD,wBAAgB,uBAAuB,CAAC,KAAK,SAAS,WAAW,EAC/D,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,GACxB,IAAI,CAEN;AAED,wBAAgB,mBAAmB,CAAC,KAAK,SAAS,WAAW,EAC3D,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,GACxB,SAAS,KAAK,EAAE,CAElB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,SAAS,WAAW,EAC5D,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,GACxB,SAAS,KAAK,EAAE,CAElB;AAED,wBAAgB,aAAa,CAAC,KAAK,SAAS,WAAW,EACrD,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,EACzB,KAAK,EAAE,KAAK,GACX,IAAI,CAYN;AAED,wBAAgB,qBAAqB,CAAC,KAAK,SAAS,WAAW,EAC7D,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,EACzB,KAAK,EAAE,KAAK,GACX,IAAI,CAKN;AAED,wEAAwE;AACxE,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,YAAY,CAAC,EAAE,WAAW,GACzB,IAAI,CASN;AAED,wBAAgB,sBAAsB,CAAC,KAAK,SAAS,WAAW,EAC9D,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,EACzB,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,GACnC,IAAI,CAUN"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { markTableChanged } from "./tableGeneration.js";
|
|
2
|
+
import { recordCacheTableCreation } from "./cacheTableDependencies.js";
|
|
3
|
+
import foldIdentifier from "./foldIdentifier.js";
|
|
2
4
|
const registries = new WeakMap();
|
|
3
5
|
function getMutableTables(simpleDB) {
|
|
4
6
|
const tables = registries.get(simpleDB);
|
|
@@ -22,15 +24,21 @@ export function registerTable(simpleDB, table) {
|
|
|
22
24
|
throw new Error(`The table must be an instance of ${TableClass.name}.`);
|
|
23
25
|
}
|
|
24
26
|
const tables = getMutableTables(simpleDB);
|
|
25
|
-
|
|
26
|
-
throw new Error(`Table ${table.name} already exists.`);
|
|
27
|
-
}
|
|
27
|
+
assertTableNameAvailable(simpleDB, table.name);
|
|
28
28
|
tables.push(table);
|
|
29
|
+
recordCacheTableCreation(table);
|
|
29
30
|
}
|
|
30
31
|
export function ensureTableRegistered(simpleDB, table) {
|
|
31
32
|
const tables = getMutableTables(simpleDB);
|
|
32
33
|
if (!tables.includes(table)) {
|
|
33
|
-
|
|
34
|
+
registerTable(simpleDB, table);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** Prevents distinct handles from owning the same DuckDB table name. */
|
|
38
|
+
export function assertTableNameAvailable(simpleDB, name, renamedTable) {
|
|
39
|
+
const normalizedName = foldIdentifier(name);
|
|
40
|
+
if (getRegisteredTables(simpleDB).some((table) => table !== renamedTable && foldIdentifier(table.name) === normalizedName)) {
|
|
41
|
+
throw new Error(`Table ${name} already exists.`);
|
|
34
42
|
}
|
|
35
43
|
}
|
|
36
44
|
export function retainRegisteredTables(simpleDB, predicate) {
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type SimpleTable from "../class/SimpleTable.js";
|
|
2
|
+
/**
|
|
3
|
+
* Generates columns from selected input columns, keeping other SQL values in
|
|
4
|
+
* DuckDB. Call from an asynchronous extension barrier. The callback must return
|
|
5
|
+
* one row per input row in the same order; only the declared output columns are
|
|
6
|
+
* stored. Existing output columns are replaced, with types inferred from the
|
|
7
|
+
* generated values. Generation runs sequentially in bounded batches (1,000 rows
|
|
8
|
+
* by default); callbacks must not depend on receiving the whole table. Non-null
|
|
9
|
+
* output types must agree across batches. All-null batches defer type inference.
|
|
10
|
+
* Only one batch of inputs and outputs is retained by this helper in JavaScript;
|
|
11
|
+
* callers must also bound their own buffering. Reads finish before callbacks or
|
|
12
|
+
* writes use the shared connection. The original table is replaced only after
|
|
13
|
+
* staging succeeds. Empty tables are unchanged and do not invoke the callback;
|
|
14
|
+
* outputs that remain null in every batch use VARCHAR.
|
|
15
|
+
*
|
|
16
|
+
* Untouched geometry columns remain in DuckDB, preserving their values, types
|
|
17
|
+
* and CRS without GeoJSON conversion. Geometry columns cannot be selected as
|
|
18
|
+
* inputs or overwritten as outputs; use updateWithJS() for editable GeoJSON.
|
|
19
|
+
* This SQL-only preservation path accepts any source CRS.
|
|
20
|
+
*
|
|
21
|
+
* @param table - Table to enrich.
|
|
22
|
+
* @param inputColumns - Columns available to the callback.
|
|
23
|
+
* @param outputColumns - Generated columns to add or replace.
|
|
24
|
+
* @param generate - Produces one result per input row, in input order.
|
|
25
|
+
* @param options - Controls the maximum rows read, generated, and staged at once.
|
|
26
|
+
* @returns Resolves after merging the generated columns into the table.
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* queueAsyncBarrier(table, {
|
|
30
|
+
* method: "label()",
|
|
31
|
+
* parameters: null,
|
|
32
|
+
* execute: () => updateColumnsWithJS(table, ["name"], ["label"], async (rows) =>
|
|
33
|
+
* rows.map((row) => ({ label: String(row.name).toUpperCase() })),
|
|
34
|
+
* { batchSize: 500 }),
|
|
35
|
+
* });
|
|
36
|
+
* await table.log();
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export default function updateColumnsWithJS(table: SimpleTable, inputColumns: string[], outputColumns: string[], generate: (rows: {
|
|
40
|
+
[key: string]: unknown;
|
|
41
|
+
}[]) => Promise<{
|
|
42
|
+
[key: string]: unknown;
|
|
43
|
+
}[]>, options?: {
|
|
44
|
+
/** Maximum rows per callback and transfer batch. Defaults to 1,000.
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* { batchSize: 500 }
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
batchSize?: number;
|
|
51
|
+
}): Promise<void>;
|
|
52
|
+
//# sourceMappingURL=updateColumnsWithJS.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updateColumnsWithJS.d.ts","sourceRoot":"","sources":["../../src/helpers/updateColumnsWithJS.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAMvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAA8B,mBAAmB,CAC/C,KAAK,EAAE,WAAW,EAClB,YAAY,EAAE,MAAM,EAAE,EACtB,aAAa,EAAE,MAAM,EAAE,EACvB,QAAQ,EAAE,CACR,IAAI,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,EAAE,KAC/B,OAAO,CAAC;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,EAAE,CAAC,EAC1C,OAAO,GAAE;IACP;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACf,GACL,OAAO,CAAC,IAAI,CAAC,CAoJf"}
|