@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
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Internal display metadata; never returned by public data extraction. */
|
|
2
|
+
export default class LogValue {
|
|
3
|
+
readonly text: string;
|
|
4
|
+
readonly jsType: string;
|
|
5
|
+
readonly category: "number" | "string" | "date" | "boolean" | "null";
|
|
6
|
+
constructor(text: string, jsType: string, category: "number" | "string" | "date" | "boolean" | "null");
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=LogValue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LogValue.d.ts","sourceRoot":"","sources":["../../src/helpers/LogValue.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,MAAM,CAAC,OAAO,OAAO,QAAQ;IAEzB,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM;gBAF3D,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM;CAEvE"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Internal display metadata; never returned by public data extraction. */
|
|
2
|
+
export default class LogValue {
|
|
3
|
+
constructor(text, jsType, category) {
|
|
4
|
+
Object.defineProperty(this, "text", {
|
|
5
|
+
enumerable: true,
|
|
6
|
+
configurable: true,
|
|
7
|
+
writable: true,
|
|
8
|
+
value: text
|
|
9
|
+
});
|
|
10
|
+
Object.defineProperty(this, "jsType", {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
configurable: true,
|
|
13
|
+
writable: true,
|
|
14
|
+
value: jsType
|
|
15
|
+
});
|
|
16
|
+
Object.defineProperty(this, "category", {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
configurable: true,
|
|
19
|
+
writable: true,
|
|
20
|
+
value: category
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import type SimpleTable from "../class/SimpleTable.js";
|
|
2
|
+
import type { PendingOp, PendingOpInput } from "./pendingOps.js";
|
|
2
3
|
import { type TableGenerationId } from "./tableGeneration.js";
|
|
3
4
|
export type CacheTableDependency = {
|
|
4
5
|
tableName: string;
|
|
5
6
|
generationId: TableGenerationId;
|
|
6
7
|
};
|
|
8
|
+
/** Keeps deferred callbacks in their originating cache scope across observers. */
|
|
9
|
+
export declare function captureCacheTableOperation(op: PendingOpInput): PendingOpInput;
|
|
10
|
+
/** Rejects mutations before they can queue work or execute SQL. */
|
|
11
|
+
export declare function assertCacheTableMutation(table: SimpleTable): void;
|
|
12
|
+
/** Tracks callback-owned handles so failure cleanup does not touch other work. */
|
|
13
|
+
export declare function recordCacheTableCreation(table: SimpleTable): void;
|
|
14
|
+
/** Tracks queued work across nested callbacks, including async barriers. */
|
|
15
|
+
export declare function recordCacheTableOperation(table: SimpleTable, op: PendingOp): void;
|
|
7
16
|
/** Records a table read when a cache computation is observing dependencies. */
|
|
8
17
|
export declare function recordCacheTableAccess(table: SimpleTable): void;
|
|
9
18
|
/** Records registered tables named in user-supplied SQL fragments. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cacheTableDependencies.d.ts","sourceRoot":"","sources":["../../src/helpers/cacheTableDependencies.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cacheTableDependencies.d.ts","sourceRoot":"","sources":["../../src/helpers/cacheTableDependencies.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAWjE,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,iBAAiB,CAAC;CACjC,CAAC;AAkBF,kFAAkF;AAClF,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,cAAc,GAAG,cAAc,CAiB7E;AAYD,mEAAmE;AACnE,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAWjE;AAED,kFAAkF;AAClF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CASjE;AAED,4EAA4E;AAC5E,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,WAAW,EAClB,EAAE,EAAE,SAAS,GACZ,IAAI,CAMN;AAED,+EAA+E;AAC/E,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAM/D;AAED,sEAAsE;AACtE,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,WAAW,EAClB,GAAG,EAAE,SAAS,MAAM,EAAE,GACrB,IAAI,CAON;AAED,qEAAqE;AACrE,wBAAsB,6BAA6B,CACjD,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAC3B,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAsDjC;AA4ED,2EAA2E;AAC3E,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,SAAS,oBAAoB,EAAE,GAAG,SAAS,GACxD,OAAO,CAYT;AAED,+EAA+E;AAC/E,wBAAgB,oCAAoC,CAClD,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,SAAS,oBAAoB,EAAE,GAC5C,MAAM,CAsBR;AAED,kEAAkE;AAClE,wBAAgB,sCAAsC,CACpD,YAAY,EAAE,SAAS,oBAAoB,EAAE,GAC5C,MAAM,CAER"}
|
|
@@ -1,22 +1,78 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
-
import
|
|
2
|
+
import referencedTables from "./referencedTables.js";
|
|
3
|
+
import { getAsyncOperationFrame, runWhileDrainingAsyncOperationFrame, } from "./asyncOperationContext.js";
|
|
4
|
+
import flushAllTables, { runExemptFromFlush } from "./flushAllTables.js";
|
|
5
|
+
import quoteIdentifier from "./quoteIdentifier.js";
|
|
6
|
+
import { getRegisteredTables, retainRegisteredTables, } from "./tableRegistry.js";
|
|
3
7
|
import { getTableGeneration, peekTableGeneration, } from "./tableGeneration.js";
|
|
4
8
|
const dependencyContext = new AsyncLocalStorage();
|
|
9
|
+
/** Keeps deferred callbacks in their originating cache scope across observers. */
|
|
10
|
+
export function captureCacheTableOperation(op) {
|
|
11
|
+
if (op.kind === "barrier" || op.kind === "asyncBarrier") {
|
|
12
|
+
return { ...op, execute: bindCacheContext(op.execute) };
|
|
13
|
+
}
|
|
14
|
+
if (op.kind === "source") {
|
|
15
|
+
return { ...op, buildSelect: bindCacheContext(op.buildSelect) };
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
...op,
|
|
19
|
+
buildSelect: bindCacheContext(op.buildSelect),
|
|
20
|
+
outputSchema: op.outputSchema === undefined
|
|
21
|
+
? undefined
|
|
22
|
+
: bindCacheContext(op.outputSchema),
|
|
23
|
+
values: typeof op.values === "function"
|
|
24
|
+
? bindCacheContext(op.values)
|
|
25
|
+
: op.values,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function bindCacheContext(callback) {
|
|
29
|
+
// Capture only the cache scope: a snapshot of all AsyncLocalStorage stores
|
|
30
|
+
// would also capture stale flush exemptions and async operation frames.
|
|
31
|
+
// An empty scope keeps unrelated work out of the observer's cache callback.
|
|
32
|
+
const frames = dependencyContext.getStore() ?? [];
|
|
33
|
+
return (...args) => dependencyContext.run(frames, () => callback(...args));
|
|
34
|
+
}
|
|
35
|
+
/** Rejects mutations before they can queue work or execute SQL. */
|
|
36
|
+
export function assertCacheTableMutation(table) {
|
|
37
|
+
for (const frame of dependencyContext.getStore() ?? []) {
|
|
38
|
+
if (frame.open && table !== frame.cachedTable &&
|
|
39
|
+
frame.availableBeforeCompute.has(table)) {
|
|
40
|
+
throw new Error(cacheTableMutationMessage(frame.cachedTable, [table.name]));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** Tracks callback-owned handles so failure cleanup does not touch other work. */
|
|
45
|
+
export function recordCacheTableCreation(table) {
|
|
46
|
+
for (const frame of dependencyContext.getStore() ?? []) {
|
|
47
|
+
if (frame.open && table.sdb === frame.cachedTable.sdb &&
|
|
48
|
+
!frame.availableBeforeCompute.has(table)) {
|
|
49
|
+
frame.created.add(table);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** Tracks queued work across nested callbacks, including async barriers. */
|
|
54
|
+
export function recordCacheTableOperation(table, op) {
|
|
55
|
+
for (const frame of dependencyContext.getStore() ?? []) {
|
|
56
|
+
if (frame.open && table.sdb === frame.cachedTable.sdb) {
|
|
57
|
+
frame.queued.add(op.sequence);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
5
61
|
/** Records a table read when a cache computation is observing dependencies. */
|
|
6
62
|
export function recordCacheTableAccess(table) {
|
|
7
|
-
dependencyContext.getStore()
|
|
63
|
+
for (const frame of dependencyContext.getStore() ?? []) {
|
|
64
|
+
if (frame.open && table.sdb === frame.cachedTable.sdb) {
|
|
65
|
+
frame.accessed.add(table);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
8
68
|
}
|
|
9
69
|
/** Records registered tables named in user-supplied SQL fragments. */
|
|
10
70
|
export function recordCacheTableReferences(table, sql) {
|
|
11
71
|
if (dependencyContext.getStore() === undefined) {
|
|
12
72
|
return;
|
|
13
73
|
}
|
|
14
|
-
for (const candidate of
|
|
15
|
-
|
|
16
|
-
const pattern = new RegExp(`(?<![\\w\"])\"?${escaped}\"?(?![\\w\"])`, "i");
|
|
17
|
-
if (sql.some((fragment) => pattern.test(fragment))) {
|
|
18
|
-
recordCacheTableAccess(candidate);
|
|
19
|
-
}
|
|
74
|
+
for (const candidate of referencedTables(sql, table.sdb)) {
|
|
75
|
+
recordCacheTableAccess(candidate);
|
|
20
76
|
}
|
|
21
77
|
}
|
|
22
78
|
/** Runs a cache computation while collecting the tables it reads. */
|
|
@@ -29,19 +85,31 @@ export async function captureCacheTableDependencies(cachedTable, compute) {
|
|
|
29
85
|
},
|
|
30
86
|
]));
|
|
31
87
|
const accessed = new Set();
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
88
|
+
const frame = {
|
|
89
|
+
cachedTable,
|
|
90
|
+
availableBeforeCompute,
|
|
91
|
+
accessed,
|
|
92
|
+
created: new Set(),
|
|
93
|
+
queued: new Set(),
|
|
94
|
+
open: true,
|
|
95
|
+
};
|
|
96
|
+
try {
|
|
97
|
+
await dependencyContext.run([...(dependencyContext.getStore() ?? []), frame], async () => {
|
|
98
|
+
await compute();
|
|
99
|
+
// A callback can queue a whole computation without observing it.
|
|
100
|
+
// Reject leaked handles before executing that pending computation.
|
|
101
|
+
assertCacheTableCleanup(frame);
|
|
102
|
+
await flushAllTables(cachedTable.sdb);
|
|
103
|
+
// Async barriers may create tables during the final flush.
|
|
104
|
+
assertCacheTableCleanup(frame);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
await cleanupCacheComputation(frame);
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
frame.open = false;
|
|
45
113
|
}
|
|
46
114
|
return [...accessed]
|
|
47
115
|
.filter((table) => table !== cachedTable && availableBeforeCompute.has(table))
|
|
@@ -57,6 +125,48 @@ export async function captureCacheTableDependencies(cachedTable, compute) {
|
|
|
57
125
|
})
|
|
58
126
|
.sort((left, right) => left.tableName.localeCompare(right.tableName));
|
|
59
127
|
}
|
|
128
|
+
function assertCacheTableCleanup(frame) {
|
|
129
|
+
const created = getRegisteredTables(frame.cachedTable.sdb)
|
|
130
|
+
.filter((table) => frame.created.has(table));
|
|
131
|
+
if (created.length > 0) {
|
|
132
|
+
throw new Error(cacheTableCleanupMessage(created.map((table) => table.name)));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async function cleanupCacheComputation(frame) {
|
|
136
|
+
const sdb = frame.cachedTable.sdb;
|
|
137
|
+
// Drop only this callback's pending operations, preserving other queues and
|
|
138
|
+
// their database-wide ordering. A nested failure also discards work captured
|
|
139
|
+
// by an enclosing async barrier, which is stored outside pendingOps.
|
|
140
|
+
for (const table of getRegisteredTables(sdb)) {
|
|
141
|
+
const retained = table.pendingOps.filter((op) => !frame.queued.has(op.sequence));
|
|
142
|
+
sdb.pendingCount -= table.pendingOps.length - retained.length;
|
|
143
|
+
table.pendingOps.splice(0, table.pendingOps.length, ...retained);
|
|
144
|
+
}
|
|
145
|
+
const operationFrame = getAsyncOperationFrame(sdb);
|
|
146
|
+
if (operationFrame !== undefined) {
|
|
147
|
+
operationFrame.entries = operationFrame.entries.filter((entry) => !frame.queued.has(entry.op.sequence));
|
|
148
|
+
}
|
|
149
|
+
const created = getRegisteredTables(sdb)
|
|
150
|
+
.filter((table) => frame.created.has(table));
|
|
151
|
+
if (created.length === 0)
|
|
152
|
+
return;
|
|
153
|
+
// Observers inside compute may already have materialized temporary tables.
|
|
154
|
+
// Cleanup must not flush work requeued after an execution error.
|
|
155
|
+
const removeCreatedTables = () => runExemptFromFlush(sdb, async () => {
|
|
156
|
+
for (const table of created) {
|
|
157
|
+
await sdb.customQuery(`DROP TABLE IF EXISTS ${quoteIdentifier(table.name)};`);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
if (operationFrame === undefined) {
|
|
161
|
+
await removeCreatedTables();
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
// Async frames take precedence over the database-wide flush exemption.
|
|
165
|
+
// Suppress their drain too, without consuming unrelated captured work.
|
|
166
|
+
await runWhileDrainingAsyncOperationFrame(operationFrame, removeCreatedTables);
|
|
167
|
+
}
|
|
168
|
+
retainRegisteredTables(sdb, (table) => !frame.created.has(table));
|
|
169
|
+
}
|
|
60
170
|
function cacheTableMutationMessage(cachedTable, changedTables) {
|
|
61
171
|
const tables = changedTables.map((name) => JSON.stringify(name)).join(", ");
|
|
62
172
|
const cachedTableName = JSON.stringify(cachedTable.name);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export default function cleanSQL(query: string): string;
|
|
1
|
+
export default function cleanSQL(query: string, syntax?: "js" | "sql"): string;
|
|
2
2
|
//# sourceMappingURL=cleanSQL.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cleanSQL.d.ts","sourceRoot":"","sources":["../../src/helpers/cleanSQL.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cleanSQL.d.ts","sourceRoot":"","sources":["../../src/helpers/cleanSQL.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,UAAU,QAAQ,CAC9B,KAAK,EAAE,MAAM,EACb,MAAM,GAAE,IAAI,GAAG,KAAY,GAC1B,MAAM,CAqRR"}
|
package/esm/helpers/cleanSQL.js
CHANGED
|
@@ -1,24 +1,269 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
1
|
+
import scanSQL from "./scanSQL.js";
|
|
2
|
+
export default function cleanSQL(query, syntax = "js") {
|
|
3
|
+
if (syntax === "sql")
|
|
4
|
+
return query;
|
|
5
|
+
const tokens = scanSQL(query);
|
|
6
|
+
const significant = tokens.filter((token) => token.kind !== "trivia");
|
|
7
|
+
const original = significant.map((token) => token.kind === "sql" ? token.text.toUpperCase() : "");
|
|
8
|
+
const pairs = new Map();
|
|
9
|
+
const stack = [];
|
|
10
|
+
for (let i = 0; i < original.length; i++) {
|
|
11
|
+
if (["(", "[", "CASE"].includes(original[i]))
|
|
12
|
+
stack.push(i);
|
|
13
|
+
else if (stack.length &&
|
|
14
|
+
((original[i] === ")" && original[stack[stack.length - 1]] === "(") ||
|
|
15
|
+
(original[i] === "]" && original[stack[stack.length - 1]] === "[") ||
|
|
16
|
+
(original[i] === "END" && original[stack[stack.length - 1]] === "CASE"))) {
|
|
17
|
+
const start = stack.pop();
|
|
18
|
+
pairs.set(start, i);
|
|
19
|
+
pairs.set(i, start);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const betweenAnd = new Set();
|
|
23
|
+
for (let i = 0; i < original.length; i++) {
|
|
24
|
+
if (original[i] !== "BETWEEN")
|
|
25
|
+
continue;
|
|
26
|
+
for (let j = i + 1; j < original.length; j++) {
|
|
27
|
+
if (["(", "[", "CASE"].includes(original[j])) {
|
|
28
|
+
j = pairs.get(j) ?? original.length;
|
|
29
|
+
}
|
|
30
|
+
else if ([")", "]", "END", ";"].includes(original[j]))
|
|
31
|
+
break;
|
|
32
|
+
else if (original[j] === "AND") {
|
|
33
|
+
betweenAnd.add(j);
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const comparisons = new Set([
|
|
39
|
+
"=",
|
|
40
|
+
"==",
|
|
41
|
+
"===",
|
|
42
|
+
"!=",
|
|
43
|
+
"!==",
|
|
44
|
+
"<>",
|
|
45
|
+
"<",
|
|
46
|
+
">",
|
|
47
|
+
"<=",
|
|
48
|
+
">=",
|
|
49
|
+
"IS",
|
|
50
|
+
"IN",
|
|
51
|
+
"LIKE",
|
|
52
|
+
"ILIKE",
|
|
53
|
+
"BETWEEN",
|
|
54
|
+
]);
|
|
55
|
+
const boundaries = new Set([
|
|
56
|
+
"SELECT",
|
|
57
|
+
"FROM",
|
|
58
|
+
"WHERE",
|
|
59
|
+
"HAVING",
|
|
60
|
+
"QUALIFY",
|
|
61
|
+
"GROUP",
|
|
62
|
+
"ORDER",
|
|
63
|
+
"LIMIT",
|
|
64
|
+
"RETURNING",
|
|
65
|
+
"UNION",
|
|
66
|
+
"EXCEPT",
|
|
67
|
+
"INTERSECT",
|
|
68
|
+
"WHEN",
|
|
69
|
+
"THEN",
|
|
70
|
+
"ELSE",
|
|
71
|
+
"AS",
|
|
72
|
+
"AND",
|
|
73
|
+
"OR",
|
|
74
|
+
"&&",
|
|
75
|
+
",",
|
|
76
|
+
";",
|
|
77
|
+
]);
|
|
78
|
+
const textTypes = new Set(["VARCHAR", "CHAR", "BPCHAR", "TEXT", "STRING"]);
|
|
79
|
+
function range(pipe, start, end, stop) {
|
|
80
|
+
let left = pipe - 1;
|
|
81
|
+
while (left >= start && !stop(left)) {
|
|
82
|
+
if ([")", "]", "END"].includes(original[left])) {
|
|
83
|
+
left = pairs.get(left) ?? start;
|
|
84
|
+
}
|
|
85
|
+
left--;
|
|
86
|
+
}
|
|
87
|
+
let right = pipe + 1;
|
|
88
|
+
while (right < end && !stop(right)) {
|
|
89
|
+
if (["(", "[", "CASE"].includes(original[right])) {
|
|
90
|
+
right = pairs.get(right) ?? end;
|
|
91
|
+
}
|
|
92
|
+
right++;
|
|
93
|
+
}
|
|
94
|
+
return [left + 1, right];
|
|
95
|
+
}
|
|
96
|
+
function predicate(start, end) {
|
|
97
|
+
if (original[start] === "(" && pairs.get(start) === end - 1) {
|
|
98
|
+
return predicate(start + 1, end - 1);
|
|
99
|
+
}
|
|
100
|
+
for (let i = start; i < end; i++) {
|
|
101
|
+
if (["(", "[", "CASE"].includes(original[i]))
|
|
102
|
+
i = pairs.get(i) ?? end;
|
|
103
|
+
else if (comparisons.has(original[i]))
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
// Only infer types that are explicit in the expression. Never infer a
|
|
109
|
+
// column's or an arbitrary function's type from its name or argument types.
|
|
110
|
+
function isTextType(start, end) {
|
|
111
|
+
return textTypes.has(original[start]) &&
|
|
112
|
+
(start + 1 === end ||
|
|
113
|
+
(original[start + 1] === "(" && pairs.get(start + 1) === end - 1));
|
|
114
|
+
}
|
|
115
|
+
function concatenable(start, end) {
|
|
116
|
+
if (start >= end)
|
|
117
|
+
return false;
|
|
118
|
+
let cast;
|
|
119
|
+
let pipe;
|
|
120
|
+
for (let i = start; i < end; i++) {
|
|
121
|
+
if (["(", "[", "CASE"].includes(original[i]))
|
|
122
|
+
i = pairs.get(i) ?? end;
|
|
123
|
+
else if (comparisons.has(original[i]))
|
|
124
|
+
return false;
|
|
125
|
+
else if (original[i] === "||")
|
|
126
|
+
pipe ??= i;
|
|
127
|
+
else if (original[i] === "::")
|
|
128
|
+
cast = i;
|
|
129
|
+
}
|
|
130
|
+
if (pipe !== undefined) {
|
|
131
|
+
return concatenable(start, pipe) || concatenable(pipe + 1, end);
|
|
132
|
+
}
|
|
133
|
+
// The final cast determines the result type, including casts to BOOLEAN.
|
|
134
|
+
if (cast !== undefined) {
|
|
135
|
+
return isTextType(cast + 1, end);
|
|
136
|
+
}
|
|
137
|
+
if (original[start] === "(" && pairs.get(start) === end - 1) {
|
|
138
|
+
return concatenable(start + 1, end - 1);
|
|
139
|
+
}
|
|
140
|
+
if (original[start] === "[" && pairs.get(start) === end - 1)
|
|
141
|
+
return true;
|
|
142
|
+
if (end === start + 1) {
|
|
143
|
+
return significant[start].kind === "quoted" &&
|
|
144
|
+
!significant[start].text.startsWith('"');
|
|
145
|
+
}
|
|
146
|
+
if (original[start + 1] === "(" && pairs.get(start + 1) === end - 1) {
|
|
147
|
+
if (["CONCAT", "CONCAT_WS"].includes(original[start]))
|
|
148
|
+
return true;
|
|
149
|
+
if (["CAST", "TRY_CAST"].includes(original[start])) {
|
|
150
|
+
for (let i = start + 2; i < end - 1; i++) {
|
|
151
|
+
if (["(", "[", "CASE"].includes(original[i])) {
|
|
152
|
+
i = pairs.get(i) ?? end;
|
|
153
|
+
}
|
|
154
|
+
else if (original[i] === "AS") {
|
|
155
|
+
return isTextType(i + 1, end - 1);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
function obviousConcatenation(pipe, start, end) {
|
|
163
|
+
const [left, right] = range(pipe, start, end, (i) => (boundaries.has(original[i]) && !betweenAnd.has(i)) ||
|
|
164
|
+
original[i] === "||");
|
|
165
|
+
// A literal in a comparison is not evidence that the comparison returns text.
|
|
166
|
+
if (predicate(left, pipe) && predicate(pipe + 1, right))
|
|
167
|
+
return false;
|
|
168
|
+
const [groupStart, groupEnd] = range(pipe, start, end, (i) => boundaries.has(original[i]) || comparisons.has(original[i]));
|
|
169
|
+
let operand = groupStart;
|
|
170
|
+
for (let i = groupStart; i <= groupEnd; i++) {
|
|
171
|
+
if (["(", "[", "CASE"].includes(original[i])) {
|
|
172
|
+
i = pairs.get(i) ?? groupEnd;
|
|
173
|
+
}
|
|
174
|
+
else if (i === groupEnd || original[i] === "||") {
|
|
175
|
+
// Do not use the RHS literal of a preceding comparison to infer OR's
|
|
176
|
+
// meaning (text = 'a' || active). Other operands can still prove concat.
|
|
177
|
+
if (!(operand === groupStart &&
|
|
178
|
+
(comparisons.has(original[groupStart - 1]) ||
|
|
179
|
+
betweenAnd.has(groupStart - 1))) &&
|
|
180
|
+
concatenable(operand, i))
|
|
181
|
+
return true;
|
|
182
|
+
operand = i + 1;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
function normalize(start, end) {
|
|
188
|
+
let statement = original[start];
|
|
189
|
+
let inSetClause = false;
|
|
190
|
+
let assignmentTarget = false;
|
|
191
|
+
for (let i = start; i < end; i++) {
|
|
192
|
+
const word = original[i];
|
|
193
|
+
if (statement === undefined)
|
|
194
|
+
statement = word;
|
|
195
|
+
// Nested queries are visited separately below. Look through statement
|
|
196
|
+
// prefixes to find the outer command that can introduce assignments.
|
|
197
|
+
if (["WITH", "EXPLAIN", "PREPARE"].includes(statement) &&
|
|
198
|
+
["SELECT", "INSERT", "UPDATE", "DELETE", "MERGE"].includes(word))
|
|
199
|
+
statement = word;
|
|
200
|
+
if (word === "UPDATE" && ["DO", "THEN"].includes(original[i - 1]))
|
|
201
|
+
statement = word;
|
|
202
|
+
if (["(", "[", "CASE"].includes(word)) {
|
|
203
|
+
const close = pairs.get(i);
|
|
204
|
+
if (close !== undefined) {
|
|
205
|
+
normalize(i + 1, close);
|
|
206
|
+
i = close;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (["WHERE", "HAVING", "QUALIFY", "WHEN"].includes(word)) {
|
|
211
|
+
statement = word;
|
|
212
|
+
inSetClause = false;
|
|
213
|
+
assignmentTarget = false;
|
|
214
|
+
}
|
|
215
|
+
else if ([
|
|
216
|
+
"THEN",
|
|
217
|
+
"ELSE",
|
|
218
|
+
"SELECT",
|
|
219
|
+
"FROM",
|
|
220
|
+
"GROUP",
|
|
221
|
+
"ORDER",
|
|
222
|
+
"LIMIT",
|
|
223
|
+
"RETURNING",
|
|
224
|
+
"UNION",
|
|
225
|
+
"EXCEPT",
|
|
226
|
+
"INTERSECT",
|
|
227
|
+
";",
|
|
228
|
+
].includes(word)) {
|
|
229
|
+
statement = word;
|
|
230
|
+
inSetClause = false;
|
|
231
|
+
assignmentTarget = false;
|
|
232
|
+
}
|
|
233
|
+
else if (word === "SET" && !inSetClause &&
|
|
234
|
+
(statement === "UPDATE" ||
|
|
235
|
+
(statement === "SET" &&
|
|
236
|
+
(original[i + 1] === "VARIABLE" || original[i + 2] === "=")))) {
|
|
237
|
+
inSetClause = true;
|
|
238
|
+
assignmentTarget = true;
|
|
239
|
+
}
|
|
240
|
+
else if (word === "," && inSetClause)
|
|
241
|
+
assignmentTarget = true;
|
|
242
|
+
if (word === ";")
|
|
243
|
+
statement = undefined;
|
|
244
|
+
// Preserve only the assignment operator itself. Comparisons in its RHS
|
|
245
|
+
// still use shorthand, even when they are not wrapped in parentheses.
|
|
246
|
+
const assignment = assignmentTarget && ["=", "==", "==="].includes(word);
|
|
247
|
+
if (assignment)
|
|
248
|
+
assignmentTarget = false;
|
|
249
|
+
const token = significant[i];
|
|
250
|
+
if (["==", "==="].includes(word))
|
|
251
|
+
token.text = "=";
|
|
252
|
+
else if (word === "!==")
|
|
253
|
+
token.text = "!=";
|
|
254
|
+
else if (word === "&&")
|
|
255
|
+
token.text = " AND ";
|
|
256
|
+
else if (word === "||" && !obviousConcatenation(i, start, end)) {
|
|
257
|
+
token.text = " OR ";
|
|
258
|
+
}
|
|
259
|
+
if (original[i + 1] === "NULL" && !assignment) {
|
|
260
|
+
if (["=", "==", "==="].includes(word))
|
|
261
|
+
token.text = " IS ";
|
|
262
|
+
else if (["!=", "!=="].includes(word))
|
|
263
|
+
token.text = " IS NOT ";
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
normalize(0, significant.length);
|
|
268
|
+
return tokens.map((token) => token.text).join("").trim();
|
|
24
269
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flushAllTables.d.ts","sourceRoot":"","sources":["../../src/helpers/flushAllTables.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,QAAQ,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"flushAllTables.d.ts","sourceRoot":"","sources":["../../src/helpers/flushAllTables.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,QAAQ,MAAM,sBAAsB,CAAC;AAkCjD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,GAAG,EAAE,QAAQ,EACb,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,CAIZ;AAED;;;;;;;;;;;;GAYG;AACH,wBAA8B,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAgCzE"}
|