@nshiab/simple-data-analysis-core 2.0.4 → 2.0.6
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 +434 -263
- package/esm/class/SimpleTable.d.ts.map +1 -1
- package/esm/class/SimpleTable.js +441 -316
- 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/addCharacterCount.d.ts +3 -0
- package/esm/methods/addCharacterCount.d.ts.map +1 -0
- package/esm/methods/addCharacterCount.js +15 -0
- package/esm/methods/addColumn.d.ts +1 -1
- package/esm/methods/addColumn.d.ts.map +1 -1
- package/esm/methods/addGeoNoise.d.ts +7 -0
- package/esm/methods/addGeoNoise.d.ts.map +1 -0
- package/esm/methods/addGeoNoise.js +135 -0
- package/esm/methods/addNoise.d.ts +5 -0
- package/esm/methods/addNoise.d.ts.map +1 -0
- package/esm/methods/addNoise.js +53 -0
- package/esm/methods/addWordCount.d.ts +3 -0
- package/esm/methods/addWordCount.d.ts.map +1 -0
- package/esm/methods/addWordCount.js +15 -0
- 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/columnProportions.d.ts +1 -0
- package/esm/methods/columnProportions.d.ts.map +1 -1
- package/esm/methods/columnProportions.js +7 -2
- 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 +4 -2
- package/esm/methods/loadArray.d.ts.map +1 -1
- package/esm/methods/loadArray.js +182 -18
- package/esm/methods/loadData.js +3 -0
- package/esm/methods/loadYahooFinanceData.d.ts +10 -0
- package/esm/methods/loadYahooFinanceData.d.ts.map +1 -0
- package/esm/methods/loadYahooFinanceData.js +133 -0
- package/esm/methods/log.d.ts +7 -0
- package/esm/methods/log.d.ts.map +1 -0
- package/esm/methods/log.js +58 -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/rowProportions.d.ts +1 -0
- package/esm/methods/rowProportions.d.ts.map +1 -1
- package/esm/methods/rowProportions.js +5 -1
- 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 +600 -430
- 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 +434 -263
- package/script/class/SimpleTable.d.ts.map +1 -1
- package/script/class/SimpleTable.js +441 -316
- 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/addCharacterCount.d.ts +3 -0
- package/script/methods/addCharacterCount.d.ts.map +1 -0
- package/script/methods/addCharacterCount.js +21 -0
- package/script/methods/addColumn.d.ts +1 -1
- package/script/methods/addColumn.d.ts.map +1 -1
- package/script/methods/addGeoNoise.d.ts +7 -0
- package/script/methods/addGeoNoise.d.ts.map +1 -0
- package/script/methods/addGeoNoise.js +141 -0
- package/script/methods/addNoise.d.ts +5 -0
- package/script/methods/addNoise.d.ts.map +1 -0
- package/script/methods/addNoise.js +59 -0
- package/script/methods/addWordCount.d.ts +3 -0
- package/script/methods/addWordCount.d.ts.map +1 -0
- package/script/methods/addWordCount.js +21 -0
- 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/columnProportions.d.ts +1 -0
- package/script/methods/columnProportions.d.ts.map +1 -1
- package/script/methods/columnProportions.js +7 -2
- 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 +4 -2
- package/script/methods/loadArray.d.ts.map +1 -1
- package/script/methods/loadArray.js +181 -17
- package/script/methods/loadData.js +3 -0
- package/script/methods/loadYahooFinanceData.d.ts +10 -0
- package/script/methods/loadYahooFinanceData.d.ts.map +1 -0
- package/script/methods/loadYahooFinanceData.js +139 -0
- package/script/methods/log.d.ts +7 -0
- package/script/methods/log.d.ts.map +1 -0
- package/script/methods/log.js +64 -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/rowProportions.d.ts +1 -0
- package/script/methods/rowProportions.d.ts.map +1 -1
- package/script/methods/rowProportions.js +5 -1
- 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
package/esm/methods/getData.js
CHANGED
|
@@ -2,7 +2,7 @@ import mergeOptions from "../helpers/mergeOptions.js";
|
|
|
2
2
|
import queryDB from "../helpers/queryDB.js";
|
|
3
3
|
import quoteIdentifier from "../helpers/quoteIdentifier.js";
|
|
4
4
|
import quoteQualifiedIdentifier from "../helpers/quoteQualifiedIdentifier.js";
|
|
5
|
-
export default async function getData(simpleTable, options = {}) {
|
|
5
|
+
export default async function getData(simpleTable, options = {}, method = "getData()") {
|
|
6
6
|
if (options.limit !== undefined &&
|
|
7
7
|
(!Number.isInteger(options.limit) || options.limit < 0)) {
|
|
8
8
|
throw new Error("getData() limit must be an integer greater than or equal to 0.");
|
|
@@ -17,7 +17,7 @@ export default async function getData(simpleTable, options = {}) {
|
|
|
17
17
|
: "*"} from ${quoteIdentifier(simpleTable.name)}${options.conditions ? ` WHERE ${options.conditions}` : ""}${options.limit === undefined ? "" : ` LIMIT ${options.limit}`}`, mergeOptions(simpleTable, {
|
|
18
18
|
returnData: true,
|
|
19
19
|
table: simpleTable.name,
|
|
20
|
-
method
|
|
20
|
+
method,
|
|
21
21
|
parameters: { options },
|
|
22
22
|
})));
|
|
23
23
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"join.d.ts","sourceRoot":"","sources":["../../src/methods/join.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"join.d.ts","sourceRoot":"","sources":["../../src/methods/join.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAKvD,MAAM,CAAC,OAAO,UAAU,IAAI,CAC1B,SAAS,EAAE,WAAW,EACtB,UAAU,EAAE,WAAW,EACvB,OAAO,GAAE;IACP,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IAC3C,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B,GACL,WAAW,CAkBb"}
|
package/esm/methods/join.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import quoteIdentifier from "../helpers/quoteIdentifier.js";
|
|
2
2
|
import getIdenticalColumns from "../helpers/getIdenticalColumns.js";
|
|
3
|
-
import mergeOptions from "../helpers/mergeOptions.js";
|
|
4
|
-
import queryDB from "../helpers/queryDB.js";
|
|
5
3
|
import queueOp from "../helpers/queueOp.js";
|
|
6
4
|
import assertSameDatabase from "../helpers/assertSameDatabase.js";
|
|
7
5
|
export default function join(leftTable, rightTable, options = {}) {
|
|
@@ -13,14 +11,15 @@ export default function join(leftTable, rightTable, options = {}) {
|
|
|
13
11
|
? leftTable.sdb.newTable(options.outputTable)
|
|
14
12
|
: leftTable;
|
|
15
13
|
queueOp(outputTable, {
|
|
16
|
-
kind: "
|
|
14
|
+
kind: "source",
|
|
15
|
+
rawSQL: [quoteIdentifier(leftTable.name), quoteIdentifier(rightTable.name)],
|
|
17
16
|
method: "join()",
|
|
18
17
|
parameters: { rightTable: rightTable.name, options },
|
|
19
|
-
|
|
18
|
+
buildSelect: () => buildJoinSelect(leftTable, rightTable, options),
|
|
20
19
|
});
|
|
21
20
|
return outputTable;
|
|
22
21
|
}
|
|
23
|
-
async function
|
|
22
|
+
async function buildJoinSelect(leftTable, rightTable, options) {
|
|
24
23
|
const leftTableColumns = await leftTable.getColumns();
|
|
25
24
|
const rightTableColumns = await rightTable.getColumns();
|
|
26
25
|
const identicalColumns = getIdenticalColumns(leftTableColumns, rightTableColumns);
|
|
@@ -74,17 +73,10 @@ async function executeJoin(leftTable, rightTable, outputTable, options) {
|
|
|
74
73
|
.filter((d) => !on.includes(d))
|
|
75
74
|
.map((d) => `${quoteIdentifier(rightTable.name)}.${quoteIdentifier(d)}`),
|
|
76
75
|
].join(", ");
|
|
77
|
-
|
|
78
|
-
table: outputTable.name,
|
|
79
|
-
method: "join()",
|
|
80
|
-
parameters: {
|
|
81
|
-
rightTable: rightTable.name,
|
|
82
|
-
options,
|
|
83
|
-
},
|
|
84
|
-
}));
|
|
76
|
+
return joinQuery(leftTable.name, rightTable.name, on, type, selectList);
|
|
85
77
|
}
|
|
86
|
-
function joinQuery(leftTable, rightTable, on, join,
|
|
87
|
-
let query = `
|
|
78
|
+
function joinQuery(leftTable, rightTable, on, join, selectList) {
|
|
79
|
+
let query = `SELECT ${selectList}`;
|
|
88
80
|
if (join === "inner") {
|
|
89
81
|
query += ` FROM ${quoteIdentifier(leftTable)} JOIN ${quoteIdentifier(rightTable)}`;
|
|
90
82
|
}
|
|
@@ -101,6 +93,6 @@ function joinQuery(leftTable, rightTable, on, join, outputTable, selectList) {
|
|
|
101
93
|
throw new Error(`Unknown ${join} join.`);
|
|
102
94
|
}
|
|
103
95
|
query += ` ON (${on.map((d) => `${quoteIdentifier(leftTable)}.${quoteIdentifier(d)} = ${quoteIdentifier(rightTable)}.${quoteIdentifier(d)}`)
|
|
104
|
-
.join(" AND ")})
|
|
96
|
+
.join(" AND ")})`;
|
|
105
97
|
return query;
|
|
106
98
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"joinGeo.d.ts","sourceRoot":"","sources":["../../src/methods/joinGeo.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"joinGeo.d.ts","sourceRoot":"","sources":["../../src/methods/joinGeo.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAMvD,MAAM,CAAC,OAAO,UAAU,OAAO,CAC7B,SAAS,EAAE,WAAW,EACtB,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,gBAAgB,EACjD,UAAU,EAAE,WAAW,EACvB,OAAO,GAAE;IACP,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,KAAK,GAAG,WAAW,GAAG,UAAU,CAAC;IAClD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B,GACL,WAAW,CAqBb"}
|
package/esm/methods/joinGeo.js
CHANGED
|
@@ -2,8 +2,6 @@ import quoteIdentifier from "../helpers/quoteIdentifier.js";
|
|
|
2
2
|
import capitalize from "../helpers/capitalize.js";
|
|
3
3
|
import findGeoColumnFromSchema from "../helpers/findGeoColumnFromSchema.js";
|
|
4
4
|
import getIdenticalColumns from "../helpers/getIdenticalColumns.js";
|
|
5
|
-
import mergeOptions from "../helpers/mergeOptions.js";
|
|
6
|
-
import queryDB from "../helpers/queryDB.js";
|
|
7
5
|
import queueOp from "../helpers/queueOp.js";
|
|
8
6
|
import assertSameDatabase from "../helpers/assertSameDatabase.js";
|
|
9
7
|
export default function joinGeo(leftTable, method, rightTable, options = {}) {
|
|
@@ -16,10 +14,12 @@ export default function joinGeo(leftTable, method, rightTable, options = {}) {
|
|
|
16
14
|
? leftTable.sdb.newTable(options.outputTable)
|
|
17
15
|
: leftTable;
|
|
18
16
|
queueOp(outputTable, {
|
|
19
|
-
kind: "
|
|
17
|
+
kind: "source",
|
|
18
|
+
rawSQL: [quoteIdentifier(leftTable.name), quoteIdentifier(rightTable.name)],
|
|
19
|
+
needsSpatial: true,
|
|
20
20
|
method: "joinGeo()",
|
|
21
21
|
parameters: { method, rightTable: rightTable.name, options },
|
|
22
|
-
|
|
22
|
+
buildSelect: () => buildJoinGeoSelect(leftTable, method, rightTable, options),
|
|
23
23
|
});
|
|
24
24
|
return outputTable;
|
|
25
25
|
}
|
|
@@ -43,7 +43,7 @@ function validateJoinGeoOptions(method, options) {
|
|
|
43
43
|
function formatReceivedValue(value) {
|
|
44
44
|
return JSON.stringify(value) ?? String(value);
|
|
45
45
|
}
|
|
46
|
-
async function
|
|
46
|
+
async function buildJoinGeoSelect(leftTable, method, rightTable, options) {
|
|
47
47
|
const leftTypes = await leftTable.getTypes();
|
|
48
48
|
const rightTypes = await rightTable.getTypes();
|
|
49
49
|
const leftColumn = options.leftColumn ??
|
|
@@ -83,19 +83,10 @@ async function executeJoinGeo(leftTable, method, rightTable, outputTable, option
|
|
|
83
83
|
]),
|
|
84
84
|
].join(", ");
|
|
85
85
|
const type = options.type ?? "left";
|
|
86
|
-
|
|
87
|
-
table: outputTable.name,
|
|
88
|
-
method: "joinGeo()",
|
|
89
|
-
parameters: {
|
|
90
|
-
leftTable: leftTable.name,
|
|
91
|
-
method,
|
|
92
|
-
rightTable: rightTable.name,
|
|
93
|
-
options,
|
|
94
|
-
},
|
|
95
|
-
}));
|
|
86
|
+
return joinGeoQuery(leftTable.name, leftColumn, method, rightTable.name, rightColumn, type, selectList, options.distance, options.distanceMethod);
|
|
96
87
|
}
|
|
97
|
-
function joinGeoQuery(leftTable, leftColumn, method, rightTable, rightColumn, join,
|
|
98
|
-
let query = `
|
|
88
|
+
function joinGeoQuery(leftTable, leftColumn, method, rightTable, rightColumn, join, selectList, distance, distanceMethod) {
|
|
89
|
+
let query = `SELECT ${selectList}`;
|
|
99
90
|
if (join === "inner") {
|
|
100
91
|
query += ` FROM ${quoteIdentifier(leftTable)} JOIN ${quoteIdentifier(rightTable)}`;
|
|
101
92
|
}
|
|
@@ -112,11 +103,11 @@ function joinGeoQuery(leftTable, leftColumn, method, rightTable, rightColumn, jo
|
|
|
112
103
|
throw new Error(`Unknown ${join} join.`);
|
|
113
104
|
}
|
|
114
105
|
if (method === "intersect") {
|
|
115
|
-
query += ` ON ST_Intersects(${quoteIdentifier(leftTable)}.${quoteIdentifier(leftColumn)}, ${quoteIdentifier(rightTable)}.${quoteIdentifier(rightColumn)})
|
|
106
|
+
query += ` ON ST_Intersects(${quoteIdentifier(leftTable)}.${quoteIdentifier(leftColumn)}, ${quoteIdentifier(rightTable)}.${quoteIdentifier(rightColumn)})`;
|
|
116
107
|
}
|
|
117
108
|
else if (method === "inside") {
|
|
118
109
|
// Order is important
|
|
119
|
-
query += ` ON ST_Covers(${quoteIdentifier(rightTable)}.${quoteIdentifier(rightColumn)}, ${quoteIdentifier(leftTable)}.${quoteIdentifier(leftColumn)})
|
|
110
|
+
query += ` ON ST_Covers(${quoteIdentifier(rightTable)}.${quoteIdentifier(rightColumn)}, ${quoteIdentifier(leftTable)}.${quoteIdentifier(leftColumn)})`;
|
|
120
111
|
}
|
|
121
112
|
else if (method === "withinDistance") {
|
|
122
113
|
if (typeof distance === "number") {
|
|
@@ -2,7 +2,7 @@ import { type DuckDBValue } from "@duckdb/node-api";
|
|
|
2
2
|
import type SimpleTable from "../class/SimpleTable.js";
|
|
3
3
|
export default function loadArray(simpleTable: SimpleTable, rows: {
|
|
4
4
|
[key: string]: unknown;
|
|
5
|
-
}[]): void;
|
|
5
|
+
}[], options?: NonNullable<Parameters<SimpleTable["loadArray"]>[1]>): void;
|
|
6
6
|
type PreparedArray = {
|
|
7
7
|
keys: string[];
|
|
8
8
|
types: string[];
|
|
@@ -11,7 +11,9 @@ type PreparedArray = {
|
|
|
11
11
|
};
|
|
12
12
|
export declare function prepareArray(rows: {
|
|
13
13
|
[key: string]: unknown;
|
|
14
|
-
}[]
|
|
14
|
+
}[], columnTypes?: {
|
|
15
|
+
[key: string]: string;
|
|
16
|
+
}, requireExplicitNestedTypes?: boolean): PreparedArray;
|
|
15
17
|
export declare function executePreparedArray(simpleTable: SimpleTable, prepared: PreparedArray): Promise<void>;
|
|
16
18
|
export {};
|
|
17
19
|
//# sourceMappingURL=loadArray.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadArray.d.ts","sourceRoot":"","sources":["../../src/methods/loadArray.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"loadArray.d.ts","sourceRoot":"","sources":["../../src/methods/loadArray.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,WAAW,EACjB,MAAM,kBAAkB,CAAC;AAK1B,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAKvD,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,EAAE,EAClC,OAAO,GAAE,WAAW,CAAC,UAAU,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAM,QAiBnE;AAED,KAAK,aAAa,GAAG;IACnB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,EAAE,WAAW,EAAE,EAAE,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,YAAY,CAC1B,IAAI,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,EAAE,EAClC,WAAW,GAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAO,EAC3C,0BAA0B,UAAQ,GACjC,aAAa,CAsHf;AAED,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,aAAa,iBA4ExB"}
|
package/esm/methods/loadArray.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import { arrayValue, DuckDBDataChunk, DuckDBTimestampValue, } from "@duckdb/node-api";
|
|
1
|
+
import { arrayValue, DuckDBDataChunk, DuckDBDateValue, DuckDBTimestampTZValue, DuckDBTimestampValue, DuckDBTimeValue, } from "@duckdb/node-api";
|
|
2
|
+
import prepareGeometry from "../helpers/prepareGeometry.js";
|
|
3
|
+
import prepareJSON from "../helpers/prepareJSON.js";
|
|
4
|
+
import geometryFromJSON from "../helpers/geometryFromJSON.js";
|
|
2
5
|
import queueOp from "../helpers/queueOp.js";
|
|
3
6
|
import parseType from "../helpers/parseTypes.js";
|
|
4
7
|
import parseDuckDBType from "../helpers/parseDuckDBType.js";
|
|
5
8
|
import quoteIdentifier from "../helpers/quoteIdentifier.js";
|
|
6
|
-
export default function loadArray(simpleTable, rows) {
|
|
9
|
+
export default function loadArray(simpleTable, rows, options = {}) {
|
|
7
10
|
// This validation doesn't need the database, so it stays at call time.
|
|
8
11
|
if (rows.length === 0) {
|
|
9
12
|
throw new Error("The array is empty. loadArray needs at least one object to infer the column types.");
|
|
10
13
|
}
|
|
11
|
-
const prepared = prepareArray(rows);
|
|
14
|
+
const prepared = prepareArray(rows, options.columnTypes, true);
|
|
12
15
|
queueOp(simpleTable, {
|
|
13
16
|
kind: "barrier",
|
|
14
17
|
method: "loadArray()",
|
|
@@ -16,14 +19,55 @@ export default function loadArray(simpleTable, rows) {
|
|
|
16
19
|
execute: () => executePreparedArray(simpleTable, prepared),
|
|
17
20
|
});
|
|
18
21
|
}
|
|
19
|
-
export function prepareArray(rows) {
|
|
22
|
+
export function prepareArray(rows, columnTypes = {}, requireExplicitNestedTypes = false) {
|
|
20
23
|
const keys = Object.keys(rows[0]);
|
|
24
|
+
const overrides = new Map();
|
|
25
|
+
for (const [key, type] of Object.entries(columnTypes)) {
|
|
26
|
+
if (!keys.includes(key)) {
|
|
27
|
+
throw new Error(`Unknown column ${JSON.stringify(key)} in loadArray columnTypes.`);
|
|
28
|
+
}
|
|
29
|
+
if (type.toUpperCase() === "JSON") {
|
|
30
|
+
overrides.set(key, "JSON");
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (/^geometry/i.test(type)) {
|
|
34
|
+
if (!/^geometry\('EPSG:4326'\)$/i.test(type)) {
|
|
35
|
+
throw new Error(`Unsupported type ${JSON.stringify(type)} for column ${JSON.stringify(key)}. GeoJSON ingestion requires GEOMETRY('EPSG:4326'); reproject input to WGS84 first.`);
|
|
36
|
+
}
|
|
37
|
+
overrides.set(key, "GEOMETRY('EPSG:4326')");
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const normalized = parseType(type);
|
|
42
|
+
parseDuckDBType(normalized);
|
|
43
|
+
overrides.set(key, normalized);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
throw new Error(`Unsupported type ${JSON.stringify(type)} for column ${JSON.stringify(key)}.`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
21
49
|
const firstNonNullValue = keys.map((key) => rows.find((obj) => obj[key] !== null && obj[key] !== undefined)?.[key]);
|
|
22
50
|
const types = [];
|
|
23
51
|
const columnsData = keys.map(() => new Array(rows.length));
|
|
24
52
|
for (let i = 0; i < keys.length; i++) {
|
|
25
53
|
const key = keys[i];
|
|
26
54
|
const columnData = columnsData[i];
|
|
55
|
+
const override = overrides.get(key);
|
|
56
|
+
if (override !== undefined) {
|
|
57
|
+
types[i] = override;
|
|
58
|
+
for (let j = 0; j < rows.length; j++) {
|
|
59
|
+
columnData[j] = prepareTypedValue(rows[j][key], override, key, j + 1);
|
|
60
|
+
}
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (requireExplicitNestedTypes) {
|
|
64
|
+
for (let j = 0; j < rows.length; j++) {
|
|
65
|
+
const cell = rows[j][key];
|
|
66
|
+
if (cell !== null && typeof cell === "object" && !(cell instanceof Date)) {
|
|
67
|
+
throw new Error(`Column ${JSON.stringify(key)}, row ${j + 1}: array and object cells require an explicit columnTypes entry. Use JSON for nested data, FLOAT[n] for fixed-size vectors, or GEOMETRY('EPSG:4326') for GeoJSON geometries.`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
27
71
|
const value = firstNonNullValue[i];
|
|
28
72
|
const type = typeof value;
|
|
29
73
|
if (type === "symbol" || type === "function") {
|
|
@@ -80,19 +124,139 @@ export async function executePreparedArray(simpleTable, prepared) {
|
|
|
80
124
|
simpleTable.connection = simpleTable.sdb.connection;
|
|
81
125
|
}
|
|
82
126
|
const { keys, types, columnsData, rowCount } = prepared;
|
|
83
|
-
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
appender.
|
|
127
|
+
const hasGeometry = types.includes("GEOMETRY('EPSG:4326')");
|
|
128
|
+
const needsConversion = hasGeometry || types.includes("JSON");
|
|
129
|
+
const staged = needsConversion
|
|
130
|
+
? `__sda_array_${crypto.randomUUID().replaceAll("-", "")}`
|
|
131
|
+
: simpleTable.name;
|
|
132
|
+
const storageTypes = types.map((type) => type.startsWith("GEOMETRY") || type === "JSON" ? "VARCHAR" : type);
|
|
133
|
+
if (hasGeometry && !simpleTable.sdb.spatialLoaded) {
|
|
134
|
+
await simpleTable.sdb.customQuery("INSTALL spatial; LOAD spatial; SET geometry_always_xy = true;");
|
|
135
|
+
simpleTable.sdb.spatialLoaded = true;
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
await simpleTable.sdb.customQuery(`CREATE ${needsConversion ? "TEMP" : "OR REPLACE"} TABLE ${quoteIdentifier(staged)}(${keys.map((key, i) => `${quoteIdentifier(key)} ${storageTypes[i]}`).join(", ")})`);
|
|
139
|
+
const appender = await simpleTable.connection
|
|
140
|
+
.createAppender(staged);
|
|
141
|
+
try {
|
|
142
|
+
const duckDBTypes = storageTypes.map((d) => parseDuckDBType(d));
|
|
143
|
+
// The maximum capacity of a DuckDB data chunk is 2048 rows.
|
|
144
|
+
const chunkSize = 2000;
|
|
145
|
+
for (let start = 0; start < rowCount; start += chunkSize) {
|
|
146
|
+
const end = Math.min(start + chunkSize, rowCount);
|
|
147
|
+
const dataChunk = DuckDBDataChunk.create(duckDBTypes, end - start);
|
|
148
|
+
for (let i = 0; i < keys.length; i++) {
|
|
149
|
+
dataChunk.setColumnValues(i, columnsData[i].slice(start, end));
|
|
150
|
+
}
|
|
151
|
+
appender.appendDataChunk(dataChunk);
|
|
152
|
+
}
|
|
153
|
+
appender.flushSync();
|
|
154
|
+
}
|
|
155
|
+
finally {
|
|
156
|
+
appender.closeSync();
|
|
157
|
+
}
|
|
158
|
+
if (!needsConversion)
|
|
159
|
+
return;
|
|
160
|
+
// CTAS is atomic: conversion must finish before the destination is replaced.
|
|
161
|
+
await simpleTable.sdb.customQuery(`CREATE OR REPLACE TABLE ${quoteIdentifier(simpleTable.name)} AS SELECT ${keys.map((key, i) => types[i].startsWith("GEOMETRY")
|
|
162
|
+
? `${geometryFromJSON(quoteIdentifier(key))} AS ${quoteIdentifier(key)}`
|
|
163
|
+
: types[i] === "JSON"
|
|
164
|
+
? `${quoteIdentifier(key)}::JSON AS ${quoteIdentifier(key)}`
|
|
165
|
+
: quoteIdentifier(key)).join(", ")} FROM ${quoteIdentifier(staged)}`);
|
|
166
|
+
}
|
|
167
|
+
finally {
|
|
168
|
+
if (needsConversion) {
|
|
169
|
+
await simpleTable.sdb.customQuery(`DROP TABLE IF EXISTS ${quoteIdentifier(staged)}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/** Validates and snapshots a value for an explicitly declared destination type. */
|
|
174
|
+
function prepareTypedValue(value, type, column, row) {
|
|
175
|
+
if (type === "JSON")
|
|
176
|
+
return prepareJSON(value, column, row);
|
|
177
|
+
if (type === "GEOMETRY('EPSG:4326')") {
|
|
178
|
+
return prepareGeometry(value, column, row);
|
|
179
|
+
}
|
|
180
|
+
if (value === null || value === undefined || Number.isNaN(value))
|
|
181
|
+
return null;
|
|
182
|
+
let compatible = false;
|
|
183
|
+
if (type === "VARCHAR" && typeof value === "string")
|
|
184
|
+
return value;
|
|
185
|
+
if (type === "BOOLEAN" && typeof value === "boolean")
|
|
186
|
+
return value;
|
|
187
|
+
if (type === "DOUBLE") {
|
|
188
|
+
if (typeof value === "number")
|
|
189
|
+
return value;
|
|
190
|
+
compatible = typeof value === "bigint";
|
|
191
|
+
if (typeof value === "bigint") {
|
|
192
|
+
const number = Number(value);
|
|
193
|
+
if (Number.isFinite(number) && BigInt(number) === value)
|
|
194
|
+
return number;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else if (type === "INTEGER") {
|
|
198
|
+
compatible = typeof value === "number" || typeof value === "bigint";
|
|
199
|
+
if (typeof value === "number") {
|
|
200
|
+
if (Number.isInteger(value) && value >= -2147483648 && value <= 2147483647) {
|
|
201
|
+
return value;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
else if (typeof value === "bigint" && value >= -2147483648n && value <= 2147483647n) {
|
|
205
|
+
return Number(value);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
else if (type === "BIGINT") {
|
|
209
|
+
compatible = typeof value === "number" || typeof value === "bigint";
|
|
210
|
+
if (typeof value === "bigint") {
|
|
211
|
+
if (value >= -9223372036854775808n && value <= 9223372036854775807n) {
|
|
212
|
+
return value;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
else if (typeof value === "number" && Number.isInteger(value) &&
|
|
216
|
+
value >= -(2 ** 63) && value < 2 ** 63) {
|
|
217
|
+
// The upper bound is exclusive: 2 ** 63 - 1 rounds up as a JS number.
|
|
218
|
+
return BigInt(value);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
else if (["DATE", "TIME", "TIMESTAMP", "TIMESTAMP WITH TIME ZONE"].includes(type)) {
|
|
222
|
+
if (type === "TIME" && value instanceof DuckDBTimeValue) {
|
|
223
|
+
if (value.micros >= 0n && value.micros <= 86400000000n) {
|
|
224
|
+
return new DuckDBTimeValue(value.micros);
|
|
225
|
+
}
|
|
226
|
+
compatible = true;
|
|
227
|
+
}
|
|
228
|
+
else if (value instanceof Date) {
|
|
229
|
+
const millis = value.getTime();
|
|
230
|
+
compatible = Number.isFinite(millis);
|
|
231
|
+
if (compatible) {
|
|
232
|
+
if (type === "DATE" && millis % 86400000 === 0) {
|
|
233
|
+
return new DuckDBDateValue(millis / 86400000);
|
|
234
|
+
}
|
|
235
|
+
const micros = BigInt(millis) * 1000n;
|
|
236
|
+
if (type === "TIMESTAMP")
|
|
237
|
+
return new DuckDBTimestampValue(micros);
|
|
238
|
+
if (type === "TIMESTAMP WITH TIME ZONE") {
|
|
239
|
+
return new DuckDBTimestampTZValue(micros);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
else if (type.startsWith("FLOAT[") && Array.isArray(value)) {
|
|
245
|
+
compatible = true;
|
|
246
|
+
const size = Number(type.slice(6, -1));
|
|
247
|
+
if (value.length === size &&
|
|
248
|
+
value.every((item) => item === null || item === undefined ||
|
|
249
|
+
(typeof item === "number" &&
|
|
250
|
+
(Number.isNaN(item) || Math.fround(item) === item)))) {
|
|
251
|
+
return arrayValue(value.map((item) => item === undefined || Number.isNaN(item)
|
|
252
|
+
? null
|
|
253
|
+
: item));
|
|
254
|
+
}
|
|
96
255
|
}
|
|
97
|
-
|
|
256
|
+
const displayed = typeof value === "string"
|
|
257
|
+
? JSON.stringify(value)
|
|
258
|
+
: String(value);
|
|
259
|
+
throw new Error(`Column ${JSON.stringify(column)}, row ${row}: value ${displayed} ${compatible
|
|
260
|
+
? `cannot be stored as ${type} without losing information`
|
|
261
|
+
: `is incompatible with ${type}`}. Select a type compatible with this value.`);
|
|
98
262
|
}
|
package/esm/methods/loadData.js
CHANGED
|
@@ -47,6 +47,9 @@ export function loadDataQuery(table, files, options = {}) {
|
|
|
47
47
|
return `CREATE OR REPLACE TABLE ${quoteIdentifier(table)} AS ${loadDataSelect(files, options)};`;
|
|
48
48
|
}
|
|
49
49
|
function loadDataSelect(files, options = {}) {
|
|
50
|
+
if (Object.values(options.columnTypes ?? {}).some((type) => /^\s*geometry\b/i.test(type))) {
|
|
51
|
+
throw new Error("Geometry column types are not supported by loadData(). Use loadGeoData() instead.");
|
|
52
|
+
}
|
|
50
53
|
const fileExtension = getExtension(files[0]);
|
|
51
54
|
if (options.fileType !== undefined &&
|
|
52
55
|
!["csv", "dsv", "json", "parquet", "excel"].includes(options.fileType)) {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type SimpleTable from "../class/SimpleTable.js";
|
|
2
|
+
declare const INTERVAL_SECONDS: {
|
|
3
|
+
readonly "1d": number;
|
|
4
|
+
readonly "1h": number;
|
|
5
|
+
readonly "1m": 60;
|
|
6
|
+
};
|
|
7
|
+
type YahooInterval = keyof typeof INTERVAL_SECONDS;
|
|
8
|
+
export default function loadYahooFinanceData(table: SimpleTable, symbol: string, startDate: Date, endDate: Date, interval: YahooInterval): void;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=loadYahooFinanceData.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadYahooFinanceData.d.ts","sourceRoot":"","sources":["../../src/methods/loadYahooFinanceData.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAKvD,QAAA,MAAM,gBAAgB;;;;CAIZ,CAAC;AAeX,KAAK,aAAa,GAAG,MAAM,OAAO,gBAAgB,CAAC;AA6BnD,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAC1C,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,IAAI,EACf,OAAO,EAAE,IAAI,EACb,QAAQ,EAAE,aAAa,GACtB,IAAI,CAeN"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import SDAError from "../class/SDAError.js";
|
|
2
|
+
import queueOp from "../helpers/queueOp.js";
|
|
3
|
+
import { executePreparedArray, prepareArray } from "./loadArray.js";
|
|
4
|
+
const INTERVAL_SECONDS = {
|
|
5
|
+
"1d": 24 * 60 * 60,
|
|
6
|
+
"1h": 60 * 60,
|
|
7
|
+
"1m": 60,
|
|
8
|
+
};
|
|
9
|
+
const COLUMN_TYPES = {
|
|
10
|
+
datetime: "TIMESTAMP",
|
|
11
|
+
open: "DOUBLE",
|
|
12
|
+
high: "DOUBLE",
|
|
13
|
+
low: "DOUBLE",
|
|
14
|
+
close: "DOUBLE",
|
|
15
|
+
adjustedClose: "DOUBLE",
|
|
16
|
+
volume: "DOUBLE",
|
|
17
|
+
};
|
|
18
|
+
const USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36";
|
|
19
|
+
export default function loadYahooFinanceData(table, symbol, startDate, endDate, interval) {
|
|
20
|
+
assertArguments(symbol, startDate, endDate, interval);
|
|
21
|
+
const request = {
|
|
22
|
+
symbol,
|
|
23
|
+
startDate: new Date(startDate),
|
|
24
|
+
endDate: new Date(endDate),
|
|
25
|
+
interval,
|
|
26
|
+
};
|
|
27
|
+
queueOp(table, {
|
|
28
|
+
kind: "barrier",
|
|
29
|
+
method: "loadYahooFinanceData()",
|
|
30
|
+
parameters: request,
|
|
31
|
+
execute: () => executeLoadYahooFinanceData(table, request),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async function executeLoadYahooFinanceData(table, request) {
|
|
35
|
+
try {
|
|
36
|
+
const rows = await getYahooFinanceData(request);
|
|
37
|
+
await executePreparedArray(table, prepareArray(rows, COLUMN_TYPES));
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (error instanceof SDAError) {
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
throw new SDAError({
|
|
44
|
+
method: "loadYahooFinanceData()",
|
|
45
|
+
parameters: request,
|
|
46
|
+
query: "",
|
|
47
|
+
cause: error,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function getYahooFinanceData(request) {
|
|
52
|
+
const { symbol, startDate, endDate, interval } = request;
|
|
53
|
+
const startTime = startDate.getTime();
|
|
54
|
+
const exclusiveEndTime = getExclusiveEndTime(endDate, interval);
|
|
55
|
+
const url = new URL(`https://query1.finance.yahoo.com/v8/finance/chart/${encodeURIComponent(symbol)}`);
|
|
56
|
+
url.search = new URLSearchParams({
|
|
57
|
+
includeAdjustedClose: "true",
|
|
58
|
+
interval,
|
|
59
|
+
period1: String(Math.floor(startTime / 1000)),
|
|
60
|
+
period2: String(Math.ceil(exclusiveEndTime / 1000)),
|
|
61
|
+
}).toString();
|
|
62
|
+
const response = await fetch(url, {
|
|
63
|
+
headers: { "User-Agent": USER_AGENT },
|
|
64
|
+
});
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
const text = (await response.text()).slice(0, 500).trim();
|
|
67
|
+
throw new Error(`Failed to fetch Yahoo Finance data: ${response.status} ${response.statusText}${text.length > 0 ? `. ${text}` : ""}. Yahoo may have changed, rate-limited, or disabled this undocumented endpoint.`);
|
|
68
|
+
}
|
|
69
|
+
const data = await response.json();
|
|
70
|
+
if (data.chart?.error) {
|
|
71
|
+
throw new Error(data.chart.error.description ??
|
|
72
|
+
"Yahoo Finance returned an unknown error.");
|
|
73
|
+
}
|
|
74
|
+
const result = data.chart?.result?.[0];
|
|
75
|
+
const timestamps = result?.timestamp;
|
|
76
|
+
if (!result || !timestamps?.length) {
|
|
77
|
+
throw new Error("No Yahoo Finance data found.");
|
|
78
|
+
}
|
|
79
|
+
const quote = result.indicators?.quote?.[0];
|
|
80
|
+
const adjustedClose = result.indicators?.adjclose?.[0]?.adjclose;
|
|
81
|
+
const rows = [];
|
|
82
|
+
for (let index = 0; index < timestamps.length; index++) {
|
|
83
|
+
const timestamp = timestamps[index] * 1000;
|
|
84
|
+
if (Number.isFinite(timestamp) && timestamp >= startTime &&
|
|
85
|
+
timestamp < exclusiveEndTime) {
|
|
86
|
+
rows.push({
|
|
87
|
+
datetime: new Date(timestamp),
|
|
88
|
+
open: getFiniteValue(quote?.open, index),
|
|
89
|
+
high: getFiniteValue(quote?.high, index),
|
|
90
|
+
low: getFiniteValue(quote?.low, index),
|
|
91
|
+
close: getFiniteValue(quote?.close, index),
|
|
92
|
+
adjustedClose: getFiniteValue(adjustedClose, index),
|
|
93
|
+
volume: getFiniteValue(quote?.volume, index),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (rows.length === 0) {
|
|
98
|
+
throw new Error(`No Yahoo Finance data found for ${symbol}.`);
|
|
99
|
+
}
|
|
100
|
+
return rows;
|
|
101
|
+
}
|
|
102
|
+
function getFiniteValue(values, index) {
|
|
103
|
+
const value = values?.[index];
|
|
104
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
105
|
+
}
|
|
106
|
+
function getExclusiveEndTime(endDate, interval) {
|
|
107
|
+
const end = new Date(endDate);
|
|
108
|
+
if (interval === "1d") {
|
|
109
|
+
end.setUTCHours(0, 0, 0, 0);
|
|
110
|
+
}
|
|
111
|
+
else if (interval === "1h") {
|
|
112
|
+
end.setUTCMinutes(0, 0, 0);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
end.setUTCSeconds(0, 0);
|
|
116
|
+
}
|
|
117
|
+
return end.getTime() + INTERVAL_SECONDS[interval] * 1000;
|
|
118
|
+
}
|
|
119
|
+
function assertArguments(symbol, startDate, endDate, interval) {
|
|
120
|
+
if (typeof symbol !== "string" || symbol.trim().length === 0) {
|
|
121
|
+
throw new TypeError("loadYahooFinanceData() symbol must be a non-empty string.");
|
|
122
|
+
}
|
|
123
|
+
if (!(startDate instanceof Date) || !(endDate instanceof Date) ||
|
|
124
|
+
!Number.isFinite(startDate.getTime()) || !Number.isFinite(endDate.getTime())) {
|
|
125
|
+
throw new RangeError("loadYahooFinanceData() startDate and endDate must be valid dates.");
|
|
126
|
+
}
|
|
127
|
+
if (endDate.getTime() < startDate.getTime()) {
|
|
128
|
+
throw new RangeError("loadYahooFinanceData() endDate must be equal to or later than startDate.");
|
|
129
|
+
}
|
|
130
|
+
if (interval !== "1d" && interval !== "1h" && interval !== "1m") {
|
|
131
|
+
throw new Error('loadYahooFinanceData() interval must be "1d", "1h", or "1m".');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/methods/log.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAMvD,wBAA8B,GAAG,CAC/B,WAAW,EAAE,WAAW,EACxB,OAAO,GAAE,KAAK,GAAG,MAAM,GAAG;IACxB,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CAChB,iBAyEP"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import logData from "../helpers/logData.js";
|
|
2
|
+
import getData from "./getData.js";
|
|
3
|
+
import quoteIdentifier from "../helpers/quoteIdentifier.js";
|
|
4
|
+
import formatNumber from "../helpers/formatNumber.js";
|
|
5
|
+
export default async function log(simpleTable, options = {}) {
|
|
6
|
+
if (simpleTable.connection === undefined) {
|
|
7
|
+
await simpleTable.sdb.start();
|
|
8
|
+
simpleTable.db = simpleTable.sdb.db;
|
|
9
|
+
simpleTable.connection = simpleTable.sdb.connection;
|
|
10
|
+
}
|
|
11
|
+
if (simpleTable.connection === undefined) {
|
|
12
|
+
throw new Error("simpleTable.connection is undefined");
|
|
13
|
+
}
|
|
14
|
+
let count;
|
|
15
|
+
if (typeof options === "number") {
|
|
16
|
+
count = options;
|
|
17
|
+
}
|
|
18
|
+
else if (options === "all") {
|
|
19
|
+
count = await simpleTable.getRowCount();
|
|
20
|
+
}
|
|
21
|
+
else if (typeof options === "object") {
|
|
22
|
+
if (options.count === "all") {
|
|
23
|
+
count = await simpleTable.getRowCount();
|
|
24
|
+
}
|
|
25
|
+
else if (typeof options.count === "number") {
|
|
26
|
+
count = options.count;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
count = simpleTable.rowsToLog;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
count = simpleTable.rowsToLog;
|
|
34
|
+
}
|
|
35
|
+
const types = typeof options === "object"
|
|
36
|
+
? options.types ?? simpleTable.typesToLog
|
|
37
|
+
: simpleTable.typesToLog;
|
|
38
|
+
const conditions = typeof options === "object"
|
|
39
|
+
? options.conditions ?? undefined
|
|
40
|
+
: undefined;
|
|
41
|
+
if (simpleTable.connection === undefined ||
|
|
42
|
+
!(await simpleTable.sdb.hasTable(simpleTable.name))) {
|
|
43
|
+
console.log(`\nTable ${simpleTable.name}: no data`);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
console.log(`\nTable ${simpleTable.name}:`);
|
|
47
|
+
conditions && console.log(`Conditions: ${conditions}`);
|
|
48
|
+
const data = await getData(simpleTable, { limit: count, conditions }, "log()");
|
|
49
|
+
logData(types ? await simpleTable.getTypes() : null, data, simpleTable.charsToLog);
|
|
50
|
+
const rowCount = conditions
|
|
51
|
+
? parseInt((await simpleTable.sdb.customQuery(`select count(*) as count from ${quoteIdentifier(simpleTable.name)} where ${conditions}`, { returnData: true }))[0].count)
|
|
52
|
+
: await simpleTable.getRowCount();
|
|
53
|
+
console.log(`${formatNumber(rowCount)} rows in total ${`(count: ${count}${typeof simpleTable.charsToLog === "number"
|
|
54
|
+
? `, charsToLog: ${simpleTable.charsToLog}`
|
|
55
|
+
: ""})`}`);
|
|
56
|
+
}
|
|
57
|
+
return;
|
|
58
|
+
}
|