dolphindb 2.0.800 → 2.0.900
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 +80 -5
- package/README.zh.md +83 -9
- package/browser.d.ts +37 -44
- package/browser.js +370 -315
- package/browser.js.map +1 -1
- package/docs.en.json +11544 -1607
- package/docs.zh.json +4215 -819
- package/index.d.ts +32 -43
- package/index.js +219 -210
- package/index.js.map +1 -1
- package/language.d.ts +5 -5
- package/language.js +3 -1
- package/language.js.map +1 -1
- package/package.json +7 -7
package/index.js
CHANGED
|
@@ -117,15 +117,6 @@ export const nulls = {
|
|
|
117
117
|
double: -Number.MAX_VALUE,
|
|
118
118
|
bytes16: Uint8Array.from(new Array(16).fill(0))
|
|
119
119
|
};
|
|
120
|
-
export const timezone_offset = 1000 * 60 * new Date().getTimezoneOffset();
|
|
121
|
-
export var StreamingStatusCode;
|
|
122
|
-
(function (StreamingStatusCode) {
|
|
123
|
-
StreamingStatusCode[StreamingStatusCode["ok"] = 0] = "ok";
|
|
124
|
-
StreamingStatusCode[StreamingStatusCode["connection_existed"] = 1] = "connection_existed";
|
|
125
|
-
StreamingStatusCode[StreamingStatusCode["not_leader"] = 2] = "not_leader";
|
|
126
|
-
StreamingStatusCode[StreamingStatusCode["other"] = 3] = "other";
|
|
127
|
-
StreamingStatusCode[StreamingStatusCode["error"] = 4] = "error";
|
|
128
|
-
})(StreamingStatusCode = StreamingStatusCode || (StreamingStatusCode = {}));
|
|
129
120
|
/** Can represent data types in all DolphinDB databases */
|
|
130
121
|
export class DdbObj {
|
|
131
122
|
static dec = new TextDecoder('utf-8');
|
|
@@ -521,8 +512,37 @@ export class DdbObj {
|
|
|
521
512
|
// 00 reserved
|
|
522
513
|
// 70 11 01 00 block.lengths = [70000 (0x00011170)]
|
|
523
514
|
// 01 00 00 00 02 00 00 00 ... 279992 more bytes> block.data
|
|
515
|
+
// decimal array vector
|
|
516
|
+
// a = array(DECIMAL32(2)[], 0, 10)
|
|
517
|
+
// append!(a, [
|
|
518
|
+
// [1, 2, 3],
|
|
519
|
+
// [4, 5],
|
|
520
|
+
// [6, 7, 8],
|
|
521
|
+
// [9, 10]
|
|
522
|
+
// ])
|
|
523
|
+
// print(a)
|
|
524
|
+
// a
|
|
525
|
+
// [[1.00,2.00,3.00],[4.00,5.00],[6.00,7.00,8.00],[9.00,10.00]]
|
|
526
|
+
// <Buffer 65 01 type = 101 = 64 + 37 (decimal32) , form = vector
|
|
527
|
+
// 04 00 00 00 0a 00 00 00 rows = 4, cols = 10
|
|
528
|
+
// scale (只有 decimal32 才有)
|
|
529
|
+
// 02 00 00 00 scale = 2
|
|
530
|
+
// block 0
|
|
531
|
+
// 04 00 block.rows = 4
|
|
532
|
+
// 01 block.unit = 1
|
|
533
|
+
// 00 reserved
|
|
534
|
+
// 03 02 03 02 block.lengths = [3, 2, 3, 2]
|
|
535
|
+
// 64 00 00 00 c8 00 00 00 2c 01 00 00 90 01 00 00 f4 01 00 00 58 02 00 00 bc 02 00 00 ... 12 more bytes> [100, 200, 300, ...]
|
|
536
|
+
// block 1
|
|
537
|
+
// ...
|
|
538
|
+
const type_ = type - 64;
|
|
524
539
|
const cols = dv.getUint32(4, le);
|
|
525
540
|
let blocks = [];
|
|
541
|
+
// decimal32/64 会在所有 blocks 之前多一个 scale
|
|
542
|
+
if (type_ === DdbType.decimal32 || type_ === DdbType.decimal64) {
|
|
543
|
+
blocks.scale = dv.getInt32(i_items_start, le);
|
|
544
|
+
i_items_start += 4;
|
|
545
|
+
}
|
|
526
546
|
let i_block_start = i_items_start;
|
|
527
547
|
// 解析一个 block
|
|
528
548
|
for (let i_row = 0; i_row < rows;) {
|
|
@@ -551,7 +571,20 @@ export class DdbObj {
|
|
|
551
571
|
let total_length = 0;
|
|
552
572
|
for (const x of lengths)
|
|
553
573
|
total_length += x;
|
|
554
|
-
|
|
574
|
+
let len_items;
|
|
575
|
+
let data;
|
|
576
|
+
switch (type_) {
|
|
577
|
+
case DdbType.decimal32:
|
|
578
|
+
len_items = total_length * 4;
|
|
579
|
+
data = new Int32Array(buf.buffer.slice(buf.byteOffset + i_data_start, buf.byteOffset + i_data_start + len_items));
|
|
580
|
+
break;
|
|
581
|
+
case DdbType.decimal64:
|
|
582
|
+
len_items = total_length * 8;
|
|
583
|
+
data = new BigInt64Array(buf.buffer.slice(buf.byteOffset + i_data_start, buf.byteOffset + i_data_start + len_items));
|
|
584
|
+
break;
|
|
585
|
+
default:
|
|
586
|
+
[len_items, data] = this.parse_vector_items(buf.subarray(i_data_start), le, type - 64, total_length);
|
|
587
|
+
}
|
|
555
588
|
blocks.push({
|
|
556
589
|
unit,
|
|
557
590
|
rows,
|
|
@@ -866,6 +899,10 @@ export class DdbObj {
|
|
|
866
899
|
if (form === DdbForm.vector && 64 <= type && type < 128)
|
|
867
900
|
return [
|
|
868
901
|
Uint32Array.of(this.rows, this.cols),
|
|
902
|
+
...(type - 64 === DdbType.decimal32 || type - 64 === DdbType.decimal64) ?
|
|
903
|
+
[Int32Array.of(this.value.scale)]
|
|
904
|
+
:
|
|
905
|
+
[],
|
|
869
906
|
...this.value.map(block => ([
|
|
870
907
|
Uint16Array.of(block.rows),
|
|
871
908
|
Uint8Array.of(block.unit, 0),
|
|
@@ -924,10 +961,7 @@ export class DdbObj {
|
|
|
924
961
|
})();
|
|
925
962
|
if (!body)
|
|
926
963
|
return new Uint8Array(0);
|
|
927
|
-
return concat([
|
|
928
|
-
header,
|
|
929
|
-
...body
|
|
930
|
-
]);
|
|
964
|
+
return concat([header, ...body]);
|
|
931
965
|
}
|
|
932
966
|
static pack_vector_body(value, type, length) {
|
|
933
967
|
switch (type) {
|
|
@@ -1017,7 +1051,8 @@ export class DdbObj {
|
|
|
1017
1051
|
throw new Error(`vector ${DdbType[type]} 暂不支持序列化`);
|
|
1018
1052
|
}
|
|
1019
1053
|
}
|
|
1020
|
-
[inspect.custom](depth,
|
|
1054
|
+
[inspect.custom](depth, _options, _inspect) {
|
|
1055
|
+
const options = { nullstr: true, quote: true, ..._options };
|
|
1021
1056
|
const type = this.inspect_type();
|
|
1022
1057
|
const data = (() => {
|
|
1023
1058
|
switch (this.form) {
|
|
@@ -1053,7 +1088,18 @@ export class DdbObj {
|
|
|
1053
1088
|
for (const length of lengths) {
|
|
1054
1089
|
let _items = new Array(Math.min(limit, length));
|
|
1055
1090
|
for (let i = 0; i < _items.length; i++)
|
|
1056
|
-
|
|
1091
|
+
if (_type === DdbType.decimal32 || _type === DdbType.decimal64) {
|
|
1092
|
+
const x = data[acc_len + i];
|
|
1093
|
+
if (x === nulls.int64 && _type === DdbType.decimal64 ||
|
|
1094
|
+
x === nulls.int32 && _type === DdbType.decimal32)
|
|
1095
|
+
return '';
|
|
1096
|
+
const { scale } = this.value;
|
|
1097
|
+
const s = String(x < 0 ? -x : x).padStart(scale, '0');
|
|
1098
|
+
const str = (x < 0 ? '-' : '') + (scale ? `${s.slice(0, -scale) || '0'}.${s.slice(-scale)}` : s);
|
|
1099
|
+
_items[i] = options.colors ? str.green : str;
|
|
1100
|
+
}
|
|
1101
|
+
else
|
|
1102
|
+
_items[i] = format(_type, data[acc_len + i], this.le, options);
|
|
1057
1103
|
items[i_items++] = format_array(_items, length > limit);
|
|
1058
1104
|
acc_len += length;
|
|
1059
1105
|
}
|
|
@@ -1217,8 +1263,8 @@ let _decimals = 20;
|
|
|
1217
1263
|
let _formatter = Intl.NumberFormat('en-US', { maximumFractionDigits: 20 });
|
|
1218
1264
|
/** Formats a single element (value) as a string according to DdbType, null returns a 'null' string */
|
|
1219
1265
|
export function format(type, value, le, options = {}) {
|
|
1266
|
+
const { decimals } = options;
|
|
1220
1267
|
const formatter = (() => {
|
|
1221
|
-
const { decimals } = options;
|
|
1222
1268
|
if (decimals === undefined || decimals === null)
|
|
1223
1269
|
return default_formatter;
|
|
1224
1270
|
if (decimals !== _decimals) {
|
|
@@ -1272,7 +1318,7 @@ export function format(type, value, le, options = {}) {
|
|
|
1272
1318
|
inspect(null, options)
|
|
1273
1319
|
:
|
|
1274
1320
|
options.colors ?
|
|
1275
|
-
date2str(value).
|
|
1321
|
+
date2str(value).magenta
|
|
1276
1322
|
:
|
|
1277
1323
|
date2str(value);
|
|
1278
1324
|
case DdbType.month:
|
|
@@ -1280,7 +1326,7 @@ export function format(type, value, le, options = {}) {
|
|
|
1280
1326
|
inspect(null, options)
|
|
1281
1327
|
:
|
|
1282
1328
|
options.colors ?
|
|
1283
|
-
month2str(value).
|
|
1329
|
+
month2str(value).magenta
|
|
1284
1330
|
:
|
|
1285
1331
|
month2str(value);
|
|
1286
1332
|
case DdbType.time:
|
|
@@ -1288,7 +1334,7 @@ export function format(type, value, le, options = {}) {
|
|
|
1288
1334
|
inspect(null, options)
|
|
1289
1335
|
:
|
|
1290
1336
|
options.colors ?
|
|
1291
|
-
time2str(value).
|
|
1337
|
+
time2str(value).magenta
|
|
1292
1338
|
:
|
|
1293
1339
|
time2str(value);
|
|
1294
1340
|
case DdbType.minute:
|
|
@@ -1296,7 +1342,7 @@ export function format(type, value, le, options = {}) {
|
|
|
1296
1342
|
inspect(null, options)
|
|
1297
1343
|
:
|
|
1298
1344
|
options.colors ?
|
|
1299
|
-
minute2str(value).
|
|
1345
|
+
minute2str(value).magenta
|
|
1300
1346
|
:
|
|
1301
1347
|
minute2str(value);
|
|
1302
1348
|
case DdbType.second:
|
|
@@ -1304,7 +1350,7 @@ export function format(type, value, le, options = {}) {
|
|
|
1304
1350
|
inspect(null, options)
|
|
1305
1351
|
:
|
|
1306
1352
|
options.colors ?
|
|
1307
|
-
second2str(value).
|
|
1353
|
+
second2str(value).magenta
|
|
1308
1354
|
:
|
|
1309
1355
|
second2str(value);
|
|
1310
1356
|
case DdbType.datetime:
|
|
@@ -1312,7 +1358,7 @@ export function format(type, value, le, options = {}) {
|
|
|
1312
1358
|
inspect(null, options)
|
|
1313
1359
|
:
|
|
1314
1360
|
options.colors ?
|
|
1315
|
-
datetime2str(value).
|
|
1361
|
+
datetime2str(value).magenta
|
|
1316
1362
|
:
|
|
1317
1363
|
datetime2str(value);
|
|
1318
1364
|
case DdbType.timestamp:
|
|
@@ -1320,7 +1366,7 @@ export function format(type, value, le, options = {}) {
|
|
|
1320
1366
|
inspect(null, options)
|
|
1321
1367
|
:
|
|
1322
1368
|
options.colors ?
|
|
1323
|
-
timestamp2str(value).
|
|
1369
|
+
timestamp2str(value).magenta
|
|
1324
1370
|
:
|
|
1325
1371
|
timestamp2str(value);
|
|
1326
1372
|
case DdbType.nanotime:
|
|
@@ -1328,7 +1374,7 @@ export function format(type, value, le, options = {}) {
|
|
|
1328
1374
|
inspect(null, options)
|
|
1329
1375
|
:
|
|
1330
1376
|
options.colors ?
|
|
1331
|
-
nanotime2str(value).
|
|
1377
|
+
nanotime2str(value).magenta
|
|
1332
1378
|
:
|
|
1333
1379
|
nanotime2str(value);
|
|
1334
1380
|
case DdbType.nanotimestamp:
|
|
@@ -1336,7 +1382,7 @@ export function format(type, value, le, options = {}) {
|
|
|
1336
1382
|
inspect(null, options)
|
|
1337
1383
|
:
|
|
1338
1384
|
options.colors ?
|
|
1339
|
-
nanotimestamp2str(value).
|
|
1385
|
+
nanotimestamp2str(value).magenta
|
|
1340
1386
|
:
|
|
1341
1387
|
nanotimestamp2str(value);
|
|
1342
1388
|
case DdbType.float:
|
|
@@ -1360,7 +1406,7 @@ export function format(type, value, le, options = {}) {
|
|
|
1360
1406
|
return inspect(value, options);
|
|
1361
1407
|
case DdbType.uuid:
|
|
1362
1408
|
return options.colors ?
|
|
1363
|
-
uuid2str(value, le).
|
|
1409
|
+
uuid2str(value, le).cyan
|
|
1364
1410
|
:
|
|
1365
1411
|
uuid2str(value, le);
|
|
1366
1412
|
case DdbType.functiondef:
|
|
@@ -1374,12 +1420,12 @@ export function format(type, value, le, options = {}) {
|
|
|
1374
1420
|
'null'
|
|
1375
1421
|
:
|
|
1376
1422
|
options.colors ?
|
|
1377
|
-
datehour2str(value).
|
|
1423
|
+
datehour2str(value).magenta
|
|
1378
1424
|
:
|
|
1379
1425
|
datehour2str(value);
|
|
1380
1426
|
case DdbType.ipaddr:
|
|
1381
1427
|
return options.colors ?
|
|
1382
|
-
ipaddr2str(value, le).
|
|
1428
|
+
ipaddr2str(value, le).cyan
|
|
1383
1429
|
:
|
|
1384
1430
|
ipaddr2str(value, le);
|
|
1385
1431
|
case DdbType.int128:
|
|
@@ -1403,7 +1449,7 @@ export function format(type, value, le, options = {}) {
|
|
|
1403
1449
|
case DdbType.duration: {
|
|
1404
1450
|
const { data, unit } = value;
|
|
1405
1451
|
const str = `${data}${DdbDurationUnit[unit]}`;
|
|
1406
|
-
return options.colors ? str.
|
|
1452
|
+
return options.colors ? str.magenta : str;
|
|
1407
1453
|
}
|
|
1408
1454
|
case DdbType.decimal32:
|
|
1409
1455
|
case DdbType.decimal64: {
|
|
@@ -1422,6 +1468,7 @@ export function format(type, value, le, options = {}) {
|
|
|
1422
1468
|
}
|
|
1423
1469
|
/** formatted vector, the index-th item in the collection is a string, a null value returns a 'null' string */
|
|
1424
1470
|
export function formati(obj, index, options = {}) {
|
|
1471
|
+
assert(index < obj.rows, 'index < obj.rows');
|
|
1425
1472
|
if (64 <= obj.type && obj.type < 128) { // array vector
|
|
1426
1473
|
// 因为 array vector 目前只支持:Logical, Integral(不包括 INT128, COMPRESS 类型), Floating, Temporal
|
|
1427
1474
|
// 都对应 TypedArray 中的一格,所以 lengths.length 等于 block 中的 row 的个数
|
|
@@ -1449,18 +1496,26 @@ export function formati(obj, index, options = {}) {
|
|
|
1449
1496
|
const limit = 10;
|
|
1450
1497
|
let items = new Array(Math.min(limit, length));
|
|
1451
1498
|
for (let i = 0; i < items.length; i++)
|
|
1452
|
-
|
|
1499
|
+
if (_type === DdbType.decimal32 || _type === DdbType.decimal64) {
|
|
1500
|
+
const x = data[acc_len + i];
|
|
1501
|
+
if (x === nulls.int64 && _type === DdbType.decimal64 ||
|
|
1502
|
+
x === nulls.int32 && _type === DdbType.decimal32)
|
|
1503
|
+
return '';
|
|
1504
|
+
const { scale } = obj.value;
|
|
1505
|
+
const s = String(x < 0 ? -x : x).padStart(scale, '0');
|
|
1506
|
+
const str = (x < 0 ? '-' : '') + (scale ? `${s.slice(0, -scale) || '0'}.${s.slice(-scale)}` : s);
|
|
1507
|
+
items[i] = options.colors ? str.green : str;
|
|
1508
|
+
}
|
|
1509
|
+
else
|
|
1510
|
+
items[i] = format(_type, data[acc_len + i], obj.le, options);
|
|
1453
1511
|
return (items.join(', ') + (length > limit ? ', ...' : '')).bracket('square');
|
|
1454
1512
|
}
|
|
1455
1513
|
}
|
|
1456
1514
|
}
|
|
1457
1515
|
switch (obj.type) {
|
|
1458
|
-
case DdbType.string:
|
|
1459
|
-
case DdbType.symbol:
|
|
1460
|
-
return obj.value[index];
|
|
1461
1516
|
case DdbType.symbol_extended: {
|
|
1462
1517
|
const { base, data } = obj.value;
|
|
1463
|
-
return base[data[index]];
|
|
1518
|
+
return format(DdbType.string, base[data[index]], obj.le, options);
|
|
1464
1519
|
}
|
|
1465
1520
|
case DdbType.uuid:
|
|
1466
1521
|
case DdbType.int128:
|
|
@@ -1788,10 +1843,14 @@ export class DdbTable extends DdbObj {
|
|
|
1788
1843
|
}
|
|
1789
1844
|
}
|
|
1790
1845
|
export function date2ms(date) {
|
|
1846
|
+
// 将 server 的本地时间 (以 ms 为单位,1970.01.01 00:00:00 作为零点) 当成是客户端这里的本地的时间,然后根据本地的时区信息转换为 utc 时间
|
|
1847
|
+
// 本地的时区与实际的时间值相关,timezone offset 可能会受到夏令时 (DST) 的影响
|
|
1848
|
+
// 得到的 utc 毫秒数交给 js date 或者 dayjs 去格式化
|
|
1849
|
+
const ms = 1000 * 3600 * 24 * date;
|
|
1791
1850
|
return (date === null || date === nulls.int32) ?
|
|
1792
1851
|
null
|
|
1793
1852
|
:
|
|
1794
|
-
|
|
1853
|
+
1000 * 60 * new Date(ms).getTimezoneOffset() + ms;
|
|
1795
1854
|
}
|
|
1796
1855
|
export function date2str(date, format = 'YYYY.MM.DD') {
|
|
1797
1856
|
return (date === null || date === nulls.int32) ?
|
|
@@ -1818,7 +1877,7 @@ export function time2ms(time) {
|
|
|
1818
1877
|
return (time === null || time === nulls.int32) ?
|
|
1819
1878
|
null
|
|
1820
1879
|
:
|
|
1821
|
-
|
|
1880
|
+
1000 * 60 * new Date(time).getTimezoneOffset() + time;
|
|
1822
1881
|
}
|
|
1823
1882
|
export function time2str(time, format = 'HH:mm:ss.SSS') {
|
|
1824
1883
|
return (time === null || time === nulls.int32) ?
|
|
@@ -1827,10 +1886,11 @@ export function time2str(time, format = 'HH:mm:ss.SSS') {
|
|
|
1827
1886
|
dayjs(time2ms(time)).format(format);
|
|
1828
1887
|
}
|
|
1829
1888
|
export function minute2ms(minute) {
|
|
1889
|
+
const ms = 60 * 1000 * minute;
|
|
1830
1890
|
return (minute === null || minute === nulls.int32) ?
|
|
1831
1891
|
null
|
|
1832
1892
|
:
|
|
1833
|
-
|
|
1893
|
+
1000 * 60 * new Date(ms).getTimezoneOffset() + ms;
|
|
1834
1894
|
}
|
|
1835
1895
|
export function minute2str(minute, format = 'HH:mm[m]') {
|
|
1836
1896
|
return (minute === null || minute === nulls.int32) ?
|
|
@@ -1839,10 +1899,11 @@ export function minute2str(minute, format = 'HH:mm[m]') {
|
|
|
1839
1899
|
dayjs(minute2ms(minute)).format(format);
|
|
1840
1900
|
}
|
|
1841
1901
|
export function second2ms(second) {
|
|
1902
|
+
const ms = 1000 * second;
|
|
1842
1903
|
return (second === null || second === nulls.int32) ?
|
|
1843
1904
|
null
|
|
1844
1905
|
:
|
|
1845
|
-
|
|
1906
|
+
1000 * 60 * new Date(ms).getTimezoneOffset() + ms;
|
|
1846
1907
|
}
|
|
1847
1908
|
export function second2str(second, format = 'HH:mm:ss') {
|
|
1848
1909
|
return (second === null || second === nulls.int32) ?
|
|
@@ -1851,10 +1912,11 @@ export function second2str(second, format = 'HH:mm:ss') {
|
|
|
1851
1912
|
dayjs(second2ms(second)).format(format);
|
|
1852
1913
|
}
|
|
1853
1914
|
export function datetime2ms(datetime) {
|
|
1915
|
+
const ms = 1000 * datetime;
|
|
1854
1916
|
return (datetime === null || datetime === nulls.int32) ?
|
|
1855
1917
|
null
|
|
1856
1918
|
:
|
|
1857
|
-
|
|
1919
|
+
1000 * 60 * new Date(ms).getTimezoneOffset() + ms;
|
|
1858
1920
|
}
|
|
1859
1921
|
export function datetime2str(datetime, format = 'YYYY.MM.DD HH:mm:ss') {
|
|
1860
1922
|
return (datetime === null || datetime === nulls.int32) ?
|
|
@@ -1863,10 +1925,11 @@ export function datetime2str(datetime, format = 'YYYY.MM.DD HH:mm:ss') {
|
|
|
1863
1925
|
dayjs(datetime2ms(datetime)).format(format);
|
|
1864
1926
|
}
|
|
1865
1927
|
export function timestamp2ms(timestamp) {
|
|
1928
|
+
const ms = Number(timestamp);
|
|
1866
1929
|
return (timestamp === null || timestamp === nulls.int64) ?
|
|
1867
1930
|
null
|
|
1868
1931
|
:
|
|
1869
|
-
|
|
1932
|
+
1000 * 60 * new Date(ms).getTimezoneOffset() + ms;
|
|
1870
1933
|
}
|
|
1871
1934
|
/** format timestamp (bigint) to string
|
|
1872
1935
|
- timestamp: bigint value
|
|
@@ -1881,16 +1944,18 @@ export function timestamp2str(timestamp, format = 'YYYY.MM.DD HH:mm:ss.SSS') {
|
|
|
1881
1944
|
dayjs(timestamp2ms(timestamp)).format(format);
|
|
1882
1945
|
}
|
|
1883
1946
|
export function datehour2ms(datehour) {
|
|
1947
|
+
const ms = 1000 * 3600 * datehour;
|
|
1884
1948
|
return (datehour === null || datehour === nulls.int32) ?
|
|
1885
1949
|
null
|
|
1886
1950
|
:
|
|
1887
|
-
|
|
1951
|
+
1000 * 60 * new Date(ms).getTimezoneOffset() + ms;
|
|
1888
1952
|
}
|
|
1889
1953
|
export function datehour2str(datehour, format = 'YYYY.MM.DDTHH') {
|
|
1954
|
+
const ms = 1000 * 3600 * datehour;
|
|
1890
1955
|
return (datehour === null || datehour === nulls.int32) ?
|
|
1891
1956
|
'null'
|
|
1892
1957
|
:
|
|
1893
|
-
dayjs(
|
|
1958
|
+
dayjs(1000 * 60 * new Date(ms).getTimezoneOffset() + ms).format(format);
|
|
1894
1959
|
}
|
|
1895
1960
|
/** parse timestamp string to bigint value
|
|
1896
1961
|
- str: timestamp string, If it is an empty string or 'null', it will return the corresponding empty value (nulls.int64)
|
|
@@ -1901,9 +1966,10 @@ export function datehour2str(datehour, format = 'YYYY.MM.DDTHH') {
|
|
|
1901
1966
|
export function str2timestamp(str, format = 'YYYY.MM.DD HH:mm:ss.SSS') {
|
|
1902
1967
|
if (!str || str === 'null')
|
|
1903
1968
|
return nulls.int64;
|
|
1904
|
-
assert('The length of the timestamp string must be equal to the length of the format string');
|
|
1905
|
-
|
|
1906
|
-
|
|
1969
|
+
assert(str.length === format.length, 'The length of the timestamp string must be equal to the length of the format string');
|
|
1970
|
+
const ms = dayjs(str, format).valueOf();
|
|
1971
|
+
return BigInt(-(1000 * 60 * new Date(ms).getTimezoneOffset()) +
|
|
1972
|
+
ms);
|
|
1907
1973
|
}
|
|
1908
1974
|
export function nanotime2ns(nanotime) {
|
|
1909
1975
|
return nanotimestamp2ns(nanotime);
|
|
@@ -1918,15 +1984,17 @@ export function nanotime2str(nanotime, format = 'HH:mm:ss.SSSSSSSSS') {
|
|
|
1918
1984
|
const i_second_end = i_second_start + 2;
|
|
1919
1985
|
const i_nanosecond_start = format.indexOf('SSSSSSSSS', i_second_end);
|
|
1920
1986
|
assert(i_nanosecond_start !== -1, 'Format string must contain nanosecond format (SSSSSSSSS)');
|
|
1921
|
-
|
|
1987
|
+
const ms = Number(nanotime) / 1000000;
|
|
1988
|
+
return (dayjs(1000 * 60 * new Date(ms).getTimezoneOffset() + ms).format(format.slice(0, i_second_end)) +
|
|
1922
1989
|
format.slice(i_second_end, i_nanosecond_start) +
|
|
1923
1990
|
String(nanotime % 1000000000n).padStart(9, '0'));
|
|
1924
1991
|
}
|
|
1925
1992
|
export function nanotimestamp2ns(nanotimestamp) {
|
|
1993
|
+
const ms = Number(nanotimestamp / 1000000n);
|
|
1926
1994
|
return (nanotimestamp === null || nanotimestamp === nulls.int64) ?
|
|
1927
1995
|
null
|
|
1928
1996
|
:
|
|
1929
|
-
BigInt(
|
|
1997
|
+
BigInt(1000 * 60 * new Date(ms).getTimezoneOffset()) * 1000000n + nanotimestamp;
|
|
1930
1998
|
}
|
|
1931
1999
|
/** format nanotimestamp value (bigint) to string
|
|
1932
2000
|
- nanotimestamp: bigint value
|
|
@@ -1951,7 +2019,8 @@ export function nanotimestamp2str(nanotimestamp, format = 'YYYY.MM.DD HH:mm:ss.S
|
|
|
1951
2019
|
assert(i_nanosecond_start !== -1, 'Format string must contain nanosecond format (SSSSSSSSS)');
|
|
1952
2020
|
const remainder = nanotimestamp % 1000000000n;
|
|
1953
2021
|
const borrow = remainder < 0n;
|
|
1954
|
-
|
|
2022
|
+
const ms = Number(nanotimestamp / 1000000n);
|
|
2023
|
+
return (dayjs(1000 * 60 * new Date(ms).getTimezoneOffset() +
|
|
1955
2024
|
// 去掉 9 位的纳秒部分,转化为毫秒
|
|
1956
2025
|
Number((nanotimestamp - remainder + (borrow ? -1000000000n : 0n)) / 1000000n)).format(format.slice(0, i_second_end)) +
|
|
1957
2026
|
format.slice(i_second_end, i_nanosecond_start) +
|
|
@@ -1976,8 +2045,9 @@ export function str2nanotimestamp(str, format = 'YYYY.MM.DD HH:mm:ss.SSSSSSSSS')
|
|
|
1976
2045
|
const i_second_end = i_second_start + 2;
|
|
1977
2046
|
const i_nanosecond_start = format.indexOf('SSSSSSSSS', i_second_end);
|
|
1978
2047
|
assert(i_nanosecond_start !== -1, 'Format string must contain nanosecond format (SSSSSSSSS)');
|
|
1979
|
-
|
|
1980
|
-
|
|
2048
|
+
const ms = dayjs(str.slice(0, i_second_end), format.slice(0, i_second_end)).valueOf();
|
|
2049
|
+
return (BigInt(-(1000 * 60 * new Date(ms).getTimezoneOffset()) +
|
|
2050
|
+
ms) * 1000000n
|
|
1981
2051
|
+
|
|
1982
2052
|
BigInt(str.slice(i_nanosecond_start, i_nanosecond_start + 9)));
|
|
1983
2053
|
}
|
|
@@ -2003,7 +2073,14 @@ export function int1282str(buffer, le = true) {
|
|
|
2003
2073
|
return [...buf].map(x => x.toString(16)
|
|
2004
2074
|
.padStart(2, '0')).join('');
|
|
2005
2075
|
}
|
|
2006
|
-
export const winsize =
|
|
2076
|
+
export const winsize = 10_0000;
|
|
2077
|
+
export class ConnectionError extends Error {
|
|
2078
|
+
ddb;
|
|
2079
|
+
constructor(ddb) {
|
|
2080
|
+
super(`websocket is disconnected: ${ddb.url}`);
|
|
2081
|
+
this.ddb = ddb;
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2007
2084
|
export class DDB {
|
|
2008
2085
|
/** 当前的 session id (http 或 tcp) */
|
|
2009
2086
|
sid = '0';
|
|
@@ -2079,52 +2156,50 @@ export class DDB {
|
|
|
2079
2156
|
this.streaming = options.streaming;
|
|
2080
2157
|
}
|
|
2081
2158
|
on_message(event) {
|
|
2082
|
-
|
|
2083
|
-
console.log(event.data);
|
|
2159
|
+
// 这里的实现一定会被 connect 中的实现覆盖
|
|
2084
2160
|
}
|
|
2085
|
-
/** Establish
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
this.
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
on_open: async (event, websocket) => {
|
|
2116
|
-
this.websocket = websocket;
|
|
2161
|
+
/** Establish a actual websocket connection to the DolphindB corresponding to the URL
|
|
2162
|
+
It is a power, and after calling, it will ensure that it has been connected to the database (ensure that websocket.ReadyState is open), otherwise an error will be reported
|
|
2163
|
+
this.autologin automatically log in when it is true */
|
|
2164
|
+
async connect() {
|
|
2165
|
+
if (this.connected)
|
|
2166
|
+
return;
|
|
2167
|
+
const ptail = this.pconnect;
|
|
2168
|
+
let resolve;
|
|
2169
|
+
this.pconnect = new Promise((_resolve, _reject) => {
|
|
2170
|
+
resolve = _resolve;
|
|
2171
|
+
});
|
|
2172
|
+
await ptail;
|
|
2173
|
+
try {
|
|
2174
|
+
if (!this.connected) {
|
|
2175
|
+
this.on_message = (event) => {
|
|
2176
|
+
assert(false, '这是在调用 this.rpc 之前默认的 on_message, 不应该被调用到,除非建立连接后 server 先推送了 message');
|
|
2177
|
+
};
|
|
2178
|
+
this.presult = Promise.resolve(null);
|
|
2179
|
+
this.pnode_run_defined = false;
|
|
2180
|
+
this.websocket = await connect_websocket(this.url, {
|
|
2181
|
+
protocols: (() => {
|
|
2182
|
+
if (this.streaming)
|
|
2183
|
+
return 'streaming';
|
|
2184
|
+
if (this.python)
|
|
2185
|
+
return 'python';
|
|
2186
|
+
})(),
|
|
2187
|
+
on_message: (event) => {
|
|
2188
|
+
this.on_message(event);
|
|
2189
|
+
}
|
|
2190
|
+
});
|
|
2117
2191
|
if (this.streaming)
|
|
2118
2192
|
await this.subscribe();
|
|
2119
|
-
else
|
|
2193
|
+
else {
|
|
2120
2194
|
await this.rpc('connect', {});
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2195
|
+
if (this.autologin)
|
|
2196
|
+
await this.call('login', [this.username, this.password], { urgent: true });
|
|
2197
|
+
}
|
|
2124
2198
|
}
|
|
2125
|
-
}
|
|
2126
|
-
|
|
2127
|
-
|
|
2199
|
+
}
|
|
2200
|
+
finally {
|
|
2201
|
+
resolve();
|
|
2202
|
+
}
|
|
2128
2203
|
}
|
|
2129
2204
|
get_rpc_options({ urgent = false, secondary = false, async: _async = false, pickle = false, clear = false, api = false, compress = false, cancellable = true, priority = urgent ? 8 : 4, parallelism = 8, root_id = '', limit, } = {}) {
|
|
2130
2205
|
let flag = 0;
|
|
@@ -2160,12 +2235,9 @@ export class DDB {
|
|
|
2160
2235
|
disconnect() {
|
|
2161
2236
|
if (this.connected)
|
|
2162
2237
|
this.websocket.close(1000);
|
|
2163
|
-
this.on_message = () => { };
|
|
2164
|
-
this.presult = Promise.resolve(null);
|
|
2165
|
-
this.pconnect = Promise.resolve();
|
|
2166
|
-
this.pnode_run_defined = false;
|
|
2167
2238
|
}
|
|
2168
2239
|
/** rpc through websocket (function/script/variable command)
|
|
2240
|
+
When the DDB is not connected, the call will be automatically connected. When the connection is disconnected, the call will throw the Connectionerror
|
|
2169
2241
|
- type: API 类型: 'script' | 'function' | 'variable'
|
|
2170
2242
|
- options:
|
|
2171
2243
|
- urgent?: 决定 `行为标识` 那一行字符串的取值(只适用于 script 和 function)
|
|
@@ -2175,24 +2247,12 @@ export class DDB {
|
|
|
2175
2247
|
为 false 时返回的 DdbObj 仅含有 buffer 和 le,不做解析,以便后续转发、序列化
|
|
2176
2248
|
*/
|
|
2177
2249
|
async rpc(type, { script, func, args = [], vars = [], urgent, listener, parse_object, }) {
|
|
2178
|
-
if (!this.websocket)
|
|
2179
|
-
|
|
2180
|
-
let resolve;
|
|
2181
|
-
this.pconnect = new Promise((_resolve, _reject) => {
|
|
2182
|
-
resolve = _resolve;
|
|
2183
|
-
});
|
|
2184
|
-
await ptail;
|
|
2185
|
-
try {
|
|
2186
|
-
if (!this.websocket)
|
|
2187
|
-
await this.connect();
|
|
2188
|
-
}
|
|
2189
|
-
finally {
|
|
2190
|
-
resolve();
|
|
2191
|
-
}
|
|
2192
|
-
}
|
|
2250
|
+
if (!this.websocket)
|
|
2251
|
+
await this.connect();
|
|
2193
2252
|
if (!this.connected)
|
|
2194
|
-
throw new
|
|
2253
|
+
throw new ConnectionError(this);
|
|
2195
2254
|
if (func === 'pnode_run' && !this.pnode_run_defined) {
|
|
2255
|
+
// 保证并发调用 rpc 时只定义一次 pnode_run
|
|
2196
2256
|
const ptail = this.ppnoderun;
|
|
2197
2257
|
let resolve;
|
|
2198
2258
|
this.ppnoderun = new Promise((_resolve, _reject) => {
|
|
@@ -2386,8 +2446,9 @@ export class DDB {
|
|
|
2386
2446
|
async cancel() {
|
|
2387
2447
|
let ddb = new DDB(this.url, this);
|
|
2388
2448
|
try {
|
|
2449
|
+
// 因为是新建的连接,而且执行完脚本之后马上就关闭了,所以不用考虑变量泄漏的问题
|
|
2389
2450
|
await ddb.eval(`jobs = exec rootJobId from getConsoleJobs() where sessionId = ${this.sid}\n` +
|
|
2390
|
-
'if (size(jobs))\n' +
|
|
2451
|
+
(this.python ? 'if size(jobs):\n' : 'if (size(jobs))\n') +
|
|
2391
2452
|
' cancelConsoleJob(jobs)\n', { urgent: true });
|
|
2392
2453
|
}
|
|
2393
2454
|
finally {
|
|
@@ -2448,110 +2509,58 @@ export class DDB {
|
|
|
2448
2509
|
}
|
|
2449
2510
|
/** Internal stream subscription method */
|
|
2450
2511
|
async subscribe() {
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
// todo: 还有用吗?需要获取客户端 IP 吗
|
|
2512
|
+
await this.rpc('connect', {});
|
|
2513
|
+
if (this.autologin)
|
|
2514
|
+
await this.call('login', [this.username, this.password]);
|
|
2515
|
+
console.log('Subscribed to streaming table, colnames:',
|
|
2516
|
+
// string[3](['time', 'stock', 'price'])
|
|
2517
|
+
this.streaming.colnames = (await this.call('publishTable', [
|
|
2458
2518
|
'localhost',
|
|
2459
|
-
// todo: 端口还有用吗?
|
|
2460
2519
|
new DdbInt(0),
|
|
2461
2520
|
this.streaming.table,
|
|
2462
2521
|
(this.streaming.action ||= `api_js_${new Date().getTime()}`),
|
|
2463
2522
|
// new DdbInt(-1), // offset
|
|
2464
2523
|
// filter
|
|
2465
2524
|
// allow exists
|
|
2466
|
-
]);
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
reject(error);
|
|
2497
|
-
}
|
|
2498
|
-
}
|
|
2499
|
-
else {
|
|
2500
|
-
try {
|
|
2501
|
-
const dv = new DataView(buffer);
|
|
2502
|
-
const buf = new Uint8Array(buffer);
|
|
2503
|
-
let { streaming } = this;
|
|
2504
|
-
streaming.time = dv.getBigInt64(1, this.le);
|
|
2505
|
-
streaming.id = dv.getBigInt64(9, this.le);
|
|
2506
|
-
const i_topic_end = buf.indexOf(0, 17);
|
|
2507
|
-
streaming.topic = this.dec.decode(buf.subarray(17, i_topic_end));
|
|
2508
|
-
if (second) {
|
|
2509
|
-
second = false;
|
|
2510
|
-
// 是 table
|
|
2511
|
-
streaming.schema = DdbObj.parse(buf.subarray(i_topic_end + 1), this.le);
|
|
2512
|
-
console.log('Received streaming table schema:', streaming.schema);
|
|
2513
|
-
streaming.window = {
|
|
2514
|
-
offset: 0,
|
|
2515
|
-
rows: 0,
|
|
2516
|
-
segments: [],
|
|
2517
|
-
};
|
|
2518
|
-
assert(streaming.schema.rows === 0, 'schema.rows === 0');
|
|
2519
|
-
resolve(streaming.schema);
|
|
2520
|
-
}
|
|
2521
|
-
else {
|
|
2522
|
-
// 是 column 片段组成的 any vector
|
|
2523
|
-
const data = streaming.data = DdbObj.parse(buf.subarray(i_topic_end + 1), this.le);
|
|
2524
|
-
let { window: win } = streaming;
|
|
2525
|
-
win.rows += data.rows;
|
|
2526
|
-
win.segments.push(data);
|
|
2527
|
-
if (win.rows >= winsize * 2 && win.segments.length >= 2) {
|
|
2528
|
-
let winsize_ = 0;
|
|
2529
|
-
let i = win.segments.length - 1;
|
|
2530
|
-
// 往前移动至首个累计 winsize_ 超过 winsize 的位置
|
|
2531
|
-
for (; winsize_ < winsize; i--)
|
|
2532
|
-
winsize_ += win.segments[i].rows;
|
|
2533
|
-
win.segments = win.segments.slice(i);
|
|
2534
|
-
win.offset += win.rows - winsize_;
|
|
2535
|
-
win.rows = winsize_;
|
|
2536
|
-
console.log('exceeds winsize, shrink window.segments', win);
|
|
2537
|
-
}
|
|
2538
|
-
streaming.handler(streaming);
|
|
2539
|
-
}
|
|
2540
|
-
}
|
|
2541
|
-
catch (error) {
|
|
2542
|
-
reject(error);
|
|
2543
|
-
}
|
|
2525
|
+
])).value);
|
|
2526
|
+
this.streaming.window = {
|
|
2527
|
+
offset: 0,
|
|
2528
|
+
rows: 0,
|
|
2529
|
+
segments: [],
|
|
2530
|
+
};
|
|
2531
|
+
// 先准备好收到 websocket message 的 callback
|
|
2532
|
+
this.on_message = ({ data: buffer }) => {
|
|
2533
|
+
let { streaming } = this;
|
|
2534
|
+
try {
|
|
2535
|
+
const dv = new DataView(buffer);
|
|
2536
|
+
const buf = new Uint8Array(buffer);
|
|
2537
|
+
streaming.time = dv.getBigInt64(1, this.le);
|
|
2538
|
+
streaming.id = dv.getBigInt64(9, this.le);
|
|
2539
|
+
const i_topic_end = buf.indexOf(0, 17);
|
|
2540
|
+
streaming.topic = this.dec.decode(buf.subarray(17, i_topic_end));
|
|
2541
|
+
// 是 column 片段组成的 any vector
|
|
2542
|
+
const data = streaming.data = DdbObj.parse(buf.subarray(i_topic_end + 1), this.le);
|
|
2543
|
+
let { window: win } = streaming;
|
|
2544
|
+
win.rows += streaming.rows = data.value[0].rows;
|
|
2545
|
+
win.segments.push(data);
|
|
2546
|
+
if (win.rows >= winsize * 2 && win.segments.length >= 2) {
|
|
2547
|
+
let winsize_ = 0;
|
|
2548
|
+
let i = win.segments.length - 1;
|
|
2549
|
+
// 往前移动至首个累计 winsize_ 超过 winsize 的位置
|
|
2550
|
+
for (; winsize_ < winsize; i--)
|
|
2551
|
+
winsize_ += win.segments[i].value[0].rows;
|
|
2552
|
+
win.segments = win.segments.slice(i);
|
|
2553
|
+
win.offset += win.rows - winsize_;
|
|
2554
|
+
win.rows = winsize_;
|
|
2544
2555
|
}
|
|
2545
|
-
}
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
]));
|
|
2554
|
-
});
|
|
2556
|
+
}
|
|
2557
|
+
catch (error) {
|
|
2558
|
+
// 将 error 交给 handler 处理
|
|
2559
|
+
streaming.error = error;
|
|
2560
|
+
}
|
|
2561
|
+
this.streaming.handler(streaming);
|
|
2562
|
+
};
|
|
2563
|
+
return this.streaming;
|
|
2555
2564
|
}
|
|
2556
2565
|
}
|
|
2557
2566
|
//# sourceMappingURL=index.js.map
|