@nshiab/simple-data-analysis-core 2.1.2 → 2.1.3
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/esm/class/SimpleDB.d.ts.map +1 -1
- package/esm/class/SimpleDB.js +23 -14
- package/esm/class/SimpleTable.d.ts +18 -6
- package/esm/class/SimpleTable.d.ts.map +1 -1
- package/esm/class/SimpleTable.js +20 -8
- package/esm/helpers/cleanCache.d.ts +1 -1
- package/esm/helpers/cleanCache.d.ts.map +1 -1
- package/esm/helpers/cleanCache.js +2 -2
- package/esm/helpers/updateColumnsWithJS.d.ts.map +1 -1
- package/esm/helpers/updateColumnsWithJS.js +14 -12
- package/esm/methods/similarityMahalanobis.d.ts +5 -0
- package/esm/methods/similarityMahalanobis.d.ts.map +1 -0
- package/esm/methods/{mahalanobis.js → similarityMahalanobis.js} +9 -9
- package/esm/methods/updateWithJS.js +24 -5
- package/llm.md +19 -10
- package/llms.txt +1 -1
- package/package.json +2 -2
- package/script/class/SimpleDB.d.ts.map +1 -1
- package/script/class/SimpleDB.js +23 -14
- package/script/class/SimpleTable.d.ts +18 -6
- package/script/class/SimpleTable.d.ts.map +1 -1
- package/script/class/SimpleTable.js +20 -8
- package/script/helpers/cleanCache.d.ts +1 -1
- package/script/helpers/cleanCache.d.ts.map +1 -1
- package/script/helpers/cleanCache.js +2 -2
- package/script/helpers/updateColumnsWithJS.d.ts.map +1 -1
- package/script/helpers/updateColumnsWithJS.js +13 -11
- package/script/methods/similarityMahalanobis.d.ts +5 -0
- package/script/methods/similarityMahalanobis.d.ts.map +1 -0
- package/script/methods/{mahalanobis.js → similarityMahalanobis.js} +10 -10
- package/script/methods/updateWithJS.js +24 -5
- package/esm/methods/mahalanobis.d.ts +0 -5
- package/esm/methods/mahalanobis.d.ts.map +0 -1
- package/script/methods/mahalanobis.d.ts +0 -5
- package/script/methods/mahalanobis.d.ts.map +0 -1
|
@@ -8,6 +8,8 @@ const quoteIdentifier_js_1 = __importDefault(require("./quoteIdentifier.js"));
|
|
|
8
8
|
const readMutationRows_js_1 = __importDefault(require("./readMutationRows.js"));
|
|
9
9
|
const tableRegistry_js_1 = require("./tableRegistry.js");
|
|
10
10
|
const loadArray_js_1 = require("../methods/loadArray.js");
|
|
11
|
+
const appendColumnBatches_js_1 = __importDefault(require("./appendColumnBatches.js"));
|
|
12
|
+
const parseDuckDBType_js_1 = __importDefault(require("./parseDuckDBType.js"));
|
|
11
13
|
/**
|
|
12
14
|
* Generates columns from selected input columns, keeping other SQL values in
|
|
13
15
|
* DuckDB. Call from an asynchronous extension barrier. The callback must return
|
|
@@ -74,7 +76,6 @@ async function updateColumnsWithJS(table, inputColumns, outputColumns, generate,
|
|
|
74
76
|
const id = `__sda_id_${suffix}`;
|
|
75
77
|
const snapshot = `__sda_source_${suffix}`;
|
|
76
78
|
const staged = table.sdb.newTable(`__sda_generated_${suffix}`);
|
|
77
|
-
const batch = table.sdb.newTable(`__sda_batch_${suffix}`);
|
|
78
79
|
const q = quoteIdentifier_js_1.default;
|
|
79
80
|
try {
|
|
80
81
|
// A SQL snapshot gives every row a stable identity, including duplicate rows
|
|
@@ -98,17 +99,17 @@ async function updateColumnsWithJS(table, inputColumns, outputColumns, generate,
|
|
|
98
99
|
throw new Error("Column generation must return one row per input row.");
|
|
99
100
|
}
|
|
100
101
|
// Generated vectors retain this helper's existing inference contract.
|
|
101
|
-
|
|
102
|
+
const prepared = (0, loadArray_js_1.prepareArray)(generated.map((row, i) => ({
|
|
102
103
|
...Object.fromEntries(outputColumns.map((name) => [name, row[name]])),
|
|
103
104
|
[id]: ids[i],
|
|
104
|
-
})))
|
|
105
|
-
const batchTypes =
|
|
105
|
+
})));
|
|
106
|
+
const batchTypes = new Map(prepared.keys.map((name, i) => [name, prepared.types[i]]));
|
|
106
107
|
for (const name of outputColumns) {
|
|
107
108
|
const nonNull = generated.some((row) => row[name] !== null && row[name] !== undefined);
|
|
108
109
|
if (!nonNull)
|
|
109
110
|
continue;
|
|
110
111
|
const previous = knownTypes.get(name);
|
|
111
|
-
const current = batchTypes
|
|
112
|
+
const current = batchTypes.get(name);
|
|
112
113
|
if (previous !== undefined && previous !== current) {
|
|
113
114
|
throw new Error(`Generated column ${JSON.stringify(name)} changed type from ${previous} to ${current}.`);
|
|
114
115
|
}
|
|
@@ -120,12 +121,13 @@ async function updateColumnsWithJS(table, inputColumns, outputColumns, generate,
|
|
|
120
121
|
}
|
|
121
122
|
}
|
|
122
123
|
if (!hasRows) {
|
|
123
|
-
await table.sdb.customQuery(`CREATE TEMP TABLE ${q(staged.name)}
|
|
124
|
+
await table.sdb.customQuery(`CREATE TEMP TABLE ${q(staged.name)} (${prepared.keys.map((name, i) => `${q(name)} ${prepared.types[i]}`)
|
|
125
|
+
.join(", ")})`);
|
|
124
126
|
hasRows = true;
|
|
125
127
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
128
|
+
// All-null batches use the column's established type, avoiding a separate
|
|
129
|
+
// batch table and SQL copy just to cast nulls into the staged schema.
|
|
130
|
+
await (0, appendColumnBatches_js_1.default)(table.connection, staged.name, prepared.keys.map((name, i) => (0, parseDuckDBType_js_1.default)(knownTypes.get(name) ?? prepared.types[i])), prepared.rowCount, (column, start, end) => prepared.columnsData[column].slice(start, end));
|
|
129
131
|
}
|
|
130
132
|
if (!hasRows)
|
|
131
133
|
return;
|
|
@@ -145,7 +147,7 @@ async function updateColumnsWithJS(table, inputColumns, outputColumns, generate,
|
|
|
145
147
|
await table.sdb.customQuery(`CREATE OR REPLACE TABLE ${q(table.name)} AS SELECT ${columns.join(", ")} FROM ${q(snapshot)} original JOIN ${q(staged.name)} generated ON original.${q(id)} = CAST(generated.${q(id)} AS BIGINT) ORDER BY original.${q(id)}`);
|
|
146
148
|
}
|
|
147
149
|
finally {
|
|
148
|
-
await table.sdb.customQuery(`DROP TABLE IF EXISTS ${q(snapshot)}; DROP TABLE IF EXISTS ${q(staged.name)}
|
|
149
|
-
(0, tableRegistry_js_1.retainRegisteredTables)(table.sdb, (item) => item !== staged
|
|
150
|
+
await table.sdb.customQuery(`DROP TABLE IF EXISTS ${q(snapshot)}; DROP TABLE IF EXISTS ${q(staged.name)};`);
|
|
151
|
+
(0, tableRegistry_js_1.retainRegisteredTables)(table.sdb, (item) => item !== staged);
|
|
150
152
|
}
|
|
151
153
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type SimpleTable from "../class/SimpleTable.js";
|
|
2
|
+
type Options = NonNullable<Parameters<SimpleTable["similarityMahalanobis"]>[3]>;
|
|
3
|
+
export default function similarityMahalanobis(table: SimpleTable, columns: string | string[], referencePoint: number[], newColumn: string, options?: Options): void;
|
|
4
|
+
export {};
|
|
5
|
+
//# sourceMappingURL=similarityMahalanobis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"similarityMahalanobis.d.ts","sourceRoot":"","sources":["../../src/methods/similarityMahalanobis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AASvD,KAAK,OAAO,GAAG,WAAW,CAAC,UAAU,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEhF,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAC3C,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,EAC1B,cAAc,EAAE,MAAM,EAAE,EACxB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,OAAY,GACpB,IAAI,CAyBN"}
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.default =
|
|
6
|
+
exports.default = similarityMahalanobis;
|
|
7
7
|
const computeCovariance_js_1 = __importDefault(require("../helpers/computeCovariance.js"));
|
|
8
8
|
const computeMahalanobisDistances_js_1 = __importDefault(require("../helpers/computeMahalanobisDistances.js"));
|
|
9
9
|
const foldIdentifier_js_1 = __importDefault(require("../helpers/foldIdentifier.js"));
|
|
@@ -11,17 +11,17 @@ const prepareNumericFeatures_js_1 = __importDefault(require("../helpers/prepareN
|
|
|
11
11
|
const publishPreparedColumns_js_1 = __importDefault(require("../helpers/publishPreparedColumns.js"));
|
|
12
12
|
const queueOp_js_1 = __importDefault(require("../helpers/queueOp.js"));
|
|
13
13
|
const quoteIdentifier_js_1 = __importDefault(require("../helpers/quoteIdentifier.js"));
|
|
14
|
-
function
|
|
14
|
+
function similarityMahalanobis(table, columns, referencePoint, newColumn, options = {}) {
|
|
15
15
|
if (!Array.isArray(referencePoint) || referencePoint.length === 0 ||
|
|
16
16
|
Array.from(referencePoint).some((value) => typeof value !== "number" || !Number.isFinite(value))) {
|
|
17
|
-
throw new Error("
|
|
17
|
+
throw new Error("similarityMahalanobis() referencePoint must be a nonempty array of finite numbers in feature-dimension order.");
|
|
18
18
|
}
|
|
19
19
|
const selected = typeof columns === "string" ? columns : [...columns];
|
|
20
20
|
const reference = [...referencePoint];
|
|
21
21
|
const settings = { ...options };
|
|
22
22
|
(0, queueOp_js_1.default)(table, {
|
|
23
23
|
kind: "barrier",
|
|
24
|
-
method: "
|
|
24
|
+
method: "similarityMahalanobis()",
|
|
25
25
|
parameters: {
|
|
26
26
|
columns: selected,
|
|
27
27
|
referencePoint: reference,
|
|
@@ -39,23 +39,23 @@ async function execute(table, columns, referencePoint, newColumn, options) {
|
|
|
39
39
|
const seen = new Set();
|
|
40
40
|
for (const name of outputNames) {
|
|
41
41
|
if (typeof name !== "string" || name.length === 0 || name.includes("\0")) {
|
|
42
|
-
throw new Error("
|
|
42
|
+
throw new Error("similarityMahalanobis() output column names must be nonempty strings without null characters.");
|
|
43
43
|
}
|
|
44
44
|
const folded = (0, foldIdentifier_js_1.default)(name);
|
|
45
45
|
if (seen.has(folded)) {
|
|
46
|
-
throw new Error("
|
|
46
|
+
throw new Error("similarityMahalanobis() distance and similarity score columns must have different names (case-insensitive).");
|
|
47
47
|
}
|
|
48
48
|
seen.add(folded);
|
|
49
49
|
if (sourceColumns.some((column) => (0, foldIdentifier_js_1.default)(column) === folded)) {
|
|
50
|
-
throw new Error(`
|
|
50
|
+
throw new Error(`similarityMahalanobis() cannot create ${(0, quoteIdentifier_js_1.default)(name)} because that column already exists. Remove it first or choose a different name.`);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
const prepared = await (0, prepareNumericFeatures_js_1.default)(table, typeof columns === "string"
|
|
54
54
|
? { kind: "vector", column: columns }
|
|
55
|
-
: { kind: "scalars", columns }, { method: "
|
|
55
|
+
: { kind: "scalars", columns }, { method: "similarityMahalanobis()" });
|
|
56
56
|
try {
|
|
57
57
|
if (referencePoint.length !== prepared.dimensions) {
|
|
58
|
-
throw new Error(`
|
|
58
|
+
throw new Error(`similarityMahalanobis() referencePoint must contain ${prepared.dimensions} values in feature-dimension order; received ${referencePoint.length}.`);
|
|
59
59
|
}
|
|
60
60
|
const model = await (0, computeCovariance_js_1.default)(table.connection, {
|
|
61
61
|
relation: prepared.relation,
|
|
@@ -79,7 +79,7 @@ async function execute(table, columns, referencePoint, newColumn, options) {
|
|
|
79
79
|
});
|
|
80
80
|
}
|
|
81
81
|
await (0, publishPreparedColumns_js_1.default)(table, prepared, {
|
|
82
|
-
method: "
|
|
82
|
+
method: "similarityMahalanobis()",
|
|
83
83
|
parameters: { columns, referencePoint, newColumn, options },
|
|
84
84
|
result: {
|
|
85
85
|
relation: distances.relation,
|
|
@@ -66,6 +66,7 @@ async function executeUpdateWithJS(simpleTable, dataModifier, options) {
|
|
|
66
66
|
const accumulator = `updateWithJS_accumulator_${suffix}`;
|
|
67
67
|
try {
|
|
68
68
|
let first = true;
|
|
69
|
+
let accumulatorSchema;
|
|
69
70
|
let lastRowid = null;
|
|
70
71
|
let sawRows = false;
|
|
71
72
|
let outputOffset = 0;
|
|
@@ -137,9 +138,17 @@ async function executeUpdateWithJS(simpleTable, dataModifier, options) {
|
|
|
137
138
|
? (0, parseDuckDBType_js_1.default)("VARCHAR")
|
|
138
139
|
: source.types.get(key) ??
|
|
139
140
|
(0, parseDuckDBType_js_1.default)(added.types[newKeys.indexOf(key)]));
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
141
|
+
const schema = JSON.stringify(keys.map((key, i) => [key, columnTypes[i].toString()]));
|
|
142
|
+
// Append matching native batches directly. SQL still handles conversion
|
|
143
|
+
// and BY NAME alignment when a callback changes the batch schema.
|
|
144
|
+
const direct = outputGeometry.length === 0 && outputJSON.length === 0 &&
|
|
145
|
+
(first || schema === accumulatorSchema);
|
|
146
|
+
const destination = direct ? accumulator : scratch.name;
|
|
147
|
+
if (!direct || first) {
|
|
148
|
+
await simpleTable.sdb.customQuery(`CREATE OR REPLACE TABLE ${(0, quoteIdentifier_js_1.default)(destination)} (${keys.map((key, i) => `${(0, quoteIdentifier_js_1.default)(key)} ${columnTypes[i]}`)
|
|
149
|
+
.join(", ")})`);
|
|
150
|
+
}
|
|
151
|
+
await (0, appendColumnBatches_js_1.default)(simpleTable.connection, destination, columnTypes, modified.length, (column, start, end) => {
|
|
143
152
|
const key = keys[column];
|
|
144
153
|
return outputGeometry.includes(key)
|
|
145
154
|
? geometryData.get(key).slice(start, end)
|
|
@@ -152,7 +161,11 @@ async function executeUpdateWithJS(simpleTable, dataModifier, options) {
|
|
|
152
161
|
: outputJSON.includes(key)
|
|
153
162
|
? `${(0, quoteIdentifier_js_1.default)(key)}::JSON AS ${(0, quoteIdentifier_js_1.default)(key)}`
|
|
154
163
|
: (0, quoteIdentifier_js_1.default)(key)).join(", ");
|
|
155
|
-
if (
|
|
164
|
+
if (direct) {
|
|
165
|
+
accumulatorSchema = schema;
|
|
166
|
+
first = false;
|
|
167
|
+
}
|
|
168
|
+
else if (first) {
|
|
156
169
|
await simpleTable.sdb.customQuery(`CREATE OR REPLACE TABLE ${(0, quoteIdentifier_js_1.default)(accumulator)} AS SELECT ${projection} FROM ${(0, quoteIdentifier_js_1.default)(scratch.name)}`);
|
|
157
170
|
first = false;
|
|
158
171
|
}
|
|
@@ -165,7 +178,13 @@ async function executeUpdateWithJS(simpleTable, dataModifier, options) {
|
|
|
165
178
|
if (first) {
|
|
166
179
|
throw new Error("The dataModifier returned no rows. updateWithJS can't infer the table schema from zero rows.");
|
|
167
180
|
}
|
|
168
|
-
|
|
181
|
+
// Publish the completed ordinary table without copying its rows again.
|
|
182
|
+
// Qualify the creation namespace: a temporary table or a later search-path
|
|
183
|
+
// schema can shadow the name without being the destination of replacement.
|
|
184
|
+
const namespace = await simpleTable.connection.runAndReadAll("SELECT current_database(), current_schema()");
|
|
185
|
+
const prefix = namespace.getRows()[0].map((name) => (0, quoteIdentifier_js_1.default)(String(name))).join(".");
|
|
186
|
+
await simpleTable.sdb.customQuery(`DROP TABLE IF EXISTS ${prefix}.${(0, quoteIdentifier_js_1.default)(simpleTable.name)};
|
|
187
|
+
ALTER TABLE ${prefix}.${(0, quoteIdentifier_js_1.default)(accumulator)} RENAME TO ${(0, quoteIdentifier_js_1.default)(simpleTable.name)};`);
|
|
169
188
|
}
|
|
170
189
|
finally {
|
|
171
190
|
await simpleTable.sdb.customQuery(`DROP TABLE IF EXISTS ${(0, quoteIdentifier_js_1.default)(accumulator)};
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type SimpleTable from "../class/SimpleTable.js";
|
|
2
|
-
type Options = NonNullable<Parameters<SimpleTable["mahalanobis"]>[3]>;
|
|
3
|
-
export default function mahalanobis(table: SimpleTable, columns: string | string[], referencePoint: number[], newColumn: string, options?: Options): void;
|
|
4
|
-
export {};
|
|
5
|
-
//# sourceMappingURL=mahalanobis.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mahalanobis.d.ts","sourceRoot":"","sources":["../../src/methods/mahalanobis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AASvD,KAAK,OAAO,GAAG,WAAW,CAAC,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEtE,MAAM,CAAC,OAAO,UAAU,WAAW,CACjC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,EAC1B,cAAc,EAAE,MAAM,EAAE,EACxB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,OAAY,GACpB,IAAI,CAyBN"}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type SimpleTable from "../class/SimpleTable.js";
|
|
2
|
-
type Options = NonNullable<Parameters<SimpleTable["mahalanobis"]>[3]>;
|
|
3
|
-
export default function mahalanobis(table: SimpleTable, columns: string | string[], referencePoint: number[], newColumn: string, options?: Options): void;
|
|
4
|
-
export {};
|
|
5
|
-
//# sourceMappingURL=mahalanobis.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mahalanobis.d.ts","sourceRoot":"","sources":["../../src/methods/mahalanobis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AASvD,KAAK,OAAO,GAAG,WAAW,CAAC,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEtE,MAAM,CAAC,OAAO,UAAU,WAAW,CACjC,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,EAC1B,cAAc,EAAE,MAAM,EAAE,EACxB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,OAAY,GACpB,IAAI,CAyBN"}
|