sqlmath 2023.12.20 → 2024.3.25
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/CHANGELOG.md +12 -0
- package/README.md +5 -5
- package/jslint.mjs +12 -6
- package/package.json +1 -1
- package/sqlmath.mjs +285 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@
|
|
|
4
4
|
- sqlmath - Add sqlite-extension for lightgbm.
|
|
5
5
|
- none
|
|
6
6
|
|
|
7
|
+
# v2024.3.25
|
|
8
|
+
- jslint-ci - Add shell-functions shGitPullrequestCleanup(), shGitPullrequest() to automatically cleanup or create-and-push github-pull-commit to origin/alpha.
|
|
9
|
+
- ci - Fix tmpdir in shell-function shBrowserScreenshot().
|
|
10
|
+
- webdemo - Update tables tradebot_intraday_xxx.
|
|
11
|
+
- migration - Rename prm ydate to xdate, ytime to xtime.
|
|
12
|
+
- sqlmath - Move function dbTableImportAsync from file sqlmath_browser.mjs to sqlmath.mjs.
|
|
13
|
+
- ci - Update github-ci for actions/cache, actions/setup-python from nodejs v16 to nodejs v20.
|
|
14
|
+
- ci - Update shell-function shRollupFetch() to fix blank date-committed.
|
|
15
|
+
|
|
16
|
+
# v2024.1.21
|
|
17
|
+
- sqlmath - Add function assertErrorThrownAsync().
|
|
18
|
+
|
|
7
19
|
# v2023.12.20
|
|
8
20
|
- chart - Improve ergonomics with import tsv.
|
|
9
21
|
- betadog - bugfix - Remove over-complicated prm ttt from table y_historical.
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
# Status
|
|
5
|
-
| Branch | [master<br>(
|
|
5
|
+
| Branch | [master<br>(v2024.3.25)](https://github.com/sqlmath/sqlmath/tree/master) | [beta<br>(Web Demo)](https://github.com/sqlmath/sqlmath/tree/beta) | [alpha<br>(Development)](https://github.com/sqlmath/sqlmath/tree/alpha) |
|
|
6
6
|
|--:|:--:|:--:|:--:|
|
|
7
7
|
| CI | [](https://github.com/sqlmath/sqlmath/actions?query=branch%3Amaster) | [](https://github.com/sqlmath/sqlmath/actions?query=branch%3Abeta) | [](https://github.com/sqlmath/sqlmath/actions?query=branch%3Aalpha) |
|
|
8
8
|
| Coverage | [](https://sqlmath.github.io/sqlmath/branch-master/.artifact/coverage/index.html) | [](https://sqlmath.github.io/sqlmath/branch-beta/.artifact/coverage/index.html) | [](https://sqlmath.github.io/sqlmath/branch-alpha/.artifact/coverage/index.html) |
|
|
@@ -122,11 +122,11 @@ PORT=8080 sh jslint_ci.sh shHttpFileServer
|
|
|
122
122
|
```shell
|
|
123
123
|
python -m build
|
|
124
124
|
#
|
|
125
|
-
twine upload --repository testpypi dist/sqlmath-
|
|
126
|
-
py -m pip install --index-url https://test.pypi.org/simple/ sqlmath==
|
|
125
|
+
twine upload --repository testpypi dist/sqlmath-2024.3.25*
|
|
126
|
+
py -m pip install --index-url https://test.pypi.org/simple/ sqlmath==2024.3.25
|
|
127
127
|
#
|
|
128
|
-
twine upload dist/sqlmath-
|
|
129
|
-
pip install sqlmath==
|
|
128
|
+
twine upload dist/sqlmath-2024.3.25*
|
|
129
|
+
pip install sqlmath==2024.3.25
|
|
130
130
|
```
|
|
131
131
|
|
|
132
132
|
|
package/jslint.mjs
CHANGED
|
@@ -163,7 +163,7 @@ let jslint_charset_ascii = (
|
|
|
163
163
|
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
|
|
164
164
|
+ "`abcdefghijklmnopqrstuvwxyz{|}~\u007f"
|
|
165
165
|
);
|
|
166
|
-
let jslint_edition = "
|
|
166
|
+
let jslint_edition = "v2024.3.1-beta";
|
|
167
167
|
let jslint_export; // The jslint object to be exported.
|
|
168
168
|
let jslint_fudge = 1; // Fudge starting line and starting
|
|
169
169
|
// ... column to 1.
|
|
@@ -5487,13 +5487,15 @@ function jslint_phase3_parse(state) {
|
|
|
5487
5487
|
if (
|
|
5488
5488
|
token_nxt.id === "."
|
|
5489
5489
|
|| token_nxt.id === "?."
|
|
5490
|
-
|
|
5490
|
+
|
|
5491
|
+
// PR-459 - Allow destructuring-assignment after function-definition.
|
|
5492
|
+
|
|
5493
|
+
// || token_nxt.id === "["
|
|
5491
5494
|
) {
|
|
5492
5495
|
|
|
5493
5496
|
// test_cause:
|
|
5494
5497
|
// ["function aa(){}\n.aa", "prefix_function", "unexpected_a", ".", 1]
|
|
5495
5498
|
// ["function aa(){}\n?.aa", "prefix_function", "unexpected_a", "?.", 1]
|
|
5496
|
-
// ["function aa(){}\n[]", "prefix_function", "unexpected_a", "[", 1]
|
|
5497
5499
|
|
|
5498
5500
|
warn("unexpected_a");
|
|
5499
5501
|
}
|
|
@@ -9952,6 +9954,12 @@ async function jstestDescribe(description, testFunction) {
|
|
|
9952
9954
|
process.on("exit", jstestOnExit);
|
|
9953
9955
|
}
|
|
9954
9956
|
|
|
9957
|
+
// PR-457 - Wait awhile for imports to initialize.
|
|
9958
|
+
|
|
9959
|
+
await new Promise(function (resolve) {
|
|
9960
|
+
setTimeout(resolve);
|
|
9961
|
+
});
|
|
9962
|
+
|
|
9955
9963
|
// Init jstestItList.
|
|
9956
9964
|
|
|
9957
9965
|
jstestItList = [];
|
|
@@ -10005,9 +10013,7 @@ function jstestIt(description, testFunction, mode) {
|
|
|
10005
10013
|
} catch (errCaught) {
|
|
10006
10014
|
err = errCaught;
|
|
10007
10015
|
}
|
|
10008
|
-
resolve([
|
|
10009
|
-
err, description, mode
|
|
10010
|
-
]);
|
|
10016
|
+
resolve([err, description, mode]);
|
|
10011
10017
|
}));
|
|
10012
10018
|
}
|
|
10013
10019
|
|
package/package.json
CHANGED
package/sqlmath.mjs
CHANGED
|
@@ -104,7 +104,24 @@ let {
|
|
|
104
104
|
let sqlMessageDict = {}; // dict of web-worker-callbacks
|
|
105
105
|
let sqlMessageId = 0;
|
|
106
106
|
let sqlWorker;
|
|
107
|
-
let version = "
|
|
107
|
+
let version = "v2024.3.25";
|
|
108
|
+
|
|
109
|
+
async function assertErrorThrownAsync(asyncFunc, regexp) {
|
|
110
|
+
|
|
111
|
+
// This function will assert calling <asyncFunc> throws an error.
|
|
112
|
+
|
|
113
|
+
let err;
|
|
114
|
+
try {
|
|
115
|
+
await asyncFunc();
|
|
116
|
+
} catch (errCaught) {
|
|
117
|
+
err = errCaught;
|
|
118
|
+
}
|
|
119
|
+
assertOrThrow(err, "No error thrown.");
|
|
120
|
+
assertOrThrow(
|
|
121
|
+
!regexp || new RegExp(regexp).test(err.message),
|
|
122
|
+
err
|
|
123
|
+
);
|
|
124
|
+
}
|
|
108
125
|
|
|
109
126
|
function assertInt64(val) {
|
|
110
127
|
// This function will assert <val> is within range of c99-signed-long-long.
|
|
@@ -758,7 +775,8 @@ async function dbFileLoadAsync({
|
|
|
758
775
|
async function dbFileSaveAsync({
|
|
759
776
|
db,
|
|
760
777
|
dbData,
|
|
761
|
-
filename
|
|
778
|
+
filename,
|
|
779
|
+
modeNoop
|
|
762
780
|
}) {
|
|
763
781
|
|
|
764
782
|
// This function will save <db> to <filename>.
|
|
@@ -767,6 +785,7 @@ async function dbFileSaveAsync({
|
|
|
767
785
|
db,
|
|
768
786
|
dbData,
|
|
769
787
|
filename,
|
|
788
|
+
modeNoop,
|
|
770
789
|
modeSave: 1
|
|
771
790
|
});
|
|
772
791
|
}
|
|
@@ -829,6 +848,117 @@ async function dbOpenAsync({
|
|
|
829
848
|
return db;
|
|
830
849
|
}
|
|
831
850
|
|
|
851
|
+
async function dbTableImportAsync({
|
|
852
|
+
db,
|
|
853
|
+
mode,
|
|
854
|
+
tableName,
|
|
855
|
+
textData
|
|
856
|
+
}) {
|
|
857
|
+
// this function will create table from imported csv/json <textData>
|
|
858
|
+
let colList;
|
|
859
|
+
let rowList;
|
|
860
|
+
let rowidList;
|
|
861
|
+
let tmp;
|
|
862
|
+
switch (mode) {
|
|
863
|
+
case "csv":
|
|
864
|
+
rowList = jsonRowListFromCsv({
|
|
865
|
+
csv: textData
|
|
866
|
+
});
|
|
867
|
+
break;
|
|
868
|
+
case "tsv":
|
|
869
|
+
rowList = [];
|
|
870
|
+
textData.trimEnd().replace((/.+/g), function (line) {
|
|
871
|
+
rowList.push(line.split("\t"));
|
|
872
|
+
});
|
|
873
|
+
break;
|
|
874
|
+
// case "json":
|
|
875
|
+
default:
|
|
876
|
+
rowList = JSON.parse(textData);
|
|
877
|
+
}
|
|
878
|
+
if (!(typeof rowList === "object" && rowList)) {
|
|
879
|
+
rowList = [];
|
|
880
|
+
}
|
|
881
|
+
// normalize rowList to list
|
|
882
|
+
if (!Array.isArray(rowList)) {
|
|
883
|
+
rowidList = [];
|
|
884
|
+
rowList = Object.entries(rowList).map(function ([
|
|
885
|
+
key, val
|
|
886
|
+
]) {
|
|
887
|
+
rowidList.push(key);
|
|
888
|
+
return val;
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
// normalize rowList[ii] to list
|
|
892
|
+
if (rowList.length === 0) {
|
|
893
|
+
rowList.push([
|
|
894
|
+
"undefined"
|
|
895
|
+
]);
|
|
896
|
+
}
|
|
897
|
+
if (!Array.isArray(rowList[0])) {
|
|
898
|
+
colList = Array.from(
|
|
899
|
+
new Set(
|
|
900
|
+
rowList.map(function (obj) {
|
|
901
|
+
return Object.keys(obj);
|
|
902
|
+
}).flat()
|
|
903
|
+
)
|
|
904
|
+
);
|
|
905
|
+
rowList = rowList.map(function (obj) {
|
|
906
|
+
return colList.map(function (key) {
|
|
907
|
+
return obj[key];
|
|
908
|
+
});
|
|
909
|
+
});
|
|
910
|
+
rowList.unshift(colList);
|
|
911
|
+
}
|
|
912
|
+
// init colList
|
|
913
|
+
colList = rowList.shift();
|
|
914
|
+
// preserve rowid
|
|
915
|
+
if (rowidList) {
|
|
916
|
+
colList.unshift("rowid");
|
|
917
|
+
rowList.forEach(function (row, ii) {
|
|
918
|
+
row.unshift(rowidList[ii]);
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
// normalize colList
|
|
922
|
+
tmp = new Set();
|
|
923
|
+
colList = colList.map(function (colName) {
|
|
924
|
+
let colName2;
|
|
925
|
+
let duplicate = 0;
|
|
926
|
+
colName = "c_" + colName.toLowerCase().replace((
|
|
927
|
+
/\W/g
|
|
928
|
+
), "_");
|
|
929
|
+
while (true) {
|
|
930
|
+
duplicate += 1;
|
|
931
|
+
colName2 = (
|
|
932
|
+
duplicate === 1
|
|
933
|
+
? colName
|
|
934
|
+
: colName + "_" + duplicate
|
|
935
|
+
);
|
|
936
|
+
if (!tmp.has(colName2)) {
|
|
937
|
+
tmp.add(colName2);
|
|
938
|
+
return colName2;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
});
|
|
942
|
+
// create dbtable from rowList
|
|
943
|
+
await dbExecAsync({
|
|
944
|
+
bindList: {
|
|
945
|
+
rowList: JSON.stringify(rowList)
|
|
946
|
+
},
|
|
947
|
+
db,
|
|
948
|
+
sql: (
|
|
949
|
+
rowList.length === 0
|
|
950
|
+
? `CREATE TABLE ${tableName} (${colList.join(",")});`
|
|
951
|
+
: (
|
|
952
|
+
`CREATE TABLE ${tableName} AS SELECT `
|
|
953
|
+
+ colList.map(function (colName, ii) {
|
|
954
|
+
return "value->>" + ii + " AS " + colName;
|
|
955
|
+
}).join(",")
|
|
956
|
+
+ " FROM JSON_EACH($rowList);"
|
|
957
|
+
)
|
|
958
|
+
)
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
|
|
832
962
|
async function fsCopyFileUnlessTest(file1, file2, mode) {
|
|
833
963
|
|
|
834
964
|
// This function will copy <file1> to <file2> unless <npm_config_mode_test> = 1.
|
|
@@ -1150,6 +1280,157 @@ function jsonParseArraybuffer(buf) {
|
|
|
1150
1280
|
);
|
|
1151
1281
|
}
|
|
1152
1282
|
|
|
1283
|
+
function jsonRowListFromCsv({
|
|
1284
|
+
csv
|
|
1285
|
+
}) {
|
|
1286
|
+
// this function will convert <csv>-text to json list-of-list
|
|
1287
|
+
//
|
|
1288
|
+
// https://tools.ietf.org/html/rfc4180#section-2
|
|
1289
|
+
// Definition of the CSV Format
|
|
1290
|
+
// While there are various specifications and implementations for the
|
|
1291
|
+
// CSV format (for ex. [4], [5], [6] and [7]), there is no formal
|
|
1292
|
+
// specification in existence, which allows for a wide variety of
|
|
1293
|
+
// interpretations of CSV files. This section documents the format that
|
|
1294
|
+
// seems to be followed by most implementations:
|
|
1295
|
+
//
|
|
1296
|
+
// 1. Each record is located on a separate line, delimited by a line
|
|
1297
|
+
// break (CRLF). For example:
|
|
1298
|
+
// aaa,bbb,ccc CRLF
|
|
1299
|
+
// zzz,yyy,xxx CRLF
|
|
1300
|
+
//
|
|
1301
|
+
// 2. The last record in the file may or may not have an ending line
|
|
1302
|
+
// break. For example:
|
|
1303
|
+
// aaa,bbb,ccc CRLF
|
|
1304
|
+
// zzz,yyy,xxx
|
|
1305
|
+
//
|
|
1306
|
+
// 3. There maybe an optional header line appearing as the first line
|
|
1307
|
+
// of the file with the same format as normal record lines. This
|
|
1308
|
+
// header will contain names corresponding to the fields in the file
|
|
1309
|
+
// and should contain the same number of fields as the records in
|
|
1310
|
+
// the rest of the file (the presence or absence of the header line
|
|
1311
|
+
// should be indicated via the optional "header" parameter of this
|
|
1312
|
+
// MIME type). For example:
|
|
1313
|
+
// field_name,field_name,field_name CRLF
|
|
1314
|
+
// aaa,bbb,ccc CRLF
|
|
1315
|
+
// zzz,yyy,xxx CRLF
|
|
1316
|
+
//
|
|
1317
|
+
// 4. Within the header and each record, there may be one or more
|
|
1318
|
+
// fields, separated by commas. Each line should contain the same
|
|
1319
|
+
// number of fields throughout the file. Spaces are considered part
|
|
1320
|
+
// of a field and should not be ignored. The last field in the
|
|
1321
|
+
// record must not be followed by a comma. For example:
|
|
1322
|
+
// aaa,bbb,ccc
|
|
1323
|
+
//
|
|
1324
|
+
// 5. Each field may or may not be enclosed in double quotes (however
|
|
1325
|
+
// some programs, such as Microsoft Excel, do not use double quotes
|
|
1326
|
+
// at all). If fields are not enclosed with double quotes, then
|
|
1327
|
+
// double quotes may not appear inside the fields. For example:
|
|
1328
|
+
// "aaa","bbb","ccc" CRLF
|
|
1329
|
+
// zzz,yyy,xxx
|
|
1330
|
+
//
|
|
1331
|
+
// 6. Fields containing line breaks (CRLF), double quotes, and commas
|
|
1332
|
+
// should be enclosed in double-quotes. For example:
|
|
1333
|
+
// "aaa","b CRLF
|
|
1334
|
+
// bb","ccc" CRLF
|
|
1335
|
+
// zzz,yyy,xxx
|
|
1336
|
+
//
|
|
1337
|
+
// 7. If double-quotes are used to enclose fields, then a double-quote
|
|
1338
|
+
// appearing inside a field must be escaped by preceding it with
|
|
1339
|
+
// another double quote. For example:
|
|
1340
|
+
// "aaa","b""bb","ccc"
|
|
1341
|
+
let match;
|
|
1342
|
+
let quote;
|
|
1343
|
+
let rgx;
|
|
1344
|
+
let row;
|
|
1345
|
+
let rowList;
|
|
1346
|
+
let val;
|
|
1347
|
+
// normalize "\r\n" to "\n"
|
|
1348
|
+
csv = csv.trimEnd().replace((
|
|
1349
|
+
/\r\n?/gu
|
|
1350
|
+
), "\n") + "\n";
|
|
1351
|
+
rgx = (
|
|
1352
|
+
/(.*?)(""|"|,|\n)/gu
|
|
1353
|
+
);
|
|
1354
|
+
rowList = [];
|
|
1355
|
+
// reset row
|
|
1356
|
+
row = [];
|
|
1357
|
+
val = "";
|
|
1358
|
+
while (true) {
|
|
1359
|
+
match = rgx.exec(csv);
|
|
1360
|
+
if (!match) {
|
|
1361
|
+
// 2. The last record in the file may or may not have an ending line
|
|
1362
|
+
// break. For example:
|
|
1363
|
+
// aaa,bbb,ccc CRLF
|
|
1364
|
+
// zzz,yyy,xxx
|
|
1365
|
+
if (!row.length) {
|
|
1366
|
+
break;
|
|
1367
|
+
}
|
|
1368
|
+
// // if eof missing crlf, then mock it
|
|
1369
|
+
// rgx.lastIndex = csv.length;
|
|
1370
|
+
// match = [
|
|
1371
|
+
// "\n", "", "\n"
|
|
1372
|
+
// ];
|
|
1373
|
+
}
|
|
1374
|
+
// build val
|
|
1375
|
+
val += match[1];
|
|
1376
|
+
if (match[2] === "\"") {
|
|
1377
|
+
// 5. Each field may or may not be enclosed in double quotes (however
|
|
1378
|
+
// some programs, such as Microsoft Excel, do not use double quotes
|
|
1379
|
+
// at all). If fields are not enclosed with double quotes, then
|
|
1380
|
+
// double quotes may not appear inside the fields. For example:
|
|
1381
|
+
// "aaa","bbb","ccc" CRLF
|
|
1382
|
+
// zzz,yyy,xxx
|
|
1383
|
+
quote = !quote;
|
|
1384
|
+
} else if (quote) {
|
|
1385
|
+
// 7. If double-quotes are used to enclose fields, then a double-quote
|
|
1386
|
+
// appearing inside a field must be escaped by preceding it with
|
|
1387
|
+
// another double quote. For example:
|
|
1388
|
+
// "aaa","b""bb","ccc"
|
|
1389
|
+
if (match[2] === "\"\"") {
|
|
1390
|
+
val += "\"";
|
|
1391
|
+
// 6. Fields containing line breaks (CRLF), double quotes, and commas
|
|
1392
|
+
// should be enclosed in double-quotes. For example:
|
|
1393
|
+
// "aaa","b CRLF
|
|
1394
|
+
// bb","ccc" CRLF
|
|
1395
|
+
// zzz,yyy,xxx
|
|
1396
|
+
} else {
|
|
1397
|
+
val += match[2];
|
|
1398
|
+
}
|
|
1399
|
+
} else if (match[2] === ",") {
|
|
1400
|
+
// 4. Within the header and each record, there may be one or more
|
|
1401
|
+
// fields, separated by commas. Each line should contain the same
|
|
1402
|
+
// number of fields throughout the file. Spaces are considered part
|
|
1403
|
+
// of a field and should not be ignored. The last field in the
|
|
1404
|
+
// record must not be followed by a comma. For example:
|
|
1405
|
+
// aaa,bbb,ccc
|
|
1406
|
+
// delimit val
|
|
1407
|
+
row.push(val);
|
|
1408
|
+
val = "";
|
|
1409
|
+
} else if (match[2] === "\n") {
|
|
1410
|
+
// 1. Each record is located on a separate line, delimited by a line
|
|
1411
|
+
// break (CRLF). For example:
|
|
1412
|
+
// aaa,bbb,ccc CRLF
|
|
1413
|
+
// zzz,yyy,xxx CRLF
|
|
1414
|
+
// delimit val
|
|
1415
|
+
row.push(val);
|
|
1416
|
+
val = "";
|
|
1417
|
+
// append row
|
|
1418
|
+
rowList.push(row);
|
|
1419
|
+
// reset row
|
|
1420
|
+
row = [];
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
// // append val
|
|
1424
|
+
// if (val) {
|
|
1425
|
+
// row.push(val);
|
|
1426
|
+
// }
|
|
1427
|
+
// // append row
|
|
1428
|
+
// if (row.length) {
|
|
1429
|
+
// rowList.push(row);
|
|
1430
|
+
// }
|
|
1431
|
+
return rowList;
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1153
1434
|
async function moduleFsInit() {
|
|
1154
1435
|
|
|
1155
1436
|
// This function will import nodejs builtin-modules if they have not yet been
|
|
@@ -1368,6 +1649,7 @@ export {
|
|
|
1368
1649
|
SQLITE_OPEN_TRANSIENT_DB,
|
|
1369
1650
|
SQLITE_OPEN_URI,
|
|
1370
1651
|
SQLITE_OPEN_WAL,
|
|
1652
|
+
assertErrorThrownAsync,
|
|
1371
1653
|
assertInt64,
|
|
1372
1654
|
assertJsonEqual,
|
|
1373
1655
|
assertNumericalEqual,
|
|
@@ -1381,6 +1663,7 @@ export {
|
|
|
1381
1663
|
dbFileSaveAsync,
|
|
1382
1664
|
dbNoopAsync,
|
|
1383
1665
|
dbOpenAsync,
|
|
1666
|
+
dbTableImportAsync,
|
|
1384
1667
|
debugInline,
|
|
1385
1668
|
fsCopyFileUnlessTest,
|
|
1386
1669
|
fsExistsUnlessTest,
|