@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.
Files changed (244) hide show
  1. package/README.md +118 -12
  2. package/esm/class/Simple.d.ts +8 -2
  3. package/esm/class/Simple.d.ts.map +1 -1
  4. package/esm/class/Simple.js +9 -3
  5. package/esm/class/SimpleDB.d.ts +72 -1
  6. package/esm/class/SimpleDB.d.ts.map +1 -1
  7. package/esm/class/SimpleDB.js +81 -1
  8. package/esm/class/SimpleTable.d.ts +271 -288
  9. package/esm/class/SimpleTable.d.ts.map +1 -1
  10. package/esm/class/SimpleTable.js +269 -340
  11. package/esm/helpers/LogValue.d.ts +8 -0
  12. package/esm/helpers/LogValue.d.ts.map +1 -0
  13. package/esm/helpers/LogValue.js +23 -0
  14. package/esm/helpers/cacheTableDependencies.d.ts +9 -0
  15. package/esm/helpers/cacheTableDependencies.d.ts.map +1 -1
  16. package/esm/helpers/cacheTableDependencies.js +131 -21
  17. package/esm/helpers/cleanSQL.d.ts +1 -1
  18. package/esm/helpers/cleanSQL.d.ts.map +1 -1
  19. package/esm/helpers/cleanSQL.js +268 -23
  20. package/esm/helpers/flushAllTables.d.ts.map +1 -1
  21. package/esm/helpers/flushAllTables.js +23 -28
  22. package/esm/helpers/foldIdentifier.d.ts +3 -0
  23. package/esm/helpers/foldIdentifier.d.ts.map +1 -0
  24. package/esm/helpers/foldIdentifier.js +4 -0
  25. package/esm/helpers/geometryFromJSON.d.ts +3 -0
  26. package/esm/helpers/geometryFromJSON.d.ts.map +1 -0
  27. package/esm/helpers/geometryFromJSON.js +4 -0
  28. package/esm/helpers/index.d.ts +1 -0
  29. package/esm/helpers/index.d.ts.map +1 -1
  30. package/esm/helpers/index.js +1 -0
  31. package/esm/helpers/logData.d.ts.map +1 -1
  32. package/esm/helpers/logData.js +45 -44
  33. package/esm/helpers/makeLogConverter.d.ts +5 -0
  34. package/esm/helpers/makeLogConverter.d.ts.map +1 -0
  35. package/esm/helpers/makeLogConverter.js +64 -0
  36. package/esm/helpers/osmFiles.d.ts.map +1 -1
  37. package/esm/helpers/parseTypes.d.ts +1 -1
  38. package/esm/helpers/parseTypes.d.ts.map +1 -1
  39. package/esm/helpers/parseTypes.js +4 -0
  40. package/esm/helpers/pendingOps.d.ts +4 -2
  41. package/esm/helpers/pendingOps.d.ts.map +1 -1
  42. package/esm/helpers/prepareGeometry.d.ts +3 -0
  43. package/esm/helpers/prepareGeometry.d.ts.map +1 -0
  44. package/esm/helpers/prepareGeometry.js +99 -0
  45. package/esm/helpers/prepareJSON.d.ts +3 -0
  46. package/esm/helpers/prepareJSON.d.ts.map +1 -0
  47. package/esm/helpers/prepareJSON.js +50 -0
  48. package/esm/helpers/printTable.d.ts +5 -4
  49. package/esm/helpers/printTable.d.ts.map +1 -1
  50. package/esm/helpers/printTable.js +32 -36
  51. package/esm/helpers/queryDB.js +1 -1
  52. package/esm/helpers/queueAsyncBarrier.d.ts +4 -0
  53. package/esm/helpers/queueAsyncBarrier.d.ts.map +1 -1
  54. package/esm/helpers/queueAsyncBarrier.js +4 -0
  55. package/esm/helpers/queueOp.d.ts.map +1 -1
  56. package/esm/helpers/queueOp.js +5 -3
  57. package/esm/helpers/readMutationRows.d.ts +9 -0
  58. package/esm/helpers/readMutationRows.d.ts.map +1 -0
  59. package/esm/helpers/readMutationRows.js +94 -0
  60. package/esm/helpers/referencedTables.d.ts +9 -0
  61. package/esm/helpers/referencedTables.d.ts.map +1 -0
  62. package/esm/helpers/referencedTables.js +22 -0
  63. package/esm/helpers/runQuery.d.ts.map +1 -1
  64. package/esm/helpers/runQuery.js +11 -13
  65. package/esm/helpers/scanSQL.d.ts +7 -0
  66. package/esm/helpers/scanSQL.d.ts.map +1 -0
  67. package/esm/helpers/scanSQL.js +71 -0
  68. package/esm/helpers/tableRegistry.d.ts +2 -0
  69. package/esm/helpers/tableRegistry.d.ts.map +1 -1
  70. package/esm/helpers/tableRegistry.js +12 -4
  71. package/esm/helpers/updateColumnsWithJS.d.ts +52 -0
  72. package/esm/helpers/updateColumnsWithJS.d.ts.map +1 -0
  73. package/esm/helpers/updateColumnsWithJS.js +139 -0
  74. package/esm/methods/addColumn.d.ts +1 -1
  75. package/esm/methods/addColumn.d.ts.map +1 -1
  76. package/esm/methods/bins.d.ts +1 -1
  77. package/esm/methods/bins.d.ts.map +1 -1
  78. package/esm/methods/bins.js +45 -29
  79. package/esm/methods/bm25.d.ts.map +1 -1
  80. package/esm/methods/bm25.js +1 -2
  81. package/esm/methods/cache.d.ts.map +1 -1
  82. package/esm/methods/cache.js +4 -6
  83. package/esm/methods/convert.d.ts +2 -2
  84. package/esm/methods/convert.d.ts.map +1 -1
  85. package/esm/methods/convert.js +5 -0
  86. package/esm/methods/getBottom.d.ts +1 -1
  87. package/esm/methods/getBottom.d.ts.map +1 -1
  88. package/esm/methods/getBottom.js +2 -2
  89. package/esm/methods/getData.d.ts +1 -1
  90. package/esm/methods/getData.d.ts.map +1 -1
  91. package/esm/methods/getData.js +2 -2
  92. package/esm/methods/join.d.ts.map +1 -1
  93. package/esm/methods/join.js +8 -16
  94. package/esm/methods/joinGeo.d.ts.map +1 -1
  95. package/esm/methods/joinGeo.js +10 -19
  96. package/esm/methods/loadArray.d.ts +1 -1
  97. package/esm/methods/loadArray.d.ts.map +1 -1
  98. package/esm/methods/loadArray.js +74 -19
  99. package/esm/methods/loadData.js +3 -0
  100. package/esm/methods/log.d.ts +7 -0
  101. package/esm/methods/log.d.ts.map +1 -0
  102. package/esm/methods/log.js +63 -0
  103. package/esm/methods/logBottom.d.ts +5 -0
  104. package/esm/methods/logBottom.d.ts.map +1 -0
  105. package/esm/methods/logBottom.js +9 -0
  106. package/esm/methods/removeTable.d.ts.map +1 -1
  107. package/esm/methods/removeTable.js +2 -0
  108. package/esm/methods/removeTables.d.ts.map +1 -1
  109. package/esm/methods/removeTables.js +7 -0
  110. package/esm/methods/renameTable.d.ts.map +1 -1
  111. package/esm/methods/renameTable.js +4 -0
  112. package/esm/methods/rowToText.js +2 -2
  113. package/esm/methods/selectTables.d.ts.map +1 -1
  114. package/esm/methods/selectTables.js +6 -0
  115. package/esm/methods/setTypes.d.ts +1 -1
  116. package/esm/methods/setTypes.d.ts.map +1 -1
  117. package/esm/methods/stream.d.ts.map +1 -1
  118. package/esm/methods/stream.js +2 -1
  119. package/esm/methods/updateWithJS.d.ts +1 -3
  120. package/esm/methods/updateWithJS.d.ts.map +1 -1
  121. package/esm/methods/updateWithJS.js +123 -37
  122. package/llm.md +365 -461
  123. package/llms.txt +1 -1
  124. package/package.json +1 -1
  125. package/script/class/Simple.d.ts +8 -2
  126. package/script/class/Simple.d.ts.map +1 -1
  127. package/script/class/Simple.js +9 -3
  128. package/script/class/SimpleDB.d.ts +72 -1
  129. package/script/class/SimpleDB.d.ts.map +1 -1
  130. package/script/class/SimpleDB.js +81 -1
  131. package/script/class/SimpleTable.d.ts +271 -288
  132. package/script/class/SimpleTable.d.ts.map +1 -1
  133. package/script/class/SimpleTable.js +269 -340
  134. package/script/helpers/LogValue.d.ts +8 -0
  135. package/script/helpers/LogValue.d.ts.map +1 -0
  136. package/script/helpers/LogValue.js +26 -0
  137. package/script/helpers/cacheTableDependencies.d.ts +9 -0
  138. package/script/helpers/cacheTableDependencies.d.ts.map +1 -1
  139. package/script/helpers/cacheTableDependencies.js +170 -20
  140. package/script/helpers/cleanSQL.d.ts +1 -1
  141. package/script/helpers/cleanSQL.d.ts.map +1 -1
  142. package/script/helpers/cleanSQL.js +271 -23
  143. package/script/helpers/flushAllTables.d.ts.map +1 -1
  144. package/script/helpers/flushAllTables.js +24 -29
  145. package/script/helpers/foldIdentifier.d.ts +3 -0
  146. package/script/helpers/foldIdentifier.d.ts.map +1 -0
  147. package/script/helpers/foldIdentifier.js +7 -0
  148. package/script/helpers/geometryFromJSON.d.ts +3 -0
  149. package/script/helpers/geometryFromJSON.d.ts.map +1 -0
  150. package/script/helpers/geometryFromJSON.js +7 -0
  151. package/script/helpers/index.d.ts +1 -0
  152. package/script/helpers/index.d.ts.map +1 -1
  153. package/script/helpers/index.js +3 -1
  154. package/script/helpers/logData.d.ts.map +1 -1
  155. package/script/helpers/logData.js +45 -44
  156. package/script/helpers/makeLogConverter.d.ts +5 -0
  157. package/script/helpers/makeLogConverter.d.ts.map +1 -0
  158. package/script/helpers/makeLogConverter.js +70 -0
  159. package/script/helpers/osmFiles.d.ts.map +1 -1
  160. package/script/helpers/parseTypes.d.ts +1 -1
  161. package/script/helpers/parseTypes.d.ts.map +1 -1
  162. package/script/helpers/parseTypes.js +4 -0
  163. package/script/helpers/pendingOps.d.ts +4 -2
  164. package/script/helpers/pendingOps.d.ts.map +1 -1
  165. package/script/helpers/prepareGeometry.d.ts +3 -0
  166. package/script/helpers/prepareGeometry.d.ts.map +1 -0
  167. package/script/helpers/prepareGeometry.js +102 -0
  168. package/script/helpers/prepareJSON.d.ts +3 -0
  169. package/script/helpers/prepareJSON.d.ts.map +1 -0
  170. package/script/helpers/prepareJSON.js +53 -0
  171. package/script/helpers/printTable.d.ts +5 -4
  172. package/script/helpers/printTable.d.ts.map +1 -1
  173. package/script/helpers/printTable.js +32 -36
  174. package/script/helpers/queryDB.js +1 -1
  175. package/script/helpers/queueAsyncBarrier.d.ts +4 -0
  176. package/script/helpers/queueAsyncBarrier.d.ts.map +1 -1
  177. package/script/helpers/queueAsyncBarrier.js +4 -0
  178. package/script/helpers/queueOp.d.ts.map +1 -1
  179. package/script/helpers/queueOp.js +4 -2
  180. package/script/helpers/readMutationRows.d.ts +9 -0
  181. package/script/helpers/readMutationRows.d.ts.map +1 -0
  182. package/script/helpers/readMutationRows.js +97 -0
  183. package/script/helpers/referencedTables.d.ts +9 -0
  184. package/script/helpers/referencedTables.d.ts.map +1 -0
  185. package/script/helpers/referencedTables.js +28 -0
  186. package/script/helpers/runQuery.d.ts.map +1 -1
  187. package/script/helpers/runQuery.js +11 -13
  188. package/script/helpers/scanSQL.d.ts +7 -0
  189. package/script/helpers/scanSQL.d.ts.map +1 -0
  190. package/script/helpers/scanSQL.js +74 -0
  191. package/script/helpers/tableRegistry.d.ts +2 -0
  192. package/script/helpers/tableRegistry.d.ts.map +1 -1
  193. package/script/helpers/tableRegistry.js +16 -4
  194. package/script/helpers/updateColumnsWithJS.d.ts +52 -0
  195. package/script/helpers/updateColumnsWithJS.d.ts.map +1 -0
  196. package/script/helpers/updateColumnsWithJS.js +145 -0
  197. package/script/methods/addColumn.d.ts +1 -1
  198. package/script/methods/addColumn.d.ts.map +1 -1
  199. package/script/methods/bins.d.ts +1 -1
  200. package/script/methods/bins.d.ts.map +1 -1
  201. package/script/methods/bins.js +45 -29
  202. package/script/methods/bm25.d.ts.map +1 -1
  203. package/script/methods/bm25.js +1 -2
  204. package/script/methods/cache.d.ts.map +1 -1
  205. package/script/methods/cache.js +3 -5
  206. package/script/methods/convert.d.ts +2 -2
  207. package/script/methods/convert.d.ts.map +1 -1
  208. package/script/methods/convert.js +5 -0
  209. package/script/methods/getBottom.d.ts +1 -1
  210. package/script/methods/getBottom.d.ts.map +1 -1
  211. package/script/methods/getBottom.js +2 -2
  212. package/script/methods/getData.d.ts +1 -1
  213. package/script/methods/getData.d.ts.map +1 -1
  214. package/script/methods/getData.js +2 -2
  215. package/script/methods/join.d.ts.map +1 -1
  216. package/script/methods/join.js +8 -16
  217. package/script/methods/joinGeo.d.ts.map +1 -1
  218. package/script/methods/joinGeo.js +10 -19
  219. package/script/methods/loadArray.d.ts +1 -1
  220. package/script/methods/loadArray.d.ts.map +1 -1
  221. package/script/methods/loadArray.js +74 -19
  222. package/script/methods/loadData.js +3 -0
  223. package/script/methods/log.d.ts +7 -0
  224. package/script/methods/log.d.ts.map +1 -0
  225. package/script/methods/log.js +69 -0
  226. package/script/methods/logBottom.d.ts +5 -0
  227. package/script/methods/logBottom.d.ts.map +1 -0
  228. package/script/methods/logBottom.js +15 -0
  229. package/script/methods/removeTable.d.ts.map +1 -1
  230. package/script/methods/removeTable.js +2 -0
  231. package/script/methods/removeTables.d.ts.map +1 -1
  232. package/script/methods/removeTables.js +7 -0
  233. package/script/methods/renameTable.d.ts.map +1 -1
  234. package/script/methods/renameTable.js +4 -0
  235. package/script/methods/rowToText.js +2 -2
  236. package/script/methods/selectTables.d.ts.map +1 -1
  237. package/script/methods/selectTables.js +6 -0
  238. package/script/methods/setTypes.d.ts +1 -1
  239. package/script/methods/setTypes.d.ts.map +1 -1
  240. package/script/methods/stream.d.ts.map +1 -1
  241. package/script/methods/stream.js +2 -1
  242. package/script/methods/updateWithJS.d.ts +1 -3
  243. package/script/methods/updateWithJS.d.ts.map +1 -1
  244. 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 handles
5
- * multi-line content within cells, making it ideal for displaying data with
6
- * long text values.
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`). Values exceeding this width will be wrapped at word boundaries.
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.toISOString();
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
- // Wrap pre-formatted strings into multi-line cells
94
- const wrappedData = [];
95
- for (let r = 0; r < formattedData.length; r++) {
96
- const wrappedRow = {};
97
- for (let c = 0; c < columns.length; c++) {
98
- const col = columns[c];
99
- const value = formattedData[r][c];
100
- const width = columnWidths[col];
101
- // Split by existing newlines, then wrap each part
102
- const lines = value.split("\n");
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 row (bold)
161
- const headerParts = columns.map((col) => ` ${colors.bold}${pad(col, columnWidths[col])}${colors.reset} `);
162
- console.log(colors.grey + "│" + colors.reset +
163
- headerParts.join(colors.grey + "│" + colors.reset) + colors.grey + "│" +
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) {
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;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"}
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;AAMtD;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,OAAO,CAC7B,WAAW,EAAE,WAAW,EACxB,EAAE,EAAE,cAAc,GACjB,IAAI,CA8CN;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"}
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"}
@@ -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":"AACA,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;AAqDF,wBAAgB,aAAa,CAC3B,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,MAAM,GAAG,IAAW,GAC9B,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAsCjC;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,CA6DA"}
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"}
@@ -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 ((bigintValue > maxSafeInteger || bigintValue < minSafeInteger) &&
19
- !warnedUnsafeIntegerColumns.has(warnKey)) {
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 converters = columnTypes.map((type, i) => makeConverter(type, columnNames[i], options.table ?? null));
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,7 @@
1
+ type Token = {
2
+ text: string;
3
+ kind: "sql" | "quoted" | "trivia";
4
+ };
5
+ export default function scanSQL(query: string): Token[];
6
+ export {};
7
+ //# sourceMappingURL=scanSQL.d.ts.map
@@ -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;AAevD,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,CAaN;AAED,wBAAgB,qBAAqB,CAAC,KAAK,SAAS,WAAW,EAC7D,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,EACzB,KAAK,EAAE,KAAK,GACX,IAAI,CAKN;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
+ {"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
- if (tables.some((registeredTable) => registeredTable.name === table.name)) {
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
- tables.push(table);
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"}