dolphindb 2.0.920 → 2.0.921
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/docs.en.json +3292 -775
- package/docs.zh.json +3607 -796
- package/package.json +44 -44
- package/browser.d.ts +0 -667
- package/browser.js +0 -2665
- package/browser.js.map +0 -1
- package/i18n/index.d.ts +0 -9
- package/i18n/index.js +0 -6
- package/i18n/index.js.map +0 -1
- package/index.d.ts +0 -656
- package/index.js +0 -2798
- package/index.js.map +0 -1
- package/language.d.ts +0 -53
- package/language.js +0 -832
- package/language.js.map +0 -1
- package/theme.dark.d.ts +0 -60
- package/theme.dark.js +0 -235
- package/theme.dark.js.map +0 -1
- package/theme.light.d.ts +0 -60
- package/theme.light.js +0 -590
- package/theme.light.js.map +0 -1
package/browser.js
DELETED
|
@@ -1,2665 +0,0 @@
|
|
|
1
|
-
import dayjs from 'dayjs';
|
|
2
|
-
import DayjsCustomParseFormat from 'dayjs/plugin/customParseFormat.js';
|
|
3
|
-
dayjs.extend(DayjsCustomParseFormat);
|
|
4
|
-
import ipaddrjs from 'ipaddr.js';
|
|
5
|
-
const { fromByteArray: buf2ipaddr } = ipaddrjs;
|
|
6
|
-
import 'xshell/prototype.browser.js';
|
|
7
|
-
import { blue, cyan, green, grey, magenta } from 'xshell/chalk.browser.js';
|
|
8
|
-
import { concat, assert } from 'xshell/utils.browser.js';
|
|
9
|
-
import { connect_websocket, WebSocketConnectionError } from 'xshell/net.browser.js';
|
|
10
|
-
import { t } from './i18n/index.js';
|
|
11
|
-
export var DdbForm;
|
|
12
|
-
(function (DdbForm) {
|
|
13
|
-
DdbForm[DdbForm["scalar"] = 0] = "scalar";
|
|
14
|
-
DdbForm[DdbForm["vector"] = 1] = "vector";
|
|
15
|
-
DdbForm[DdbForm["pair"] = 2] = "pair";
|
|
16
|
-
DdbForm[DdbForm["matrix"] = 3] = "matrix";
|
|
17
|
-
DdbForm[DdbForm["set"] = 4] = "set";
|
|
18
|
-
DdbForm[DdbForm["dict"] = 5] = "dict";
|
|
19
|
-
DdbForm[DdbForm["table"] = 6] = "table";
|
|
20
|
-
DdbForm[DdbForm["chart"] = 7] = "chart";
|
|
21
|
-
/** 结点内部通信可能会使用,调用函数执行脚本一般不会返回这种类型
|
|
22
|
-
Node internal communication may be used, calling function execution script generally does not return this type */
|
|
23
|
-
DdbForm[DdbForm["chunk"] = 8] = "chunk";
|
|
24
|
-
/** sysobj */
|
|
25
|
-
DdbForm[DdbForm["object"] = 9] = "object";
|
|
26
|
-
})(DdbForm = DdbForm || (DdbForm = {}));
|
|
27
|
-
/** DolphinDB DataType
|
|
28
|
-
对应的 array vector 类型为 64 + 基本类型 The corresponding array vector type is 64 + base type
|
|
29
|
-
对应的 extended 类型为 128 + 基本类型 The corresponding extended type is 128 + base type
|
|
30
|
-
*/
|
|
31
|
-
export var DdbType;
|
|
32
|
-
(function (DdbType) {
|
|
33
|
-
DdbType[DdbType["void"] = 0] = "void";
|
|
34
|
-
DdbType[DdbType["bool"] = 1] = "bool";
|
|
35
|
-
DdbType[DdbType["char"] = 2] = "char";
|
|
36
|
-
DdbType[DdbType["short"] = 3] = "short";
|
|
37
|
-
DdbType[DdbType["int"] = 4] = "int";
|
|
38
|
-
DdbType[DdbType["long"] = 5] = "long";
|
|
39
|
-
DdbType[DdbType["date"] = 6] = "date";
|
|
40
|
-
DdbType[DdbType["month"] = 7] = "month";
|
|
41
|
-
DdbType[DdbType["time"] = 8] = "time";
|
|
42
|
-
DdbType[DdbType["minute"] = 9] = "minute";
|
|
43
|
-
DdbType[DdbType["second"] = 10] = "second";
|
|
44
|
-
DdbType[DdbType["datetime"] = 11] = "datetime";
|
|
45
|
-
DdbType[DdbType["timestamp"] = 12] = "timestamp";
|
|
46
|
-
DdbType[DdbType["nanotime"] = 13] = "nanotime";
|
|
47
|
-
DdbType[DdbType["nanotimestamp"] = 14] = "nanotimestamp";
|
|
48
|
-
DdbType[DdbType["float"] = 15] = "float";
|
|
49
|
-
DdbType[DdbType["double"] = 16] = "double";
|
|
50
|
-
DdbType[DdbType["symbol"] = 17] = "symbol";
|
|
51
|
-
DdbType[DdbType["string"] = 18] = "string";
|
|
52
|
-
DdbType[DdbType["uuid"] = 19] = "uuid";
|
|
53
|
-
DdbType[DdbType["functiondef"] = 20] = "functiondef";
|
|
54
|
-
DdbType[DdbType["handle"] = 21] = "handle";
|
|
55
|
-
DdbType[DdbType["code"] = 22] = "code";
|
|
56
|
-
DdbType[DdbType["datasource"] = 23] = "datasource";
|
|
57
|
-
DdbType[DdbType["resource"] = 24] = "resource";
|
|
58
|
-
DdbType[DdbType["any"] = 25] = "any";
|
|
59
|
-
DdbType[DdbType["compress"] = 26] = "compress";
|
|
60
|
-
DdbType[DdbType["dict"] = 27] = "dict";
|
|
61
|
-
DdbType[DdbType["datehour"] = 28] = "datehour";
|
|
62
|
-
DdbType[DdbType["ipaddr"] = 30] = "ipaddr";
|
|
63
|
-
DdbType[DdbType["int128"] = 31] = "int128";
|
|
64
|
-
DdbType[DdbType["blob"] = 32] = "blob";
|
|
65
|
-
DdbType[DdbType["complex"] = 34] = "complex";
|
|
66
|
-
DdbType[DdbType["point"] = 35] = "point";
|
|
67
|
-
DdbType[DdbType["duration"] = 36] = "duration";
|
|
68
|
-
DdbType[DdbType["decimal32"] = 37] = "decimal32";
|
|
69
|
-
DdbType[DdbType["decimal64"] = 38] = "decimal64";
|
|
70
|
-
DdbType[DdbType["decimal128"] = 39] = "decimal128";
|
|
71
|
-
DdbType[DdbType["object"] = 40] = "object";
|
|
72
|
-
DdbType[DdbType["pynone"] = 41] = "pynone";
|
|
73
|
-
DdbType[DdbType["symbol_extended"] = 145] = "symbol_extended";
|
|
74
|
-
})(DdbType = DdbType || (DdbType = {}));
|
|
75
|
-
export var DdbFunctionType;
|
|
76
|
-
(function (DdbFunctionType) {
|
|
77
|
-
DdbFunctionType[DdbFunctionType["SystemFunc"] = 0] = "SystemFunc";
|
|
78
|
-
DdbFunctionType[DdbFunctionType["SystemProc"] = 1] = "SystemProc";
|
|
79
|
-
DdbFunctionType[DdbFunctionType["OperatorFunc"] = 2] = "OperatorFunc";
|
|
80
|
-
DdbFunctionType[DdbFunctionType["UserDefinedFunc"] = 3] = "UserDefinedFunc";
|
|
81
|
-
DdbFunctionType[DdbFunctionType["PartialFunc"] = 4] = "PartialFunc";
|
|
82
|
-
DdbFunctionType[DdbFunctionType["DynamicFunc"] = 5] = "DynamicFunc";
|
|
83
|
-
DdbFunctionType[DdbFunctionType["PiecewiseFunc"] = 6] = "PiecewiseFunc";
|
|
84
|
-
DdbFunctionType[DdbFunctionType["JitFunc"] = 7] = "JitFunc";
|
|
85
|
-
DdbFunctionType[DdbFunctionType["JitPartialFunc"] = 8] = "JitPartialFunc";
|
|
86
|
-
})(DdbFunctionType = DdbFunctionType || (DdbFunctionType = {}));
|
|
87
|
-
export var DdbDurationUnit;
|
|
88
|
-
(function (DdbDurationUnit) {
|
|
89
|
-
DdbDurationUnit[DdbDurationUnit["ns"] = 0] = "ns";
|
|
90
|
-
DdbDurationUnit[DdbDurationUnit["us"] = 1] = "us";
|
|
91
|
-
DdbDurationUnit[DdbDurationUnit["ms"] = 2] = "ms";
|
|
92
|
-
DdbDurationUnit[DdbDurationUnit["s"] = 3] = "s";
|
|
93
|
-
DdbDurationUnit[DdbDurationUnit["m"] = 4] = "m";
|
|
94
|
-
DdbDurationUnit[DdbDurationUnit["H"] = 5] = "H";
|
|
95
|
-
DdbDurationUnit[DdbDurationUnit["d"] = 6] = "d";
|
|
96
|
-
DdbDurationUnit[DdbDurationUnit["w"] = 7] = "w";
|
|
97
|
-
DdbDurationUnit[DdbDurationUnit["M"] = 8] = "M";
|
|
98
|
-
DdbDurationUnit[DdbDurationUnit["y"] = 9] = "y";
|
|
99
|
-
DdbDurationUnit[DdbDurationUnit["B"] = 10] = "B";
|
|
100
|
-
})(DdbDurationUnit = DdbDurationUnit || (DdbDurationUnit = {}));
|
|
101
|
-
export var DdbChartType;
|
|
102
|
-
(function (DdbChartType) {
|
|
103
|
-
DdbChartType[DdbChartType["area"] = 0] = "area";
|
|
104
|
-
DdbChartType[DdbChartType["bar"] = 1] = "bar";
|
|
105
|
-
DdbChartType[DdbChartType["column"] = 2] = "column";
|
|
106
|
-
DdbChartType[DdbChartType["histogram"] = 3] = "histogram";
|
|
107
|
-
DdbChartType[DdbChartType["line"] = 4] = "line";
|
|
108
|
-
DdbChartType[DdbChartType["pie"] = 5] = "pie";
|
|
109
|
-
DdbChartType[DdbChartType["scatter"] = 6] = "scatter";
|
|
110
|
-
DdbChartType[DdbChartType["trend"] = 7] = "trend";
|
|
111
|
-
DdbChartType[DdbChartType["kline"] = 8] = "kline";
|
|
112
|
-
})(DdbChartType = DdbChartType || (DdbChartType = {}));
|
|
113
|
-
export const nulls = {
|
|
114
|
-
int8: -0x80,
|
|
115
|
-
int16: -0x80_00,
|
|
116
|
-
int32: -0x80_00_00_00,
|
|
117
|
-
int64: -0x8000000000000000n,
|
|
118
|
-
float32: -3.4028234663852886e+38,
|
|
119
|
-
/** -Number.MAX_VALUE */
|
|
120
|
-
double: -Number.MAX_VALUE,
|
|
121
|
-
bytes16: Uint8Array.from(new Array(16).fill(0))
|
|
122
|
-
};
|
|
123
|
-
/** 可以表示所有 DolphinDB 数据库中的数据类型 Can represent data types in all DolphinDB databases */
|
|
124
|
-
export class DdbObj {
|
|
125
|
-
static dec = new TextDecoder('utf-8');
|
|
126
|
-
static enc = new TextEncoder();
|
|
127
|
-
/** 维护已解析的 symbol base,比如流数据中后续的 symbol 向量可能只发送一个 base.id, base.size == 0, 依赖之前发送的 symbol base ?
|
|
128
|
-
只是暂存,如果一张表有多个 symbol 列,可能这个 symbol base 会被复用,不同的对象之间 symbol base 一般不复用
|
|
129
|
-
*/
|
|
130
|
-
static symbol_bases = {};
|
|
131
|
-
/** little endian (client) */
|
|
132
|
-
static le_client = Boolean(new Uint8Array(Uint32Array.of(1).buffer)[0]);
|
|
133
|
-
/** 是否为小端 (little endian) */
|
|
134
|
-
le = DdbObj.le_client;
|
|
135
|
-
/** 数据形式 https://www.dolphindb.cn/cn/help/DataTypesandStructures/DataForms/index.html */
|
|
136
|
-
form;
|
|
137
|
-
/** 数据类型 https://www.dolphindb.cn/cn/help/DataTypesandStructures/DataTypes/index.html */
|
|
138
|
-
type;
|
|
139
|
-
/** 占用 parse 时传入的 buf 的长度 */
|
|
140
|
-
length;
|
|
141
|
-
/** table name / column name */
|
|
142
|
-
name;
|
|
143
|
-
/**
|
|
144
|
-
最低维、第 1 维
|
|
145
|
-
- vector: rows = n, cols = 1
|
|
146
|
-
- pair: rows = 2, cols = 1
|
|
147
|
-
- matrix: rows = n, cols = m
|
|
148
|
-
- set: 同 vector
|
|
149
|
-
- dict: 包含 keys, values 向量
|
|
150
|
-
- table: 同 matrix
|
|
151
|
-
*/
|
|
152
|
-
rows;
|
|
153
|
-
/** 第 2 维 */
|
|
154
|
-
cols;
|
|
155
|
-
/** 实际数据。不同的 DdbForm, DdbType 使用 DdbValue 中不同的类型来表示实际数据
|
|
156
|
-
The actual data. Different DdbForm, DdbType use different types in DdbValue to represent actual data */
|
|
157
|
-
value;
|
|
158
|
-
/** 原始二进制数据,仅在 parse_object 为 false 时通过 parse_message 生成的顶层对象有这个属性 */
|
|
159
|
-
buffer;
|
|
160
|
-
constructor(data) {
|
|
161
|
-
Object.assign(this, data);
|
|
162
|
-
}
|
|
163
|
-
static parse(buf, le) {
|
|
164
|
-
if (!buf.length)
|
|
165
|
-
return new this({
|
|
166
|
-
le,
|
|
167
|
-
form: DdbForm.scalar,
|
|
168
|
-
type: DdbType.void,
|
|
169
|
-
length: 0,
|
|
170
|
-
value: null
|
|
171
|
-
});
|
|
172
|
-
const type = buf[0];
|
|
173
|
-
const form = buf[1];
|
|
174
|
-
if (buf.length <= 2) {
|
|
175
|
-
return new this({
|
|
176
|
-
le,
|
|
177
|
-
form,
|
|
178
|
-
type,
|
|
179
|
-
length: 2,
|
|
180
|
-
value: null,
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
// set 里面 data 嵌套了一个 vector, 跳过 vector 的 type 和 form
|
|
184
|
-
const i_data = form === DdbForm.set ? 4 : 2;
|
|
185
|
-
const buf_data = buf.subarray(i_data);
|
|
186
|
-
switch (form) {
|
|
187
|
-
case DdbForm.scalar: {
|
|
188
|
-
const [length, value] = this.parse_scalar(buf_data, le, type);
|
|
189
|
-
return new this({
|
|
190
|
-
le,
|
|
191
|
-
form,
|
|
192
|
-
type,
|
|
193
|
-
length: i_data + length,
|
|
194
|
-
value,
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
case DdbForm.vector:
|
|
198
|
-
case DdbForm.pair:
|
|
199
|
-
case DdbForm.set: {
|
|
200
|
-
let vector = this.parse_vector(buf_data, le, type);
|
|
201
|
-
vector.length += i_data;
|
|
202
|
-
vector.form = form;
|
|
203
|
-
return vector;
|
|
204
|
-
}
|
|
205
|
-
case DdbForm.table: {
|
|
206
|
-
// table([
|
|
207
|
-
// [1, 2] as a,
|
|
208
|
-
// [1, 2] as b
|
|
209
|
-
// ])
|
|
210
|
-
// <Buffer
|
|
211
|
-
// 00 06 form = table
|
|
212
|
-
// 02 00 00 00 02 00 00 00 rows = 2, cols = 2
|
|
213
|
-
// 00 行名称
|
|
214
|
-
// 61 00 62 00 列名称 a, b
|
|
215
|
-
// 04 01 form = vector, type = int
|
|
216
|
-
// 02 00 00 00 01 00 00 00 cols = 2, rows = 1
|
|
217
|
-
// 01 00 00 00 02 00 00 00
|
|
218
|
-
// 04 01
|
|
219
|
-
// 02 00 00 00 01 00 00 00
|
|
220
|
-
// 01 00 00 00 02 00 00 00>
|
|
221
|
-
const dv = new DataView(buf.buffer, buf.byteOffset + i_data);
|
|
222
|
-
const rows = dv.getUint32(0, le);
|
|
223
|
-
const cols = dv.getUint32(4, le);
|
|
224
|
-
const i_name_tail = buf_data.indexOf(0, 8);
|
|
225
|
-
const name = this.dec.decode(buf_data.subarray(8, i_name_tail));
|
|
226
|
-
const i_items_start = i_name_tail + 1;
|
|
227
|
-
const [len_items, colnames] = this.parse_vector_items(buf_data.subarray(i_items_start), le, DdbType.string, cols);
|
|
228
|
-
let value = new Array(cols);
|
|
229
|
-
let i_start = i_items_start + len_items;
|
|
230
|
-
for (let i = 0; i < cols; i++) {
|
|
231
|
-
const type = buf_data[i_start];
|
|
232
|
-
let col = this.parse_vector(buf_data.subarray(i_start + 2), le, type);
|
|
233
|
-
col.length += 2;
|
|
234
|
-
col.name = colnames[i];
|
|
235
|
-
value[i] = col;
|
|
236
|
-
i_start += col.length;
|
|
237
|
-
}
|
|
238
|
-
return new this({
|
|
239
|
-
le,
|
|
240
|
-
form,
|
|
241
|
-
type,
|
|
242
|
-
length: i_data + i_start,
|
|
243
|
-
name,
|
|
244
|
-
rows,
|
|
245
|
-
cols,
|
|
246
|
-
value,
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
case DdbForm.dict:
|
|
250
|
-
case DdbForm.chart: {
|
|
251
|
-
// <Buffer 19 05 type = any, form = dict
|
|
252
|
-
// 12 01 keys.type = string, keys.form = vector
|
|
253
|
-
// 03 00 00 00 01 00 00 00 keys.cols = 3, keys.rows = 1
|
|
254
|
-
// 63 00 62 00 61 00
|
|
255
|
-
// 19 01 values.type = any, values.form = vector
|
|
256
|
-
// 03 00 00 00 01 00 00 00 values.cols = 3, values.rows = 1
|
|
257
|
-
// 04 00 03 00 00 00 04 00 02 00 00 00 04 00 01 00 00 00>
|
|
258
|
-
let keys = this.parse_vector(buf_data.subarray(2), le, buf_data[0]);
|
|
259
|
-
keys.length += 2;
|
|
260
|
-
let values = this.parse_vector(buf_data.subarray(keys.length + 2), le, buf_data[keys.length]);
|
|
261
|
-
values.length += 2;
|
|
262
|
-
let dict = new this({
|
|
263
|
-
le,
|
|
264
|
-
form: DdbForm.dict,
|
|
265
|
-
type,
|
|
266
|
-
length: i_data + keys.length + values.length,
|
|
267
|
-
rows: keys.rows,
|
|
268
|
-
cols: 2,
|
|
269
|
-
value: [
|
|
270
|
-
keys,
|
|
271
|
-
values
|
|
272
|
-
],
|
|
273
|
-
});
|
|
274
|
-
if (form === DdbForm.dict)
|
|
275
|
-
return dict;
|
|
276
|
-
else {
|
|
277
|
-
const { chartType: type, stacking, binStart: bin_start, binEnd: bin_end, binCount: bin_count, title: titles, extras, data, ...others } = dict.to_dict();
|
|
278
|
-
const [chart, x_axis, y_axis] = titles.value;
|
|
279
|
-
dict.form = DdbForm.chart;
|
|
280
|
-
dict.value = {
|
|
281
|
-
type: type.value,
|
|
282
|
-
stacking: stacking.value,
|
|
283
|
-
titles: {
|
|
284
|
-
chart,
|
|
285
|
-
x_axis,
|
|
286
|
-
y_axis,
|
|
287
|
-
},
|
|
288
|
-
...bin_start ? { bin_start, bin_end, } : {},
|
|
289
|
-
...bin_count ? { bin_count } : {},
|
|
290
|
-
...extras ? (() => {
|
|
291
|
-
const { multiYAxes: multi_y_axes = false, ...extras_others } = extras.to_dict({ strip: true });
|
|
292
|
-
return {
|
|
293
|
-
extras: {
|
|
294
|
-
multi_y_axes,
|
|
295
|
-
...extras_others,
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
})() : {},
|
|
299
|
-
data,
|
|
300
|
-
...others,
|
|
301
|
-
};
|
|
302
|
-
return dict;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
case DdbForm.matrix: {
|
|
306
|
-
// rename!(
|
|
307
|
-
// 1..9$3:3,
|
|
308
|
-
// [1, 2, 3],
|
|
309
|
-
// ['c1', 'c2', 'c3']
|
|
310
|
-
// )
|
|
311
|
-
// <Buffer 04 03 type = int, form = matrix
|
|
312
|
-
// 03 has_row_label (& 0x01) = 1, has_col_label (& 0x02) = 1
|
|
313
|
-
// row labels
|
|
314
|
-
// 04 01 type = int, form = vector
|
|
315
|
-
// 03 00 00 00 01 00 00 00 rows = 3, cols = 1
|
|
316
|
-
// 01 00 00 00 02 00 00 00 03 00 00 00 vector values
|
|
317
|
-
// col labels
|
|
318
|
-
// 12 01 type = string, form = vector
|
|
319
|
-
// 03 00 00 00 01 00 00 00 rows = 3, cols = 1
|
|
320
|
-
// 63 31 00 63 32 00 63 33 00
|
|
321
|
-
// matrix data
|
|
322
|
-
// 04 03 type = matrix.type, form = matrix
|
|
323
|
-
// 03 00 00 00 03 00 00 00 rows = 3, cols = 3
|
|
324
|
-
const dv = new DataView(buf.buffer, buf.byteOffset + i_data);
|
|
325
|
-
const label_flags = buf_data[0];
|
|
326
|
-
const has_row_labels = Boolean(label_flags & 0x01);
|
|
327
|
-
const has_col_labels = Boolean(label_flags & 0x02);
|
|
328
|
-
let row_labels = null;
|
|
329
|
-
let col_labels = null;
|
|
330
|
-
let offset = 1;
|
|
331
|
-
if (has_row_labels) {
|
|
332
|
-
row_labels = this.parse_vector(buf_data.subarray(offset + 2), le, buf_data[offset]);
|
|
333
|
-
row_labels.length += 2;
|
|
334
|
-
offset += row_labels.length;
|
|
335
|
-
}
|
|
336
|
-
if (has_col_labels) {
|
|
337
|
-
col_labels = this.parse_vector(buf_data.subarray(offset + 2), le, buf_data[offset]);
|
|
338
|
-
col_labels.length += 2;
|
|
339
|
-
offset += col_labels.length;
|
|
340
|
-
}
|
|
341
|
-
assert(buf_data[offset] === type, 'matrix.datatype === matrix.type');
|
|
342
|
-
const rows = dv.getUint32(offset + 2, le);
|
|
343
|
-
const cols = dv.getUint32(offset + 6, le);
|
|
344
|
-
const [len_items, data] = this.parse_vector_items(buf_data.subarray(offset + 10), le, type, rows * cols // 假设小于 2**32
|
|
345
|
-
);
|
|
346
|
-
offset += 10 + len_items;
|
|
347
|
-
return new this({
|
|
348
|
-
le,
|
|
349
|
-
form,
|
|
350
|
-
type,
|
|
351
|
-
length: i_data + offset,
|
|
352
|
-
rows,
|
|
353
|
-
cols,
|
|
354
|
-
value: {
|
|
355
|
-
rows: row_labels,
|
|
356
|
-
cols: col_labels,
|
|
357
|
-
data,
|
|
358
|
-
},
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
default:
|
|
362
|
-
return new this({
|
|
363
|
-
le,
|
|
364
|
-
form,
|
|
365
|
-
type,
|
|
366
|
-
length: i_data + buf_data.length,
|
|
367
|
-
value: buf_data
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
static parse_scalar(buf, le, type) {
|
|
372
|
-
switch (type) {
|
|
373
|
-
case DdbType.void:
|
|
374
|
-
return [1, null];
|
|
375
|
-
case DdbType.bool: {
|
|
376
|
-
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
377
|
-
const value = dv.getInt8(0);
|
|
378
|
-
return [1, value === nulls.int8 ? null : Boolean(value)];
|
|
379
|
-
}
|
|
380
|
-
case DdbType.char: {
|
|
381
|
-
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
382
|
-
const value = dv.getInt8(0);
|
|
383
|
-
return [1, value === nulls.int8 ? null : value];
|
|
384
|
-
}
|
|
385
|
-
case DdbType.short: {
|
|
386
|
-
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
387
|
-
const value = dv.getInt16(0, le);
|
|
388
|
-
return [2, value === nulls.int16 ? null : value];
|
|
389
|
-
}
|
|
390
|
-
case DdbType.int:
|
|
391
|
-
// datetime
|
|
392
|
-
case DdbType.date:
|
|
393
|
-
case DdbType.month:
|
|
394
|
-
case DdbType.time:
|
|
395
|
-
case DdbType.minute:
|
|
396
|
-
case DdbType.second:
|
|
397
|
-
case DdbType.datetime:
|
|
398
|
-
case DdbType.datehour: {
|
|
399
|
-
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
400
|
-
const value = dv.getInt32(0, le);
|
|
401
|
-
return [4, value === nulls.int32 ? null : value];
|
|
402
|
-
}
|
|
403
|
-
case DdbType.float: {
|
|
404
|
-
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
405
|
-
const value = dv.getFloat32(0, le);
|
|
406
|
-
return [4, value === nulls.float32 ? null : value];
|
|
407
|
-
}
|
|
408
|
-
case DdbType.double: {
|
|
409
|
-
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
410
|
-
const value = dv.getFloat64(0, le);
|
|
411
|
-
return [8, value === nulls.double ? null : value];
|
|
412
|
-
}
|
|
413
|
-
case DdbType.long:
|
|
414
|
-
// timestamp
|
|
415
|
-
case DdbType.timestamp:
|
|
416
|
-
case DdbType.nanotime:
|
|
417
|
-
case DdbType.nanotimestamp: {
|
|
418
|
-
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
419
|
-
const value = dv.getBigInt64(0, le);
|
|
420
|
-
return [8, value === nulls.int64 ? null : value];
|
|
421
|
-
}
|
|
422
|
-
case DdbType.string:
|
|
423
|
-
case DdbType.symbol:
|
|
424
|
-
case DdbType.code:
|
|
425
|
-
case DdbType.handle:
|
|
426
|
-
case DdbType.functiondef:
|
|
427
|
-
// mysql 插件 connect 方法会返回 resource 类型的对象
|
|
428
|
-
case DdbType.resource: {
|
|
429
|
-
const i_head = type === DdbType.functiondef ? 1 : 0;
|
|
430
|
-
let i_zero = buf.indexOf(0, i_head);
|
|
431
|
-
let i_end; // 整个字符串(包括 0)的末尾,excluding
|
|
432
|
-
if (i_zero === -1)
|
|
433
|
-
i_end = i_zero = buf.length;
|
|
434
|
-
else
|
|
435
|
-
i_end = i_zero + 1;
|
|
436
|
-
// 调整了 i_zero 到字符串(不包括 0)的末尾,excluding
|
|
437
|
-
const str = this.dec.decode(buf.subarray(i_head, i_zero));
|
|
438
|
-
return [
|
|
439
|
-
i_end,
|
|
440
|
-
type === DdbType.functiondef ?
|
|
441
|
-
{
|
|
442
|
-
type: buf[0],
|
|
443
|
-
name: str
|
|
444
|
-
}
|
|
445
|
-
:
|
|
446
|
-
str
|
|
447
|
-
];
|
|
448
|
-
}
|
|
449
|
-
case DdbType.uuid:
|
|
450
|
-
case DdbType.ipaddr:
|
|
451
|
-
case DdbType.int128:
|
|
452
|
-
return [16, buf.slice(0, 16)];
|
|
453
|
-
case DdbType.blob: {
|
|
454
|
-
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
455
|
-
const length = dv.getUint32(0, le);
|
|
456
|
-
return [4 + length, buf.slice(4, 4 + length)];
|
|
457
|
-
}
|
|
458
|
-
case DdbType.complex:
|
|
459
|
-
case DdbType.point: {
|
|
460
|
-
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
461
|
-
return [16, [dv.getFloat64(0, le), dv.getFloat64(8, le)]];
|
|
462
|
-
}
|
|
463
|
-
case DdbType.duration: {
|
|
464
|
-
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
465
|
-
return [8, { unit: dv.getUint32(4, le), data: dv.getInt32(0, le) }];
|
|
466
|
-
}
|
|
467
|
-
case DdbType.decimal32: {
|
|
468
|
-
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
469
|
-
const data = dv.getInt32(4, le);
|
|
470
|
-
return [8, { scale: dv.getInt32(0, le), data: data === nulls.int32 ? null : data }];
|
|
471
|
-
}
|
|
472
|
-
case DdbType.decimal64: {
|
|
473
|
-
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
474
|
-
const data = dv.getBigInt64(4, le);
|
|
475
|
-
return [12, { scale: dv.getInt32(0, le), data: data === nulls.int64 ? null : data }];
|
|
476
|
-
}
|
|
477
|
-
default:
|
|
478
|
-
throw new Error(String(DdbType[type] || type) + t(' 暂时不支持解析'));
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
/** parse: rows, cols, items
|
|
482
|
-
返回的 ddbobj.length 不包括 vector 的 type 和 form
|
|
483
|
-
*/
|
|
484
|
-
static parse_vector(buf, le, type) {
|
|
485
|
-
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
486
|
-
const rows = dv.getUint32(0, le);
|
|
487
|
-
let i_items_start = 8;
|
|
488
|
-
if (type < 64 || type >= 128) {
|
|
489
|
-
const [len_items, value] = this.parse_vector_items(buf.subarray(i_items_start), le, type, rows);
|
|
490
|
-
return new this({
|
|
491
|
-
le,
|
|
492
|
-
form: DdbForm.vector,
|
|
493
|
-
type,
|
|
494
|
-
length: i_items_start + len_items,
|
|
495
|
-
cols: 1,
|
|
496
|
-
rows,
|
|
497
|
-
value,
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
// array vector
|
|
501
|
-
// av = array(INT[], 0, 3)
|
|
502
|
-
// append!(av, [1..4])
|
|
503
|
-
// append!(av, [1..70000])
|
|
504
|
-
// av
|
|
505
|
-
// <Buffer 44 01 type = array vector, form = vector
|
|
506
|
-
// 02 00 00 00 74 11 01 00 rows = 2, cols = 70004 (0x011174)
|
|
507
|
-
// block 0
|
|
508
|
-
// 01 00 block.rows = 1
|
|
509
|
-
// 04 block.unit = 4
|
|
510
|
-
// 00 reserved
|
|
511
|
-
// 04 00 00 00 block.lengths = [4]
|
|
512
|
-
// 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 block.data
|
|
513
|
-
// block 1
|
|
514
|
-
// 01 00 block.rows = 1
|
|
515
|
-
// 04 block.unit = 4
|
|
516
|
-
// 00 reserved
|
|
517
|
-
// 70 11 01 00 block.lengths = [70000 (0x00011170)]
|
|
518
|
-
// 01 00 00 00 02 00 00 00 ... 279992 more bytes> block.data
|
|
519
|
-
// decimal array vector
|
|
520
|
-
// a = array(DECIMAL32(2)[], 0, 10)
|
|
521
|
-
// append!(a, [
|
|
522
|
-
// [1, 2, 3],
|
|
523
|
-
// [4, 5],
|
|
524
|
-
// [6, 7, 8],
|
|
525
|
-
// [9, 10]
|
|
526
|
-
// ])
|
|
527
|
-
// print(a)
|
|
528
|
-
// a
|
|
529
|
-
// [[1.00,2.00,3.00],[4.00,5.00],[6.00,7.00,8.00],[9.00,10.00]]
|
|
530
|
-
// <Buffer 65 01 type = 101 = 64 + 37 (decimal32) , form = vector
|
|
531
|
-
// 04 00 00 00 0a 00 00 00 rows = 4, cols = 10
|
|
532
|
-
// scale (只有 decimal32 才有)
|
|
533
|
-
// 02 00 00 00 scale = 2
|
|
534
|
-
// block 0
|
|
535
|
-
// 04 00 block.rows = 4
|
|
536
|
-
// 01 block.unit = 1
|
|
537
|
-
// 00 reserved
|
|
538
|
-
// 03 02 03 02 block.lengths = [3, 2, 3, 2]
|
|
539
|
-
// 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, ...]
|
|
540
|
-
// block 1
|
|
541
|
-
// ...
|
|
542
|
-
const type_ = type - 64;
|
|
543
|
-
const cols = dv.getUint32(4, le);
|
|
544
|
-
let blocks = [];
|
|
545
|
-
// decimal32/64 会在所有 blocks 之前多一个 scale
|
|
546
|
-
if (type_ === DdbType.decimal32 || type_ === DdbType.decimal64) {
|
|
547
|
-
blocks.scale = dv.getInt32(i_items_start, le);
|
|
548
|
-
i_items_start += 4;
|
|
549
|
-
}
|
|
550
|
-
let i_block_start = i_items_start;
|
|
551
|
-
// 解析一个 block
|
|
552
|
-
for (let i_row = 0; i_row < rows;) {
|
|
553
|
-
/** 对应 array vector 中元素个数 */
|
|
554
|
-
const rows = dv.getUint16(i_block_start, le);
|
|
555
|
-
/** 每个 length 占用的字节数 */
|
|
556
|
-
const unit = dv.getUint8(i_block_start + 2);
|
|
557
|
-
/** array vector 每个元素的子元素长度 */
|
|
558
|
-
let lengths;
|
|
559
|
-
const i_lengths_start = i_block_start + 4;
|
|
560
|
-
const i_data_start = i_lengths_start + rows * unit;
|
|
561
|
-
const lengths_buf = buf.slice(i_lengths_start, i_data_start);
|
|
562
|
-
switch (unit) {
|
|
563
|
-
case 1:
|
|
564
|
-
lengths = lengths_buf;
|
|
565
|
-
break;
|
|
566
|
-
case 2:
|
|
567
|
-
lengths = new Uint16Array(lengths_buf.buffer);
|
|
568
|
-
break;
|
|
569
|
-
case 4:
|
|
570
|
-
lengths = new Uint32Array(lengths_buf.buffer);
|
|
571
|
-
break;
|
|
572
|
-
default:
|
|
573
|
-
throw new Error(t('array vector 存在非法 unit: {{unit}}', { unit }));
|
|
574
|
-
}
|
|
575
|
-
let total_length = 0;
|
|
576
|
-
for (const x of lengths)
|
|
577
|
-
total_length += x;
|
|
578
|
-
let len_items;
|
|
579
|
-
let data;
|
|
580
|
-
switch (type_) {
|
|
581
|
-
case DdbType.decimal32:
|
|
582
|
-
len_items = total_length * 4;
|
|
583
|
-
data = new Int32Array(buf.buffer.slice(buf.byteOffset + i_data_start, buf.byteOffset + i_data_start + len_items));
|
|
584
|
-
break;
|
|
585
|
-
case DdbType.decimal64:
|
|
586
|
-
len_items = total_length * 8;
|
|
587
|
-
data = new BigInt64Array(buf.buffer.slice(buf.byteOffset + i_data_start, buf.byteOffset + i_data_start + len_items));
|
|
588
|
-
break;
|
|
589
|
-
default:
|
|
590
|
-
[len_items, data] = this.parse_vector_items(buf.subarray(i_data_start), le, type - 64, total_length);
|
|
591
|
-
}
|
|
592
|
-
blocks.push({
|
|
593
|
-
unit,
|
|
594
|
-
rows,
|
|
595
|
-
lengths,
|
|
596
|
-
data: data
|
|
597
|
-
});
|
|
598
|
-
i_block_start = i_data_start + len_items;
|
|
599
|
-
i_row += rows;
|
|
600
|
-
}
|
|
601
|
-
return new this({
|
|
602
|
-
le,
|
|
603
|
-
form: DdbForm.vector,
|
|
604
|
-
type,
|
|
605
|
-
length: i_block_start,
|
|
606
|
-
cols,
|
|
607
|
-
rows,
|
|
608
|
-
value: blocks
|
|
609
|
-
});
|
|
610
|
-
}
|
|
611
|
-
/** 有可能没有字节对齐,不能直接使用原有 message 的 arraybuffer, 统一复制出来,让原有 arraybuffer 被回收掉比较好 */
|
|
612
|
-
static parse_vector_items(buf, le, type, length) {
|
|
613
|
-
switch (type) {
|
|
614
|
-
case DdbType.bool:
|
|
615
|
-
case DdbType.char:
|
|
616
|
-
return [
|
|
617
|
-
length,
|
|
618
|
-
new Int8Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + length))
|
|
619
|
-
];
|
|
620
|
-
case DdbType.short:
|
|
621
|
-
return [
|
|
622
|
-
2 * length,
|
|
623
|
-
new Int16Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + 2 * length))
|
|
624
|
-
];
|
|
625
|
-
case DdbType.int:
|
|
626
|
-
// datetime
|
|
627
|
-
case DdbType.date:
|
|
628
|
-
case DdbType.month:
|
|
629
|
-
case DdbType.time:
|
|
630
|
-
case DdbType.minute:
|
|
631
|
-
case DdbType.second:
|
|
632
|
-
case DdbType.datetime:
|
|
633
|
-
case DdbType.datehour:
|
|
634
|
-
return [
|
|
635
|
-
4 * length,
|
|
636
|
-
new Int32Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + 4 * length))
|
|
637
|
-
];
|
|
638
|
-
case DdbType.float:
|
|
639
|
-
return [
|
|
640
|
-
4 * length,
|
|
641
|
-
new Float32Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + 4 * length))
|
|
642
|
-
];
|
|
643
|
-
case DdbType.double:
|
|
644
|
-
return [
|
|
645
|
-
8 * length,
|
|
646
|
-
new Float64Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + 8 * length))
|
|
647
|
-
];
|
|
648
|
-
case DdbType.long:
|
|
649
|
-
// timestamp
|
|
650
|
-
case DdbType.timestamp:
|
|
651
|
-
case DdbType.nanotime:
|
|
652
|
-
case DdbType.nanotimestamp:
|
|
653
|
-
return [
|
|
654
|
-
8 * length,
|
|
655
|
-
new BigInt64Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + 8 * length))
|
|
656
|
-
];
|
|
657
|
-
case DdbType.string:
|
|
658
|
-
case DdbType.symbol:
|
|
659
|
-
case DdbType.handle:
|
|
660
|
-
case DdbType.code: {
|
|
661
|
-
let value = new Array(length);
|
|
662
|
-
let i_head = 0, i_tail = i_head;
|
|
663
|
-
for (let i = 0; i < length; i++) {
|
|
664
|
-
i_tail = buf.indexOf(0, i_head);
|
|
665
|
-
value[i] = this.dec.decode(buf.subarray(i_head, i_tail));
|
|
666
|
-
i_head = i_tail + 1;
|
|
667
|
-
}
|
|
668
|
-
return [i_head, value];
|
|
669
|
-
}
|
|
670
|
-
case DdbType.symbol_extended: {
|
|
671
|
-
// <Buffer 91 01 type = symbol extended, form = vector
|
|
672
|
-
// 05 00 00 00 01 00 00 00 row = 5, col = 1
|
|
673
|
-
// buf:
|
|
674
|
-
// 00 00 00 00 symbol base id = 0 (uint32)
|
|
675
|
-
// 02 00 00 00 symbol base size = 2
|
|
676
|
-
// 00 61 61 00 以 \0 分割的字符串
|
|
677
|
-
// 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00>
|
|
678
|
-
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
679
|
-
const base_id = dv.getUint32(0, le);
|
|
680
|
-
const base_size = dv.getUint32(4, le);
|
|
681
|
-
let base_length = 0;
|
|
682
|
-
let base = this.symbol_bases[base_id];
|
|
683
|
-
// base_size 为 0 时复用之前的 symbol base
|
|
684
|
-
if (base_size) {
|
|
685
|
-
[base_length, base] = this.parse_vector_items(buf.subarray(8), le, DdbType.string, base_size);
|
|
686
|
-
this.symbol_bases[base_id] = base;
|
|
687
|
-
}
|
|
688
|
-
const value_start = 8 + base_length;
|
|
689
|
-
const value_end = value_start + length * 4;
|
|
690
|
-
const data = new Uint32Array(buf.buffer.slice(buf.byteOffset + value_start, buf.byteOffset + value_end));
|
|
691
|
-
return [
|
|
692
|
-
value_end,
|
|
693
|
-
{
|
|
694
|
-
base_id,
|
|
695
|
-
base,
|
|
696
|
-
data
|
|
697
|
-
}
|
|
698
|
-
];
|
|
699
|
-
}
|
|
700
|
-
case DdbType.uuid:
|
|
701
|
-
case DdbType.ipaddr:
|
|
702
|
-
case DdbType.int128:
|
|
703
|
-
return [
|
|
704
|
-
16 * length,
|
|
705
|
-
new Uint8Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + 16 * length))
|
|
706
|
-
];
|
|
707
|
-
case DdbType.blob: {
|
|
708
|
-
// <Buffer 20 01 type = blob, form = vector
|
|
709
|
-
// 02 00 00 00 01 00 00 00 cols = 2, rows = 1
|
|
710
|
-
// 04 00 00 00 61 62 63 64
|
|
711
|
-
// 04 00 00 00 61 62 63 64>
|
|
712
|
-
let value = new Array(length);
|
|
713
|
-
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
714
|
-
let i_head = 0;
|
|
715
|
-
for (let i = 0; i < length; i++) {
|
|
716
|
-
const sublen = dv.getUint32(i_head, le);
|
|
717
|
-
const i_blob_head = i_head + 4;
|
|
718
|
-
const i_blob_tail = i_blob_head + sublen;
|
|
719
|
-
value[i] = buf.slice(i_blob_head, i_blob_tail);
|
|
720
|
-
i_head = i_blob_tail;
|
|
721
|
-
}
|
|
722
|
-
return [i_head, value];
|
|
723
|
-
}
|
|
724
|
-
case DdbType.complex:
|
|
725
|
-
case DdbType.point:
|
|
726
|
-
return [
|
|
727
|
-
16 * length,
|
|
728
|
-
new Float64Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + 16 * length))
|
|
729
|
-
];
|
|
730
|
-
case DdbType.any: {
|
|
731
|
-
// [1, 2, 'a', 'aaa']
|
|
732
|
-
// any[4](<Buffer
|
|
733
|
-
// 04 00 DdbType.int, DdbForm.scalar
|
|
734
|
-
// 01 00 00 00
|
|
735
|
-
// 04 00 DdbType.int, DdbForm.scalar
|
|
736
|
-
// 02 00 00 00
|
|
737
|
-
// 02 00 DdbType.char, DdbForm.scalar
|
|
738
|
-
// 61
|
|
739
|
-
// 12 00 DdbType.string, DdbForm.scalar
|
|
740
|
-
// 61 61 61 00>)
|
|
741
|
-
let values = new Array(length);
|
|
742
|
-
let i_head = 0;
|
|
743
|
-
for (let i = 0; i < length; i++) {
|
|
744
|
-
const obj = this.parse(buf.subarray(i_head), le);
|
|
745
|
-
values[i] = obj;
|
|
746
|
-
i_head += obj.length;
|
|
747
|
-
}
|
|
748
|
-
return [
|
|
749
|
-
i_head,
|
|
750
|
-
values
|
|
751
|
-
];
|
|
752
|
-
}
|
|
753
|
-
// 25 01 type = decimal32, form = vector
|
|
754
|
-
// 02 00 00 00 01 00 00 00
|
|
755
|
-
// 00 00 00 00 scale = 0
|
|
756
|
-
// 01 00 00 00 data[0] = 1
|
|
757
|
-
// 3a 01 00 00 data[1] = 0x013a = 314
|
|
758
|
-
case DdbType.decimal32: {
|
|
759
|
-
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
760
|
-
return [
|
|
761
|
-
4 + 4 * length,
|
|
762
|
-
{
|
|
763
|
-
scale: dv.getInt32(0, le),
|
|
764
|
-
data: new Int32Array(buf.buffer.slice(buf.byteOffset + 4, buf.byteOffset + 4 + 4 * length))
|
|
765
|
-
}
|
|
766
|
-
];
|
|
767
|
-
}
|
|
768
|
-
case DdbType.decimal64: {
|
|
769
|
-
const dv = new DataView(buf.buffer, buf.byteOffset);
|
|
770
|
-
return [
|
|
771
|
-
4 + 8 * length,
|
|
772
|
-
{
|
|
773
|
-
scale: dv.getInt32(0, le),
|
|
774
|
-
data: new BigInt64Array(buf.buffer.slice(buf.byteOffset + 4, buf.byteOffset + 4 + 8 * length))
|
|
775
|
-
}
|
|
776
|
-
];
|
|
777
|
-
}
|
|
778
|
-
// case DdbType.duration: -> 实际会返回一个 any vector
|
|
779
|
-
// [2y, 1M, 3d, 7H, 11m, 12s, 15ms, 16us, 17ns]
|
|
780
|
-
// <Buffer 19 01 type = any, form = vector
|
|
781
|
-
// 09 00 00 00 01 00 00 00 rows = 9, cols = 1
|
|
782
|
-
// 24 00 type = DdbType.duration, form = scalar
|
|
783
|
-
// 02 00 00 00 09 00 00 00
|
|
784
|
-
// 24 00 01 00 00 00 08 00 00 00 24 00 03 00 00 00 06 00 00 00 24 00 07 00 00 00 05 00 00 00 ... 50 more bytes>
|
|
785
|
-
default:
|
|
786
|
-
return [0, buf];
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
pack() {
|
|
790
|
-
const { form, type, value } = this;
|
|
791
|
-
let header = new Uint8Array(2);
|
|
792
|
-
header[0] = type;
|
|
793
|
-
header[1] = form;
|
|
794
|
-
const body = (() => {
|
|
795
|
-
switch (form) {
|
|
796
|
-
case DdbForm.scalar:
|
|
797
|
-
switch (type) {
|
|
798
|
-
case DdbType.void:
|
|
799
|
-
return [Uint8Array.of(1)];
|
|
800
|
-
case DdbType.bool:
|
|
801
|
-
return [
|
|
802
|
-
Int8Array.of(value === null ?
|
|
803
|
-
nulls.int8
|
|
804
|
-
:
|
|
805
|
-
Number(value))
|
|
806
|
-
];
|
|
807
|
-
case DdbType.char:
|
|
808
|
-
return [
|
|
809
|
-
Int8Array.of((value === null ?
|
|
810
|
-
nulls.int8
|
|
811
|
-
:
|
|
812
|
-
value))
|
|
813
|
-
];
|
|
814
|
-
case DdbType.short:
|
|
815
|
-
return [
|
|
816
|
-
Int16Array.of(value === null ?
|
|
817
|
-
nulls.int16
|
|
818
|
-
:
|
|
819
|
-
value)
|
|
820
|
-
];
|
|
821
|
-
case DdbType.int:
|
|
822
|
-
// datetime
|
|
823
|
-
case DdbType.date:
|
|
824
|
-
case DdbType.month:
|
|
825
|
-
case DdbType.time:
|
|
826
|
-
case DdbType.minute:
|
|
827
|
-
case DdbType.second:
|
|
828
|
-
case DdbType.datetime:
|
|
829
|
-
case DdbType.datehour:
|
|
830
|
-
return [
|
|
831
|
-
Int32Array.of(value === null ?
|
|
832
|
-
nulls.int32
|
|
833
|
-
:
|
|
834
|
-
value)
|
|
835
|
-
];
|
|
836
|
-
case DdbType.float:
|
|
837
|
-
return [
|
|
838
|
-
Float32Array.of(value === null ?
|
|
839
|
-
nulls.float32
|
|
840
|
-
:
|
|
841
|
-
value)
|
|
842
|
-
];
|
|
843
|
-
case DdbType.double:
|
|
844
|
-
return [
|
|
845
|
-
Float64Array.of(value === null ?
|
|
846
|
-
nulls.double
|
|
847
|
-
:
|
|
848
|
-
value)
|
|
849
|
-
];
|
|
850
|
-
case DdbType.long:
|
|
851
|
-
// timestamp
|
|
852
|
-
case DdbType.timestamp:
|
|
853
|
-
case DdbType.nanotime:
|
|
854
|
-
case DdbType.nanotimestamp:
|
|
855
|
-
return [
|
|
856
|
-
BigInt64Array.of(value === null ?
|
|
857
|
-
nulls.int64
|
|
858
|
-
:
|
|
859
|
-
value)
|
|
860
|
-
];
|
|
861
|
-
case DdbType.string:
|
|
862
|
-
case DdbType.symbol:
|
|
863
|
-
case DdbType.code:
|
|
864
|
-
case DdbType.handle:
|
|
865
|
-
case DdbType.resource:
|
|
866
|
-
return [
|
|
867
|
-
DdbObj.enc.encode(value),
|
|
868
|
-
Uint8Array.of(0),
|
|
869
|
-
];
|
|
870
|
-
case DdbType.functiondef:
|
|
871
|
-
return [
|
|
872
|
-
Uint8Array.of(value.type),
|
|
873
|
-
DdbObj.enc.encode(value.name),
|
|
874
|
-
Uint8Array.of(0)
|
|
875
|
-
];
|
|
876
|
-
case DdbType.uuid:
|
|
877
|
-
case DdbType.ipaddr:
|
|
878
|
-
case DdbType.int128:
|
|
879
|
-
return [this.value];
|
|
880
|
-
case DdbType.blob:
|
|
881
|
-
return [Uint32Array.of(this.value.byteLength), this.value];
|
|
882
|
-
case DdbType.complex:
|
|
883
|
-
case DdbType.point:
|
|
884
|
-
return [Float64Array.from(this.value)];
|
|
885
|
-
case DdbType.duration: {
|
|
886
|
-
const { unit, data } = this.value;
|
|
887
|
-
return [Int32Array.of(data, unit)];
|
|
888
|
-
}
|
|
889
|
-
case DdbType.decimal32: {
|
|
890
|
-
const { scale, data } = this.value;
|
|
891
|
-
return [Int32Array.of(scale, data === null ? nulls.int32 : data)];
|
|
892
|
-
}
|
|
893
|
-
case DdbType.decimal64: {
|
|
894
|
-
const { scale, data } = this.value;
|
|
895
|
-
return [Int32Array.of(scale), BigInt64Array.of(data === null ? nulls.int64 : data)];
|
|
896
|
-
}
|
|
897
|
-
default:
|
|
898
|
-
throw new Error(String(DdbType[type] || type) + t(' 暂时不支持序列化'));
|
|
899
|
-
}
|
|
900
|
-
case DdbForm.vector:
|
|
901
|
-
case DdbForm.pair:
|
|
902
|
-
// pack array vector
|
|
903
|
-
if (form === DdbForm.vector && 64 <= type && type < 128)
|
|
904
|
-
return [
|
|
905
|
-
Uint32Array.of(this.rows, this.cols),
|
|
906
|
-
...(type - 64 === DdbType.decimal32 || type - 64 === DdbType.decimal64) ?
|
|
907
|
-
[Int32Array.of(this.value.scale)]
|
|
908
|
-
:
|
|
909
|
-
[],
|
|
910
|
-
...this.value.map(block => ([
|
|
911
|
-
Uint16Array.of(block.rows),
|
|
912
|
-
Uint8Array.of(block.unit, 0),
|
|
913
|
-
block.lengths,
|
|
914
|
-
block.data
|
|
915
|
-
])).flat()
|
|
916
|
-
];
|
|
917
|
-
return [
|
|
918
|
-
Uint32Array.of(this.rows, 1),
|
|
919
|
-
...DdbObj.pack_vector_body(value, type, this.rows)
|
|
920
|
-
];
|
|
921
|
-
case DdbForm.set:
|
|
922
|
-
return [new DdbObj({ ...this, form: DdbForm.vector }).pack()];
|
|
923
|
-
case DdbForm.table:
|
|
924
|
-
return [
|
|
925
|
-
Uint32Array.of(this.rows, this.cols),
|
|
926
|
-
DdbObj.enc.encode(this.name || ''),
|
|
927
|
-
// column names
|
|
928
|
-
Uint8Array.of(0),
|
|
929
|
-
...DdbObj.pack_vector_body(this.value.map((col, i) => col.name || `col${i}`), DdbType.string, this.cols),
|
|
930
|
-
// column vectors
|
|
931
|
-
...this.value.map(col => col.pack())
|
|
932
|
-
];
|
|
933
|
-
case DdbForm.dict:
|
|
934
|
-
return [value[0].pack(), value[1].pack()];
|
|
935
|
-
case DdbForm.chart: {
|
|
936
|
-
const { type, stacking, bin_start, bin_end, bin_count, titles: { chart, x_axis, y_axis }, extras, data } = this.value;
|
|
937
|
-
const { value: [keys, values] } = new DdbDict({
|
|
938
|
-
chartType: new DdbInt(type),
|
|
939
|
-
stacking,
|
|
940
|
-
...bin_start ? { binStart: bin_start, binEnd: bin_end } : {},
|
|
941
|
-
...bin_count ? { binCount: bin_count } : {},
|
|
942
|
-
title: new DdbVectorString([chart, x_axis, y_axis]),
|
|
943
|
-
...extras ? (() => {
|
|
944
|
-
const { multi_y_axes, ...extras_other } = extras;
|
|
945
|
-
return { extras: new DdbDict({ multiYAxes: multi_y_axes, ...extras_other }) };
|
|
946
|
-
})() : {},
|
|
947
|
-
data,
|
|
948
|
-
});
|
|
949
|
-
return [keys.pack(), values.pack()];
|
|
950
|
-
}
|
|
951
|
-
case DdbForm.matrix: {
|
|
952
|
-
const { rows, cols, data } = value;
|
|
953
|
-
return [
|
|
954
|
-
Uint8Array.of((rows ? 0x01 : 0x00) | (cols ? 0x02 : 0x00)),
|
|
955
|
-
...rows ? [rows.pack()] : [],
|
|
956
|
-
...cols ? [cols.pack()] : [],
|
|
957
|
-
Uint8Array.of(this.type, this.form),
|
|
958
|
-
Uint32Array.of(this.rows, this.cols),
|
|
959
|
-
...DdbObj.pack_vector_body(data, this.type, this.rows * this.cols)
|
|
960
|
-
];
|
|
961
|
-
}
|
|
962
|
-
default:
|
|
963
|
-
throw new Error(t('vector {{type}} 暂不支持序列化', { type: DdbType[type] || type }));
|
|
964
|
-
}
|
|
965
|
-
})();
|
|
966
|
-
if (!body)
|
|
967
|
-
return new Uint8Array(0);
|
|
968
|
-
return concat([header, ...body]);
|
|
969
|
-
}
|
|
970
|
-
static pack_vector_body(value, type, length) {
|
|
971
|
-
switch (type) {
|
|
972
|
-
case DdbType.bool:
|
|
973
|
-
return [value];
|
|
974
|
-
case DdbType.char:
|
|
975
|
-
return [value];
|
|
976
|
-
case DdbType.short:
|
|
977
|
-
return [value];
|
|
978
|
-
case DdbType.int:
|
|
979
|
-
// datetime
|
|
980
|
-
case DdbType.date:
|
|
981
|
-
case DdbType.month:
|
|
982
|
-
case DdbType.time:
|
|
983
|
-
case DdbType.minute:
|
|
984
|
-
case DdbType.second:
|
|
985
|
-
case DdbType.datetime:
|
|
986
|
-
case DdbType.datehour:
|
|
987
|
-
return [value];
|
|
988
|
-
case DdbType.float:
|
|
989
|
-
return [value];
|
|
990
|
-
case DdbType.double:
|
|
991
|
-
return [value];
|
|
992
|
-
case DdbType.long:
|
|
993
|
-
// timestamp
|
|
994
|
-
case DdbType.timestamp:
|
|
995
|
-
case DdbType.nanotime:
|
|
996
|
-
case DdbType.nanotimestamp:
|
|
997
|
-
return [value];
|
|
998
|
-
case DdbType.string:
|
|
999
|
-
case DdbType.symbol:
|
|
1000
|
-
case DdbType.handle:
|
|
1001
|
-
case DdbType.code: {
|
|
1002
|
-
let bufs = new Array(length * 2);
|
|
1003
|
-
for (let i = 0; i < length; i++) {
|
|
1004
|
-
bufs[2 * i] = this.enc.encode(value[i]);
|
|
1005
|
-
bufs[2 * i + 1] = Uint8Array.of(0);
|
|
1006
|
-
}
|
|
1007
|
-
return bufs;
|
|
1008
|
-
}
|
|
1009
|
-
case DdbType.uuid:
|
|
1010
|
-
case DdbType.ipaddr:
|
|
1011
|
-
case DdbType.int128:
|
|
1012
|
-
return [value];
|
|
1013
|
-
case DdbType.blob: {
|
|
1014
|
-
let bufs = new Array(length * 2);
|
|
1015
|
-
for (let i = 0; i < length; i++) {
|
|
1016
|
-
const blob_value = value[i];
|
|
1017
|
-
bufs[2 * i] = Uint32Array.of(blob_value.length);
|
|
1018
|
-
bufs[2 * i + 1] = blob_value;
|
|
1019
|
-
}
|
|
1020
|
-
return bufs;
|
|
1021
|
-
}
|
|
1022
|
-
case DdbType.complex:
|
|
1023
|
-
case DdbType.point:
|
|
1024
|
-
return [value];
|
|
1025
|
-
case DdbType.any: {
|
|
1026
|
-
// [1, 2, 'a', 'aaa']
|
|
1027
|
-
// any[4](<Buffer
|
|
1028
|
-
// 04 00 DdbType.int, DdbForm.scalar
|
|
1029
|
-
// 01 00 00 00
|
|
1030
|
-
// 04 00 DdbType.int, DdbForm.scalar
|
|
1031
|
-
// 02 00 00 00
|
|
1032
|
-
// 02 00 DdbType.char, DdbForm.scalar
|
|
1033
|
-
// 61
|
|
1034
|
-
// 12 00 DdbType.string, DdbForm.scalar
|
|
1035
|
-
// 61 61 61 00>)
|
|
1036
|
-
let bufs = new Array(length);
|
|
1037
|
-
for (let i = 0; i < length; i++)
|
|
1038
|
-
bufs[i] = value[i].pack();
|
|
1039
|
-
return bufs;
|
|
1040
|
-
}
|
|
1041
|
-
case DdbType.symbol_extended: {
|
|
1042
|
-
const { base_id, base, data } = value;
|
|
1043
|
-
return [
|
|
1044
|
-
Uint32Array.of(base_id || 0, base.length),
|
|
1045
|
-
...this.pack_vector_body(base, DdbType.string, base.length),
|
|
1046
|
-
data
|
|
1047
|
-
];
|
|
1048
|
-
}
|
|
1049
|
-
case DdbType.decimal32:
|
|
1050
|
-
case DdbType.decimal64: {
|
|
1051
|
-
const { scale, data } = value;
|
|
1052
|
-
return [Int32Array.of(scale), data];
|
|
1053
|
-
}
|
|
1054
|
-
default:
|
|
1055
|
-
throw new Error(t('vector {{type}} 暂不支持序列化', { type: String(DdbType[type] || type) }));
|
|
1056
|
-
}
|
|
1057
|
-
}
|
|
1058
|
-
toString(options = { nullstr: true, quote: true }) {
|
|
1059
|
-
const type = this.inspect_type();
|
|
1060
|
-
const data = (() => {
|
|
1061
|
-
switch (this.form) {
|
|
1062
|
-
case DdbForm.scalar:
|
|
1063
|
-
return format(this.type, this.value, this.le, options);
|
|
1064
|
-
case DdbForm.vector:
|
|
1065
|
-
case DdbForm.pair:
|
|
1066
|
-
case DdbForm.set: {
|
|
1067
|
-
const form = this.form;
|
|
1068
|
-
function format_array(items, ellipsis) {
|
|
1069
|
-
const str_items = items.join(', ') + (ellipsis ? ', ...' : '');
|
|
1070
|
-
return form === DdbForm.pair ?
|
|
1071
|
-
str_items
|
|
1072
|
-
:
|
|
1073
|
-
str_items.bracket('square');
|
|
1074
|
-
}
|
|
1075
|
-
if (64 <= this.type && this.type < 128) { // array vector
|
|
1076
|
-
// 因为 array vector 目前只支持:Logical, Integral(不包括 INT128, COMPRESS 类型), Floating, Temporal
|
|
1077
|
-
// 都对应 TypedArray 中的一格,所以直接根据 index 去取即可
|
|
1078
|
-
// av = array(INT[], 0, 5)
|
|
1079
|
-
// append!(av, [1..1])
|
|
1080
|
-
// append!(av, [1..70000])
|
|
1081
|
-
// append!(av, [1..1])
|
|
1082
|
-
// append!(av, [1..500])
|
|
1083
|
-
// ...
|
|
1084
|
-
// av
|
|
1085
|
-
const type_ = this.type - 64;
|
|
1086
|
-
const limit = 10;
|
|
1087
|
-
let array_items = new Array(Math.min(limit, this.rows));
|
|
1088
|
-
let i_items = 0;
|
|
1089
|
-
for (const { lengths, data } of this.value) {
|
|
1090
|
-
let acc_len = 0;
|
|
1091
|
-
for (const length of lengths) {
|
|
1092
|
-
let items = new Array(Math.min(limit, length));
|
|
1093
|
-
for (let i = 0; i < items.length; i++)
|
|
1094
|
-
switch (type_) {
|
|
1095
|
-
case DdbType.decimal32:
|
|
1096
|
-
case DdbType.decimal64:
|
|
1097
|
-
const x = data[acc_len + i];
|
|
1098
|
-
if (x === nulls.int64 /* && type_ === DdbType.decimal64 一定成立 */ ||
|
|
1099
|
-
x === nulls.int32 && type_ === DdbType.decimal32)
|
|
1100
|
-
return '';
|
|
1101
|
-
const { scale } = this.value;
|
|
1102
|
-
const s = String(x < 0 ? -x : x).padStart(scale, '0');
|
|
1103
|
-
const str = (x < 0 ? '-' : '') + (scale ? `${s.slice(0, -scale) || '0'}.${s.slice(-scale)}` : s);
|
|
1104
|
-
items[i] = options.colors ? green(str) : str;
|
|
1105
|
-
break;
|
|
1106
|
-
case DdbType.complex:
|
|
1107
|
-
case DdbType.point: {
|
|
1108
|
-
const index = acc_len + i;
|
|
1109
|
-
items[i] = format(type_, data.subarray(2 * index, 2 * (index + 1)), this.le, options);
|
|
1110
|
-
break;
|
|
1111
|
-
}
|
|
1112
|
-
case DdbType.uuid:
|
|
1113
|
-
case DdbType.int128:
|
|
1114
|
-
case DdbType.ipaddr: {
|
|
1115
|
-
const index = acc_len + i;
|
|
1116
|
-
items[i] = format(type_, data.subarray(16 * index, 16 * (index + 1)), this.le, options);
|
|
1117
|
-
break;
|
|
1118
|
-
}
|
|
1119
|
-
default:
|
|
1120
|
-
items[i] = format(type_, data[acc_len + i], this.le, options);
|
|
1121
|
-
break;
|
|
1122
|
-
}
|
|
1123
|
-
array_items[i_items++] = format_array(items, length > limit);
|
|
1124
|
-
acc_len += length;
|
|
1125
|
-
}
|
|
1126
|
-
if (i_items >= limit)
|
|
1127
|
-
break;
|
|
1128
|
-
}
|
|
1129
|
-
return format_array(array_items, this.rows > limit);
|
|
1130
|
-
}
|
|
1131
|
-
switch (this.type) {
|
|
1132
|
-
case DdbType.symbol_extended: {
|
|
1133
|
-
const limit = 50;
|
|
1134
|
-
const { base, data } = this.value;
|
|
1135
|
-
let items = new Array(Math.min(limit, data.length));
|
|
1136
|
-
for (let i = 0; i < items.length; i++)
|
|
1137
|
-
items[i] = base[data[i]].quote('single');
|
|
1138
|
-
return format_array(items, data.length > limit);
|
|
1139
|
-
}
|
|
1140
|
-
case DdbType.uuid:
|
|
1141
|
-
case DdbType.int128:
|
|
1142
|
-
case DdbType.ipaddr: {
|
|
1143
|
-
const limit = 10;
|
|
1144
|
-
const value = this.value;
|
|
1145
|
-
const len_data = value.length / 16;
|
|
1146
|
-
let items = new Array(Math.min(limit, len_data));
|
|
1147
|
-
for (let i = 0; i < items.length; i++)
|
|
1148
|
-
items[i] = format(this.type, value.subarray(16 * i, 16 * (i + 1)), this.le, options);
|
|
1149
|
-
return format_array(items, len_data > limit);
|
|
1150
|
-
}
|
|
1151
|
-
case DdbType.complex:
|
|
1152
|
-
case DdbType.point: {
|
|
1153
|
-
const limit = 20;
|
|
1154
|
-
const value = this.value;
|
|
1155
|
-
const len_data = value.length / 2;
|
|
1156
|
-
let items = new Array(Math.min(limit, len_data));
|
|
1157
|
-
for (let i = 0; i < items.length; i++)
|
|
1158
|
-
items[i] = format(this.type, value.subarray(2 * i, 2 * (i + 1)), this.le, options);
|
|
1159
|
-
return format_array(items, len_data > limit);
|
|
1160
|
-
}
|
|
1161
|
-
case DdbType.decimal32:
|
|
1162
|
-
case DdbType.decimal64: {
|
|
1163
|
-
const limit = 50;
|
|
1164
|
-
const { data } = this.value;
|
|
1165
|
-
let items = new Array(Math.min(limit, data.length));
|
|
1166
|
-
for (let i = 0; i < items.length; i++)
|
|
1167
|
-
items[i] = formati(this, i, options);
|
|
1168
|
-
return format_array(items, data.length > limit);
|
|
1169
|
-
}
|
|
1170
|
-
default: {
|
|
1171
|
-
const limit = 50;
|
|
1172
|
-
let items = new Array(Math.min(limit, this.value.length));
|
|
1173
|
-
for (let i = 0; i < items.length; i++)
|
|
1174
|
-
items[i] = format(this.type, this.value[i], this.le, options);
|
|
1175
|
-
return format_array(items, this.value.length > limit);
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
case DdbForm.chart:
|
|
1180
|
-
return JSON.stringify(this.value, (key, value) => key === 'data' ? value.toString(options) : value, 4);
|
|
1181
|
-
}
|
|
1182
|
-
return String(this.value);
|
|
1183
|
-
})();
|
|
1184
|
-
return `${options?.colors ? blue(type) : type}(${this.name ? `'${this.name}', ` : ''}${data})\n`;
|
|
1185
|
-
}
|
|
1186
|
-
inspect_type() {
|
|
1187
|
-
const tname = DdbType[this.type];
|
|
1188
|
-
switch (this.form) {
|
|
1189
|
-
case DdbForm.scalar:
|
|
1190
|
-
if (this.type === DdbType.functiondef)
|
|
1191
|
-
return `functiondef<${DdbFunctionType[this.value.type]}>`;
|
|
1192
|
-
return tname;
|
|
1193
|
-
case DdbForm.vector:
|
|
1194
|
-
if (64 <= this.type && this.type < 128)
|
|
1195
|
-
return `${DdbType[this.type - 64]}[][${this.rows}]`;
|
|
1196
|
-
return `${tname}[${this.rows}]`;
|
|
1197
|
-
case DdbForm.pair:
|
|
1198
|
-
return `pair<${tname}>`;
|
|
1199
|
-
case DdbForm.set:
|
|
1200
|
-
return `set<${tname}>[${this.rows}]`;
|
|
1201
|
-
case DdbForm.table:
|
|
1202
|
-
return `table[${this.rows}r][${this.cols}c]`;
|
|
1203
|
-
case DdbForm.dict:
|
|
1204
|
-
return `dict<${DdbType[this.value[0].type]}, ${DdbType[this.value[1].type]}>[${this.rows}]`;
|
|
1205
|
-
case DdbForm.chart:
|
|
1206
|
-
return `chart<${DdbChartType[this.value.type]}>`;
|
|
1207
|
-
case DdbForm.matrix:
|
|
1208
|
-
return `matrix<${tname}>[${this.rows}r][${this.cols}c]`;
|
|
1209
|
-
default:
|
|
1210
|
-
return `${DdbForm[this.form]} ${tname}`;
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
/** 自动转换 js string, boolean 为 DdbObj */
|
|
1214
|
-
static to_ddbobj(value) {
|
|
1215
|
-
if (value && value instanceof DdbObj)
|
|
1216
|
-
return value;
|
|
1217
|
-
const type = typeof value;
|
|
1218
|
-
switch (type) {
|
|
1219
|
-
case 'string':
|
|
1220
|
-
return new DdbString(value);
|
|
1221
|
-
case 'boolean':
|
|
1222
|
-
return new DdbBool(value);
|
|
1223
|
-
default:
|
|
1224
|
-
throw new Error(t('不能自动转换 {{type}} 至 DdbObj', { type }));
|
|
1225
|
-
}
|
|
1226
|
-
}
|
|
1227
|
-
/** 转换 js 数组为 DdbObj[] */
|
|
1228
|
-
static to_ddbobjs(values) {
|
|
1229
|
-
return values.map(value => this.to_ddbobj(value));
|
|
1230
|
-
}
|
|
1231
|
-
to_cols() {
|
|
1232
|
-
assert(this.form === DdbForm.table, t('form 必须是 DdbForm.table, 否则不能 to_cols'));
|
|
1233
|
-
return this.value.map(col => ({
|
|
1234
|
-
title: col.name,
|
|
1235
|
-
dataIndex: col.name,
|
|
1236
|
-
render: (value) => format(col.type, value, col.le, { nullstr: false, quote: false })
|
|
1237
|
-
}));
|
|
1238
|
-
}
|
|
1239
|
-
to_rows() {
|
|
1240
|
-
assert(this.form === DdbForm.table, t('form 必须是 DdbForm.table, 否则不能 to_rows'));
|
|
1241
|
-
let rows = new Array(this.rows);
|
|
1242
|
-
for (let i = 0; i < this.rows; i++) {
|
|
1243
|
-
let row = {};
|
|
1244
|
-
for (let j = 0; j < this.cols; j++) {
|
|
1245
|
-
const { type, name, value: values } = this.value[j]; // column
|
|
1246
|
-
switch (type) {
|
|
1247
|
-
case DdbType.bool: {
|
|
1248
|
-
const value = values[i];
|
|
1249
|
-
row[name] = value === nulls.int8 ?
|
|
1250
|
-
null
|
|
1251
|
-
:
|
|
1252
|
-
Boolean(value);
|
|
1253
|
-
break;
|
|
1254
|
-
}
|
|
1255
|
-
case DdbType.ipaddr:
|
|
1256
|
-
row[name] = values.subarray(16 * i, 16 * (i + 1));
|
|
1257
|
-
break;
|
|
1258
|
-
case DdbType.symbol_extended: {
|
|
1259
|
-
const { base, data } = values;
|
|
1260
|
-
row[name] = base[data[i]];
|
|
1261
|
-
break;
|
|
1262
|
-
}
|
|
1263
|
-
default:
|
|
1264
|
-
row[name] = values[i];
|
|
1265
|
-
}
|
|
1266
|
-
}
|
|
1267
|
-
rows[i] = row;
|
|
1268
|
-
}
|
|
1269
|
-
return rows;
|
|
1270
|
-
}
|
|
1271
|
-
to_dict({ strip, deep, } = {}) {
|
|
1272
|
-
assert(this.form === DdbForm.dict, t('this.form 必须是 DdbForm.dict, 否则不能调用 to_dict 转换为 js object'));
|
|
1273
|
-
const [{ value: keys, type: key_type }, { value: values, type: value_type }] = this.value;
|
|
1274
|
-
assert(key_type === DdbType.string && value_type === DdbType.any, t('当前只支持自动转换 dict<string, any> 为 js object'));
|
|
1275
|
-
assert(!(deep && !strip), t('deep = true 时必须设置 strip = true'));
|
|
1276
|
-
let obj = {};
|
|
1277
|
-
for (let i = 0; i < this.rows; i++) {
|
|
1278
|
-
let value = values[i];
|
|
1279
|
-
if (deep && value.form === DdbForm.dict)
|
|
1280
|
-
obj[keys[i]] = value.to_dict({ strip, deep });
|
|
1281
|
-
else
|
|
1282
|
-
obj[keys[i]] = strip ? value.value : value;
|
|
1283
|
-
}
|
|
1284
|
-
return obj;
|
|
1285
|
-
}
|
|
1286
|
-
}
|
|
1287
|
-
/** 整数一定用这个 number formatter, InspectOptions.decimals 不传也用这个 Integer must use this number formatter, InspectOptions.decimals also use this if not passed */
|
|
1288
|
-
let default_formatter = Intl.NumberFormat('en-US', { maximumFractionDigits: 20 });
|
|
1289
|
-
let _decimals = 20;
|
|
1290
|
-
/** 缓存,为了优化性能,通常 options.decimals 都是不变的 Cache, in order to optimize performance, usually options.decimals are unchanged */
|
|
1291
|
-
let _formatter = Intl.NumberFormat('en-US', { maximumFractionDigits: 20 });
|
|
1292
|
-
/** 根据 DdbType 格式化单个元素 (value) 为字符串 Formats a single element (value) as a string according to DdbType, null returns a 'null' string */
|
|
1293
|
-
export function format(type, value, le, options = {}) {
|
|
1294
|
-
const { decimals, nullstr = false, colors = false, quote = false } = options;
|
|
1295
|
-
const formatter = (() => {
|
|
1296
|
-
if (decimals === undefined || decimals === null)
|
|
1297
|
-
return default_formatter;
|
|
1298
|
-
if (decimals !== _decimals) {
|
|
1299
|
-
_decimals = decimals;
|
|
1300
|
-
_formatter = Intl.NumberFormat('en-US', { maximumFractionDigits: decimals, minimumFractionDigits: decimals });
|
|
1301
|
-
}
|
|
1302
|
-
return _formatter;
|
|
1303
|
-
})();
|
|
1304
|
-
function get_nullstr() {
|
|
1305
|
-
return nullstr ?
|
|
1306
|
-
colors ? grey('null') : 'null'
|
|
1307
|
-
:
|
|
1308
|
-
'';
|
|
1309
|
-
}
|
|
1310
|
-
switch (type) {
|
|
1311
|
-
case DdbType.bool:
|
|
1312
|
-
if (value === null || value === nulls.int8)
|
|
1313
|
-
return get_nullstr();
|
|
1314
|
-
else {
|
|
1315
|
-
const str = String(Boolean(value));
|
|
1316
|
-
return colors ? blue(str) : str;
|
|
1317
|
-
}
|
|
1318
|
-
case DdbType.char:
|
|
1319
|
-
if (value === null || value === nulls.int8)
|
|
1320
|
-
return get_nullstr();
|
|
1321
|
-
else {
|
|
1322
|
-
let str =
|
|
1323
|
-
// ascii printable
|
|
1324
|
-
// http://facweb.cs.depaul.edu/sjost/it212/documents/ascii-pr.htm
|
|
1325
|
-
(32 <= value && value <= 126) ?
|
|
1326
|
-
String.fromCharCode(value)
|
|
1327
|
-
:
|
|
1328
|
-
'\\' + String(value);
|
|
1329
|
-
if (quote)
|
|
1330
|
-
str = str.quote();
|
|
1331
|
-
return colors ? green(str) : str;
|
|
1332
|
-
}
|
|
1333
|
-
case DdbType.short:
|
|
1334
|
-
if (value === null || value === nulls.int16)
|
|
1335
|
-
return get_nullstr();
|
|
1336
|
-
else {
|
|
1337
|
-
const str = default_formatter.format(value);
|
|
1338
|
-
return colors ? green(str) : str;
|
|
1339
|
-
}
|
|
1340
|
-
case DdbType.int:
|
|
1341
|
-
if (value === null || value === nulls.int32)
|
|
1342
|
-
return get_nullstr();
|
|
1343
|
-
else {
|
|
1344
|
-
const str = default_formatter.format(value);
|
|
1345
|
-
return colors ? green(str) : str;
|
|
1346
|
-
}
|
|
1347
|
-
case DdbType.long:
|
|
1348
|
-
if (value === null || value === nulls.int64)
|
|
1349
|
-
return get_nullstr();
|
|
1350
|
-
else {
|
|
1351
|
-
const str = default_formatter.format(value);
|
|
1352
|
-
return colors ? green(str) : str;
|
|
1353
|
-
}
|
|
1354
|
-
case DdbType.date:
|
|
1355
|
-
if (value === null || value === nulls.int16)
|
|
1356
|
-
return get_nullstr();
|
|
1357
|
-
else {
|
|
1358
|
-
const str = date2str(value);
|
|
1359
|
-
return colors ? magenta(str) : str;
|
|
1360
|
-
}
|
|
1361
|
-
case DdbType.month:
|
|
1362
|
-
if (value === null || value === nulls.int32)
|
|
1363
|
-
return get_nullstr();
|
|
1364
|
-
else {
|
|
1365
|
-
const str = month2str(value);
|
|
1366
|
-
return colors ? magenta(str) : str;
|
|
1367
|
-
}
|
|
1368
|
-
case DdbType.time:
|
|
1369
|
-
if (value === null || value === nulls.int32)
|
|
1370
|
-
return get_nullstr();
|
|
1371
|
-
else {
|
|
1372
|
-
const str = time2str(value);
|
|
1373
|
-
return colors ? magenta(str) : str;
|
|
1374
|
-
}
|
|
1375
|
-
case DdbType.minute:
|
|
1376
|
-
if (value === null || value === nulls.int16)
|
|
1377
|
-
return get_nullstr();
|
|
1378
|
-
else {
|
|
1379
|
-
const str = minute2str(value);
|
|
1380
|
-
return colors ? magenta(str) : str;
|
|
1381
|
-
}
|
|
1382
|
-
case DdbType.second:
|
|
1383
|
-
if (value === null || value === nulls.int32)
|
|
1384
|
-
return get_nullstr();
|
|
1385
|
-
else {
|
|
1386
|
-
const str = second2str(value);
|
|
1387
|
-
return colors ? magenta(str) : str;
|
|
1388
|
-
}
|
|
1389
|
-
case DdbType.datetime:
|
|
1390
|
-
if (value === null || value === nulls.int32)
|
|
1391
|
-
return get_nullstr();
|
|
1392
|
-
else {
|
|
1393
|
-
const str = datetime2str(value);
|
|
1394
|
-
return colors ? magenta(str) : str;
|
|
1395
|
-
}
|
|
1396
|
-
case DdbType.timestamp:
|
|
1397
|
-
if (value === null || value === nulls.int64)
|
|
1398
|
-
return get_nullstr();
|
|
1399
|
-
else {
|
|
1400
|
-
const str = timestamp2str(value);
|
|
1401
|
-
return colors ? magenta(str) : str;
|
|
1402
|
-
}
|
|
1403
|
-
case DdbType.nanotime:
|
|
1404
|
-
if (value === null || value === nulls.int64)
|
|
1405
|
-
return get_nullstr();
|
|
1406
|
-
else {
|
|
1407
|
-
const str = nanotime2str(value);
|
|
1408
|
-
return colors ? magenta(str) : str;
|
|
1409
|
-
}
|
|
1410
|
-
case DdbType.nanotimestamp:
|
|
1411
|
-
if (value === null || value === nulls.int64)
|
|
1412
|
-
return get_nullstr();
|
|
1413
|
-
else {
|
|
1414
|
-
const str = nanotimestamp2str(value);
|
|
1415
|
-
return colors ? magenta(str) : str;
|
|
1416
|
-
}
|
|
1417
|
-
case DdbType.float:
|
|
1418
|
-
if (value === null || value === nulls.float32)
|
|
1419
|
-
return get_nullstr();
|
|
1420
|
-
else {
|
|
1421
|
-
const str = formatter.format(value);
|
|
1422
|
-
return colors ? green(str) : str;
|
|
1423
|
-
}
|
|
1424
|
-
case DdbType.double:
|
|
1425
|
-
if (value === null || value === nulls.double)
|
|
1426
|
-
return get_nullstr();
|
|
1427
|
-
else {
|
|
1428
|
-
const str = formatter.format(value);
|
|
1429
|
-
return colors ? green(str) : str;
|
|
1430
|
-
}
|
|
1431
|
-
case DdbType.symbol:
|
|
1432
|
-
case DdbType.string: {
|
|
1433
|
-
let str = value;
|
|
1434
|
-
if (quote)
|
|
1435
|
-
str = str.quote('single');
|
|
1436
|
-
return colors ? cyan(str) : str;
|
|
1437
|
-
}
|
|
1438
|
-
case DdbType.uuid: {
|
|
1439
|
-
const str = uuid2str(value, le);
|
|
1440
|
-
return colors ? cyan(str) : str;
|
|
1441
|
-
}
|
|
1442
|
-
case DdbType.functiondef: {
|
|
1443
|
-
const str = value.name.quote('single');
|
|
1444
|
-
return colors ? cyan(str) : str;
|
|
1445
|
-
}
|
|
1446
|
-
case DdbType.handle:
|
|
1447
|
-
case DdbType.code:
|
|
1448
|
-
case DdbType.resource: {
|
|
1449
|
-
const str = value.quote('single');
|
|
1450
|
-
return colors ? cyan(str) : str;
|
|
1451
|
-
}
|
|
1452
|
-
case DdbType.datehour:
|
|
1453
|
-
if (value === null || value === nulls.int32)
|
|
1454
|
-
return get_nullstr();
|
|
1455
|
-
else {
|
|
1456
|
-
const str = datehour2str(value);
|
|
1457
|
-
return colors ? magenta(str) : str;
|
|
1458
|
-
}
|
|
1459
|
-
case DdbType.ipaddr: {
|
|
1460
|
-
const str = ipaddr2str(value, le);
|
|
1461
|
-
return colors ? cyan(str) : str;
|
|
1462
|
-
}
|
|
1463
|
-
case DdbType.int128: {
|
|
1464
|
-
const str = int1282str(value, le);
|
|
1465
|
-
return colors ? cyan(str) : str;
|
|
1466
|
-
}
|
|
1467
|
-
case DdbType.blob: {
|
|
1468
|
-
const str = value.length > 100 ?
|
|
1469
|
-
DdbObj.dec.decode(value.subarray(0, 98)) + '…'
|
|
1470
|
-
:
|
|
1471
|
-
DdbObj.dec.decode(value);
|
|
1472
|
-
return colors ? cyan(str) : str;
|
|
1473
|
-
}
|
|
1474
|
-
case DdbType.point: {
|
|
1475
|
-
const [x, y] = value;
|
|
1476
|
-
return `(${format(DdbType.double, x, le, options)}, ${format(DdbType.double, y, le, options)})`;
|
|
1477
|
-
}
|
|
1478
|
-
case DdbType.complex: {
|
|
1479
|
-
const [x, y] = value;
|
|
1480
|
-
return `${format(DdbType.double, x, le, options)}+${format(DdbType.double, y, le, options)}i`;
|
|
1481
|
-
}
|
|
1482
|
-
case DdbType.duration: {
|
|
1483
|
-
const { data, unit } = value;
|
|
1484
|
-
const str = `${data}${DdbDurationUnit[unit]}`;
|
|
1485
|
-
return colors ? magenta(str) : str;
|
|
1486
|
-
}
|
|
1487
|
-
case DdbType.decimal32:
|
|
1488
|
-
case DdbType.decimal64: {
|
|
1489
|
-
const { scale, data } = value;
|
|
1490
|
-
if (data === null ||
|
|
1491
|
-
(data === nulls.int64 && type === DdbType.decimal64) ||
|
|
1492
|
-
(data === nulls.int32 && type === DdbType.decimal32))
|
|
1493
|
-
return get_nullstr();
|
|
1494
|
-
const s = String(data < 0 ? -data : data).padStart(scale, '0');
|
|
1495
|
-
const str = (data < 0 ? '-' : '') + (scale ? `${s.slice(0, -scale) || '0'}.${s.slice(-scale)}` : s);
|
|
1496
|
-
return colors ? green(str) : str;
|
|
1497
|
-
}
|
|
1498
|
-
default:
|
|
1499
|
-
return String(value);
|
|
1500
|
-
}
|
|
1501
|
-
}
|
|
1502
|
-
/** 格式化向量、集合中的第 index 项为字符串 formatted vector, the index-th item in the collection is a string */
|
|
1503
|
-
export function formati(obj, index, options = {}) {
|
|
1504
|
-
assert(index < obj.rows, 'index < obj.rows');
|
|
1505
|
-
if (64 <= obj.type && obj.type < 128) { // array vector
|
|
1506
|
-
// 因为 array vector 目前只支持:Logical, Integral(不包括 INT128, COMPRESS 类型), Floating, Temporal
|
|
1507
|
-
// 都对应 TypedArray 中的一格,所以 lengths.length 等于 block 中的 row 的个数
|
|
1508
|
-
// av = array(INT[], 0, 5)
|
|
1509
|
-
// append!(av, [1..1])
|
|
1510
|
-
// append!(av, [1..70000])
|
|
1511
|
-
// append!(av, [1..1])
|
|
1512
|
-
// append!(av, [1..500])
|
|
1513
|
-
// ...
|
|
1514
|
-
// av
|
|
1515
|
-
const type_ = obj.type - 64;
|
|
1516
|
-
let offset = 0;
|
|
1517
|
-
for (const { lengths, data, rows } of obj.value) {
|
|
1518
|
-
let acc_len = 0;
|
|
1519
|
-
if (offset + rows <= index) {
|
|
1520
|
-
offset += rows;
|
|
1521
|
-
continue; // 跳过这个 block
|
|
1522
|
-
}
|
|
1523
|
-
for (const length of lengths) {
|
|
1524
|
-
if (offset < index) {
|
|
1525
|
-
offset++;
|
|
1526
|
-
acc_len += length;
|
|
1527
|
-
continue;
|
|
1528
|
-
}
|
|
1529
|
-
const limit = 10;
|
|
1530
|
-
let items = new Array(Math.min(limit, length));
|
|
1531
|
-
for (let i = 0; i < items.length; i++)
|
|
1532
|
-
switch (type_) {
|
|
1533
|
-
case DdbType.decimal32:
|
|
1534
|
-
case DdbType.decimal64:
|
|
1535
|
-
const x = data[acc_len + i];
|
|
1536
|
-
if (x === nulls.int64 /* && type_ === DdbType.decimal64 一定成立 */ ||
|
|
1537
|
-
x === nulls.int32 && type_ === DdbType.decimal32)
|
|
1538
|
-
return '';
|
|
1539
|
-
const { scale } = obj.value;
|
|
1540
|
-
const s = String(x < 0 ? -x : x).padStart(scale, '0');
|
|
1541
|
-
const str = (x < 0 ? '-' : '') + (scale ? `${s.slice(0, -scale) || '0'}.${s.slice(-scale)}` : s);
|
|
1542
|
-
items[i] = options.colors ? green(str) : str;
|
|
1543
|
-
break;
|
|
1544
|
-
case DdbType.complex:
|
|
1545
|
-
case DdbType.point: {
|
|
1546
|
-
const index = acc_len + i;
|
|
1547
|
-
items[i] = format(type_, data.subarray(2 * index, 2 * (index + 1)), obj.le, options);
|
|
1548
|
-
break;
|
|
1549
|
-
}
|
|
1550
|
-
case DdbType.uuid:
|
|
1551
|
-
case DdbType.int128:
|
|
1552
|
-
case DdbType.ipaddr: {
|
|
1553
|
-
const index = acc_len + i;
|
|
1554
|
-
items[i] = format(type_, data.subarray(16 * index, 16 * (index + 1)), obj.le, options);
|
|
1555
|
-
break;
|
|
1556
|
-
}
|
|
1557
|
-
default:
|
|
1558
|
-
items[i] = format(type_, data[acc_len + i], obj.le, options);
|
|
1559
|
-
break;
|
|
1560
|
-
}
|
|
1561
|
-
return (items.join(', ') + (length > limit ? ', ...' : '')).bracket('square');
|
|
1562
|
-
}
|
|
1563
|
-
}
|
|
1564
|
-
}
|
|
1565
|
-
switch (obj.type) {
|
|
1566
|
-
case DdbType.symbol_extended: {
|
|
1567
|
-
const { base, data } = obj.value;
|
|
1568
|
-
return format(DdbType.string, base[data[index]], obj.le, options);
|
|
1569
|
-
}
|
|
1570
|
-
case DdbType.uuid:
|
|
1571
|
-
case DdbType.int128:
|
|
1572
|
-
case DdbType.ipaddr:
|
|
1573
|
-
return format(obj.type, obj.value.subarray(16 * index, 16 * (index + 1)), obj.le, options);
|
|
1574
|
-
case DdbType.blob: {
|
|
1575
|
-
const value = obj.value[index];
|
|
1576
|
-
return value.length > 100 ?
|
|
1577
|
-
DdbObj.dec.decode(value.subarray(0, 98)) + '…'
|
|
1578
|
-
:
|
|
1579
|
-
DdbObj.dec.decode(value);
|
|
1580
|
-
}
|
|
1581
|
-
case DdbType.complex:
|
|
1582
|
-
case DdbType.point:
|
|
1583
|
-
return format(obj.type, obj.value.subarray(2 * index, 2 * (index + 1)), obj.le, options);
|
|
1584
|
-
case DdbType.decimal32:
|
|
1585
|
-
case DdbType.decimal64: {
|
|
1586
|
-
const { scale, data } = obj.value;
|
|
1587
|
-
const x = data[index];
|
|
1588
|
-
if (x === nulls.int64 && obj.type === DdbType.decimal64 ||
|
|
1589
|
-
x === nulls.int32 && obj.type === DdbType.decimal32)
|
|
1590
|
-
return '';
|
|
1591
|
-
const s = String(x < 0 ? -x : x).padStart(scale, '0');
|
|
1592
|
-
const str = (x < 0 ? '-' : '') + (scale ? `${s.slice(0, -scale) || '0'}.${s.slice(-scale)}` : s);
|
|
1593
|
-
return options.colors ? green(str) : str;
|
|
1594
|
-
}
|
|
1595
|
-
default:
|
|
1596
|
-
return format(obj.type, obj.value[index], obj.le, options);
|
|
1597
|
-
}
|
|
1598
|
-
}
|
|
1599
|
-
export class DdbVoid extends DdbObj {
|
|
1600
|
-
constructor() {
|
|
1601
|
-
super({
|
|
1602
|
-
form: DdbForm.scalar,
|
|
1603
|
-
type: DdbType.void,
|
|
1604
|
-
value: null,
|
|
1605
|
-
});
|
|
1606
|
-
}
|
|
1607
|
-
}
|
|
1608
|
-
export class DdbBool extends DdbObj {
|
|
1609
|
-
constructor(value) {
|
|
1610
|
-
super({
|
|
1611
|
-
form: DdbForm.scalar,
|
|
1612
|
-
type: DdbType.bool,
|
|
1613
|
-
value,
|
|
1614
|
-
});
|
|
1615
|
-
}
|
|
1616
|
-
}
|
|
1617
|
-
export class DdbChar extends DdbObj {
|
|
1618
|
-
constructor(value) {
|
|
1619
|
-
super({
|
|
1620
|
-
form: DdbForm.scalar,
|
|
1621
|
-
type: DdbType.char,
|
|
1622
|
-
value: typeof value === 'string' ?
|
|
1623
|
-
value.charCodeAt(0)
|
|
1624
|
-
:
|
|
1625
|
-
value
|
|
1626
|
-
});
|
|
1627
|
-
}
|
|
1628
|
-
}
|
|
1629
|
-
export class DdbInt extends DdbObj {
|
|
1630
|
-
constructor(value) {
|
|
1631
|
-
super({
|
|
1632
|
-
form: DdbForm.scalar,
|
|
1633
|
-
type: DdbType.int,
|
|
1634
|
-
value,
|
|
1635
|
-
});
|
|
1636
|
-
}
|
|
1637
|
-
}
|
|
1638
|
-
export class DdbString extends DdbObj {
|
|
1639
|
-
constructor(value) {
|
|
1640
|
-
super({
|
|
1641
|
-
form: DdbForm.scalar,
|
|
1642
|
-
type: DdbType.string,
|
|
1643
|
-
value
|
|
1644
|
-
});
|
|
1645
|
-
}
|
|
1646
|
-
}
|
|
1647
|
-
export class DdbLong extends DdbObj {
|
|
1648
|
-
constructor(value) {
|
|
1649
|
-
super({
|
|
1650
|
-
form: DdbForm.scalar,
|
|
1651
|
-
type: DdbType.long,
|
|
1652
|
-
value
|
|
1653
|
-
});
|
|
1654
|
-
}
|
|
1655
|
-
}
|
|
1656
|
-
export class DdbDouble extends DdbObj {
|
|
1657
|
-
constructor(value) {
|
|
1658
|
-
super({
|
|
1659
|
-
form: DdbForm.scalar,
|
|
1660
|
-
type: DdbType.double,
|
|
1661
|
-
value
|
|
1662
|
-
});
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
export class DdbDateTime extends DdbObj {
|
|
1666
|
-
constructor(value) {
|
|
1667
|
-
super({
|
|
1668
|
-
form: DdbForm.scalar,
|
|
1669
|
-
type: DdbType.datetime,
|
|
1670
|
-
value
|
|
1671
|
-
});
|
|
1672
|
-
}
|
|
1673
|
-
}
|
|
1674
|
-
export class DdbTimeStamp extends DdbObj {
|
|
1675
|
-
constructor(value) {
|
|
1676
|
-
super({
|
|
1677
|
-
form: DdbForm.scalar,
|
|
1678
|
-
type: DdbType.timestamp,
|
|
1679
|
-
value
|
|
1680
|
-
});
|
|
1681
|
-
}
|
|
1682
|
-
}
|
|
1683
|
-
export class DdbNanoTimeStamp extends DdbObj {
|
|
1684
|
-
constructor(value) {
|
|
1685
|
-
super({
|
|
1686
|
-
form: DdbForm.scalar,
|
|
1687
|
-
type: DdbType.nanotimestamp,
|
|
1688
|
-
value
|
|
1689
|
-
});
|
|
1690
|
-
}
|
|
1691
|
-
}
|
|
1692
|
-
export class DdbPair extends DdbObj {
|
|
1693
|
-
constructor(l, r = null) {
|
|
1694
|
-
super({
|
|
1695
|
-
form: DdbForm.pair,
|
|
1696
|
-
type: DdbType.int,
|
|
1697
|
-
rows: 2,
|
|
1698
|
-
cols: 1,
|
|
1699
|
-
value: Int32Array.of(l === null ? nulls.int32 : l, r === null ? nulls.int32 : r)
|
|
1700
|
-
});
|
|
1701
|
-
}
|
|
1702
|
-
}
|
|
1703
|
-
export class DdbFunction extends DdbObj {
|
|
1704
|
-
constructor(name, type) {
|
|
1705
|
-
super({
|
|
1706
|
-
form: DdbForm.scalar,
|
|
1707
|
-
type: DdbType.functiondef,
|
|
1708
|
-
value: { type, name }
|
|
1709
|
-
});
|
|
1710
|
-
}
|
|
1711
|
-
}
|
|
1712
|
-
export class DdbVectorInt extends DdbObj {
|
|
1713
|
-
constructor(ints, name) {
|
|
1714
|
-
super({
|
|
1715
|
-
form: DdbForm.vector,
|
|
1716
|
-
type: DdbType.int,
|
|
1717
|
-
rows: ints.length,
|
|
1718
|
-
cols: 1,
|
|
1719
|
-
value: ints instanceof Int32Array ?
|
|
1720
|
-
ints
|
|
1721
|
-
:
|
|
1722
|
-
Int32Array.from(ints, v => v === null ?
|
|
1723
|
-
nulls.int32
|
|
1724
|
-
:
|
|
1725
|
-
v),
|
|
1726
|
-
name,
|
|
1727
|
-
});
|
|
1728
|
-
}
|
|
1729
|
-
}
|
|
1730
|
-
export class DdbVectorDouble extends DdbObj {
|
|
1731
|
-
constructor(doubles, name) {
|
|
1732
|
-
super({
|
|
1733
|
-
form: DdbForm.vector,
|
|
1734
|
-
type: DdbType.double,
|
|
1735
|
-
rows: doubles.length,
|
|
1736
|
-
cols: 1,
|
|
1737
|
-
value: doubles instanceof Float64Array ?
|
|
1738
|
-
doubles
|
|
1739
|
-
:
|
|
1740
|
-
Float64Array.from(doubles, v => v === null ?
|
|
1741
|
-
nulls.double
|
|
1742
|
-
:
|
|
1743
|
-
v),
|
|
1744
|
-
name,
|
|
1745
|
-
});
|
|
1746
|
-
}
|
|
1747
|
-
}
|
|
1748
|
-
export class DdbVectorString extends DdbObj {
|
|
1749
|
-
constructor(strings, name) {
|
|
1750
|
-
super({
|
|
1751
|
-
form: DdbForm.vector,
|
|
1752
|
-
type: DdbType.string,
|
|
1753
|
-
rows: strings.length,
|
|
1754
|
-
cols: 1,
|
|
1755
|
-
value: strings,
|
|
1756
|
-
name,
|
|
1757
|
-
});
|
|
1758
|
-
}
|
|
1759
|
-
}
|
|
1760
|
-
export class DdbVectorAny extends DdbObj {
|
|
1761
|
-
constructor(objs, name) {
|
|
1762
|
-
super({
|
|
1763
|
-
form: DdbForm.vector,
|
|
1764
|
-
type: DdbType.any,
|
|
1765
|
-
rows: objs.length,
|
|
1766
|
-
cols: 1,
|
|
1767
|
-
value: DdbObj.to_ddbobjs(objs),
|
|
1768
|
-
name,
|
|
1769
|
-
});
|
|
1770
|
-
}
|
|
1771
|
-
}
|
|
1772
|
-
export class DdbVectorSymbol extends DdbObj {
|
|
1773
|
-
constructor(strings, name) {
|
|
1774
|
-
let map = new Map([
|
|
1775
|
-
['', 0]
|
|
1776
|
-
]);
|
|
1777
|
-
let data = new Uint32Array(strings.length);
|
|
1778
|
-
for (let i = 0; i < strings.length; i++) {
|
|
1779
|
-
const x = strings[i];
|
|
1780
|
-
let index = map.get(x);
|
|
1781
|
-
if (index === undefined) {
|
|
1782
|
-
index = map.size;
|
|
1783
|
-
map.set(x, index);
|
|
1784
|
-
}
|
|
1785
|
-
data[i] = index;
|
|
1786
|
-
}
|
|
1787
|
-
super({
|
|
1788
|
-
form: DdbForm.vector,
|
|
1789
|
-
type: DdbType.symbol_extended,
|
|
1790
|
-
rows: strings.length,
|
|
1791
|
-
cols: 1,
|
|
1792
|
-
value: {
|
|
1793
|
-
base: [...map.keys()],
|
|
1794
|
-
base_id: null,
|
|
1795
|
-
data,
|
|
1796
|
-
},
|
|
1797
|
-
name
|
|
1798
|
-
});
|
|
1799
|
-
}
|
|
1800
|
-
}
|
|
1801
|
-
export class DdbSetInt extends DdbObj {
|
|
1802
|
-
constructor(ints) {
|
|
1803
|
-
super({
|
|
1804
|
-
form: DdbForm.set,
|
|
1805
|
-
type: DdbType.int,
|
|
1806
|
-
rows: ints instanceof Set ?
|
|
1807
|
-
ints.size
|
|
1808
|
-
:
|
|
1809
|
-
ints.length,
|
|
1810
|
-
cols: 1,
|
|
1811
|
-
value: ints instanceof Int32Array ?
|
|
1812
|
-
ints
|
|
1813
|
-
:
|
|
1814
|
-
Int32Array.from(ints, v => v === null ?
|
|
1815
|
-
nulls.int32
|
|
1816
|
-
:
|
|
1817
|
-
v),
|
|
1818
|
-
});
|
|
1819
|
-
}
|
|
1820
|
-
}
|
|
1821
|
-
export class DdbSetDouble extends DdbObj {
|
|
1822
|
-
constructor(doubles) {
|
|
1823
|
-
super({
|
|
1824
|
-
form: DdbForm.set,
|
|
1825
|
-
type: DdbType.double,
|
|
1826
|
-
rows: doubles instanceof Set ?
|
|
1827
|
-
doubles.size
|
|
1828
|
-
:
|
|
1829
|
-
doubles.length,
|
|
1830
|
-
cols: 1,
|
|
1831
|
-
value: doubles instanceof Int32Array ?
|
|
1832
|
-
doubles
|
|
1833
|
-
:
|
|
1834
|
-
Int32Array.from(doubles, v => v === null ?
|
|
1835
|
-
nulls.int32
|
|
1836
|
-
:
|
|
1837
|
-
v),
|
|
1838
|
-
});
|
|
1839
|
-
}
|
|
1840
|
-
}
|
|
1841
|
-
export class DdbSetString extends DdbObj {
|
|
1842
|
-
constructor(strings) {
|
|
1843
|
-
if (strings instanceof Set)
|
|
1844
|
-
strings = [...strings];
|
|
1845
|
-
super({
|
|
1846
|
-
form: DdbForm.set,
|
|
1847
|
-
type: DdbType.string,
|
|
1848
|
-
rows: strings.length,
|
|
1849
|
-
cols: 1,
|
|
1850
|
-
value: strings
|
|
1851
|
-
});
|
|
1852
|
-
}
|
|
1853
|
-
}
|
|
1854
|
-
/** 构造 DdbDict 对象,支持两种用法: Constructs a DdbDict object, which supports two usages:
|
|
1855
|
-
- 传入类型是 DdbVectorObj 的 keys, values 两个参数直接组成 dict<keys.type, values.type> 的 DdbDict
|
|
1856
|
-
The incoming type is the keys of DdbObj<DdbVectorValue>, and the two parameters of values directly form the DdbDict of dict<keys.type, values.type>
|
|
1857
|
-
- 传入 js object (类型是 Record<string, boolean | string | DdbObj>), 自动转换为 dict<string, any> 的 DdbDict
|
|
1858
|
-
Pass in js object (type is Record<string, boolean | string | DdbObj>), automatically converted to DdbDict of dict<string, any> */
|
|
1859
|
-
export class DdbDict extends DdbObj {
|
|
1860
|
-
constructor(arg0, arg1) {
|
|
1861
|
-
if (arg1)
|
|
1862
|
-
super({
|
|
1863
|
-
form: DdbForm.dict,
|
|
1864
|
-
type: arg1.type,
|
|
1865
|
-
rows: arg0.rows,
|
|
1866
|
-
cols: 2,
|
|
1867
|
-
value: [arg0, arg1]
|
|
1868
|
-
});
|
|
1869
|
-
else {
|
|
1870
|
-
const keys = Object.keys(arg0);
|
|
1871
|
-
super({
|
|
1872
|
-
form: DdbForm.dict,
|
|
1873
|
-
type: DdbType.any,
|
|
1874
|
-
rows: keys.length,
|
|
1875
|
-
cols: 2,
|
|
1876
|
-
value: [
|
|
1877
|
-
new DdbVectorString(keys),
|
|
1878
|
-
new DdbVectorAny(Object.values(arg0))
|
|
1879
|
-
]
|
|
1880
|
-
});
|
|
1881
|
-
}
|
|
1882
|
-
}
|
|
1883
|
-
}
|
|
1884
|
-
export class DdbTable extends DdbObj {
|
|
1885
|
-
constructor(columns, name = '') {
|
|
1886
|
-
super({
|
|
1887
|
-
form: DdbForm.table,
|
|
1888
|
-
type: DdbType.void,
|
|
1889
|
-
rows: columns[0].rows,
|
|
1890
|
-
cols: columns.length,
|
|
1891
|
-
name,
|
|
1892
|
-
value: columns,
|
|
1893
|
-
});
|
|
1894
|
-
}
|
|
1895
|
-
}
|
|
1896
|
-
export function date2ms(date) {
|
|
1897
|
-
// 将 server 的本地时间 (以 ms 为单位,1970.01.01 00:00:00 作为零点) 当成是客户端这里的本地的时间,然后根据本地的时区信息转换为 utc 时间
|
|
1898
|
-
// 本地的时区与实际的时间值相关,timezone offset 可能会受到夏令时 (DST) 的影响
|
|
1899
|
-
// 得到的 utc 毫秒数交给 js date 或者 dayjs 去格式化
|
|
1900
|
-
if (date === null || date === nulls.int32)
|
|
1901
|
-
return null;
|
|
1902
|
-
const ms = 1000 * 3600 * 24 * date;
|
|
1903
|
-
return 1000 * 60 * new Date(ms).getTimezoneOffset() + ms;
|
|
1904
|
-
}
|
|
1905
|
-
export function date2str(date, format = 'YYYY.MM.DD') {
|
|
1906
|
-
return (date === null || date === nulls.int32) ?
|
|
1907
|
-
'null'
|
|
1908
|
-
:
|
|
1909
|
-
dayjs(date2ms(date)).format(format);
|
|
1910
|
-
}
|
|
1911
|
-
export function month2ms(month) {
|
|
1912
|
-
return (month === null || month === nulls.int32) ?
|
|
1913
|
-
null
|
|
1914
|
-
:
|
|
1915
|
-
dayjs(month2str(month), 'YYYY.MM[M]').valueOf();
|
|
1916
|
-
}
|
|
1917
|
-
export function month2str(month) {
|
|
1918
|
-
if (month === null || month === nulls.int32)
|
|
1919
|
-
return 'null';
|
|
1920
|
-
if (month < 0)
|
|
1921
|
-
return String(month);
|
|
1922
|
-
const _month = month % 12;
|
|
1923
|
-
const year = Math.trunc(month / 12);
|
|
1924
|
-
return `${String(year).padStart(4, '0')}.${String(_month + 1).padStart(2, '0')}M`;
|
|
1925
|
-
}
|
|
1926
|
-
export function time2ms(time) {
|
|
1927
|
-
return (time === null || time === nulls.int32) ?
|
|
1928
|
-
null
|
|
1929
|
-
:
|
|
1930
|
-
1000 * 60 * new Date(time).getTimezoneOffset() + time;
|
|
1931
|
-
}
|
|
1932
|
-
export function time2str(time, format = 'HH:mm:ss.SSS') {
|
|
1933
|
-
return (time === null || time === nulls.int32) ?
|
|
1934
|
-
'null'
|
|
1935
|
-
:
|
|
1936
|
-
dayjs(time2ms(time)).format(format);
|
|
1937
|
-
}
|
|
1938
|
-
export function minute2ms(minute) {
|
|
1939
|
-
if (minute === null || minute === nulls.int32)
|
|
1940
|
-
return null;
|
|
1941
|
-
const ms = 60 * 1000 * minute;
|
|
1942
|
-
return 1000 * 60 * new Date(ms).getTimezoneOffset() + ms;
|
|
1943
|
-
}
|
|
1944
|
-
export function minute2str(minute, format = 'HH:mm[m]') {
|
|
1945
|
-
return (minute === null || minute === nulls.int32) ?
|
|
1946
|
-
'null'
|
|
1947
|
-
:
|
|
1948
|
-
dayjs(minute2ms(minute)).format(format);
|
|
1949
|
-
}
|
|
1950
|
-
export function second2ms(second) {
|
|
1951
|
-
if (second === null || second === nulls.int32)
|
|
1952
|
-
return null;
|
|
1953
|
-
const ms = 1000 * second;
|
|
1954
|
-
return 1000 * 60 * new Date(ms).getTimezoneOffset() + ms;
|
|
1955
|
-
}
|
|
1956
|
-
export function second2str(second, format = 'HH:mm:ss') {
|
|
1957
|
-
return (second === null || second === nulls.int32) ?
|
|
1958
|
-
'null'
|
|
1959
|
-
:
|
|
1960
|
-
dayjs(second2ms(second)).format(format);
|
|
1961
|
-
}
|
|
1962
|
-
export function datetime2ms(datetime) {
|
|
1963
|
-
if (datetime === null || datetime === nulls.int32)
|
|
1964
|
-
return null;
|
|
1965
|
-
const ms = 1000 * datetime;
|
|
1966
|
-
return 1000 * 60 * new Date(ms).getTimezoneOffset() + ms;
|
|
1967
|
-
}
|
|
1968
|
-
export function datetime2str(datetime, format = 'YYYY.MM.DD HH:mm:ss') {
|
|
1969
|
-
return (datetime === null || datetime === nulls.int32) ?
|
|
1970
|
-
'null'
|
|
1971
|
-
:
|
|
1972
|
-
dayjs(datetime2ms(datetime)).format(format);
|
|
1973
|
-
}
|
|
1974
|
-
export function timestamp2ms(timestamp) {
|
|
1975
|
-
if (timestamp === null || timestamp === nulls.int64)
|
|
1976
|
-
return null;
|
|
1977
|
-
const ms = Number(timestamp);
|
|
1978
|
-
return 1000 * 60 * new Date(ms).getTimezoneOffset() + ms;
|
|
1979
|
-
}
|
|
1980
|
-
/** format timestamp (bigint) to string
|
|
1981
|
-
- timestamp: bigint value
|
|
1982
|
-
- format?:
|
|
1983
|
-
格式串,默认是 `YYYY.MM.DD HH:mm:ss.SSS` format string, default to `YYYY.MM.DD HH:mm:ss.SSS`
|
|
1984
|
-
https://day.js.org/docs/en/parse/string-format#list-of-all-available-parsing-tokens
|
|
1985
|
-
*/
|
|
1986
|
-
export function timestamp2str(timestamp, format = 'YYYY.MM.DD HH:mm:ss.SSS') {
|
|
1987
|
-
return (timestamp === null || timestamp === nulls.int64) ?
|
|
1988
|
-
'null'
|
|
1989
|
-
:
|
|
1990
|
-
dayjs(timestamp2ms(timestamp)).format(format);
|
|
1991
|
-
}
|
|
1992
|
-
export function datehour2ms(datehour) {
|
|
1993
|
-
if (datehour === null || datehour === nulls.int32)
|
|
1994
|
-
return null;
|
|
1995
|
-
const ms = 1000 * 3600 * datehour;
|
|
1996
|
-
return 1000 * 60 * new Date(ms).getTimezoneOffset() + ms;
|
|
1997
|
-
}
|
|
1998
|
-
export function datehour2str(datehour, format = 'YYYY.MM.DDTHH') {
|
|
1999
|
-
if (datehour === null || datehour === nulls.int32)
|
|
2000
|
-
return 'null';
|
|
2001
|
-
const ms = 1000 * 3600 * datehour;
|
|
2002
|
-
return dayjs(1000 * 60 * new Date(ms).getTimezoneOffset() + ms).format(format);
|
|
2003
|
-
}
|
|
2004
|
-
/** parse timestamp string to bigint value
|
|
2005
|
-
- str: timestamp string, 如果为空字符串或 'null' 会返回对应的空值 (nulls.int64)
|
|
2006
|
-
timestamp string, If it is an empty string or 'null', it will return the corresponding empty value (nulls.int64)
|
|
2007
|
-
- format?:
|
|
2008
|
-
对应传入字符串的格式串,默认是 `YYYY.MM.DD HH:mm:ss.SSS`
|
|
2009
|
-
The format string corresponding to the incoming string, the default is `YYYY.MM.DD HH:mm:ss.SSS`
|
|
2010
|
-
https://day.js.org/docs/en/parse/string-format#list-of-all-available-parsing-tokens
|
|
2011
|
-
*/
|
|
2012
|
-
export function str2timestamp(str, format = 'YYYY.MM.DD HH:mm:ss.SSS') {
|
|
2013
|
-
if (!str || str === 'null')
|
|
2014
|
-
return nulls.int64;
|
|
2015
|
-
assert(str.length === format.length, t('timestamp 字符串长度必须等于格式串长度'));
|
|
2016
|
-
const ms = dayjs(str, format).valueOf();
|
|
2017
|
-
return BigInt(-(1000 * 60 * new Date(ms).getTimezoneOffset()) +
|
|
2018
|
-
ms);
|
|
2019
|
-
}
|
|
2020
|
-
export function nanotime2ns(nanotime) {
|
|
2021
|
-
return nanotimestamp2ns(nanotime);
|
|
2022
|
-
}
|
|
2023
|
-
export function nanotime2str(nanotime, format = 'HH:mm:ss.SSSSSSSSS') {
|
|
2024
|
-
if (nanotime === null || nanotime === nulls.int64)
|
|
2025
|
-
return 'null';
|
|
2026
|
-
if (nanotime < 0n)
|
|
2027
|
-
return String(nanotime);
|
|
2028
|
-
const i_second_start = format.indexOf('ss');
|
|
2029
|
-
assert(i_second_start !== -1, t('格式串必须包含秒的格式 (ss)'));
|
|
2030
|
-
const i_second_end = i_second_start + 2;
|
|
2031
|
-
const i_nanosecond_start = format.indexOf('SSSSSSSSS', i_second_end);
|
|
2032
|
-
assert(i_nanosecond_start !== -1, t('格式串必须包含纳秒的格式 (SSSSSSSSS)'));
|
|
2033
|
-
const ms = Number(nanotime) / 1000000;
|
|
2034
|
-
return (dayjs(1000 * 60 * new Date(ms).getTimezoneOffset() + ms).format(format.slice(0, i_second_end)) +
|
|
2035
|
-
format.slice(i_second_end, i_nanosecond_start) +
|
|
2036
|
-
String(nanotime % 1000000000n).padStart(9, '0'));
|
|
2037
|
-
}
|
|
2038
|
-
export function nanotimestamp2ns(nanotimestamp) {
|
|
2039
|
-
if (nanotimestamp === null || nanotimestamp === nulls.int64)
|
|
2040
|
-
return null;
|
|
2041
|
-
const ms = Number(nanotimestamp / 1000000n);
|
|
2042
|
-
return BigInt(1000 * 60 * new Date(ms).getTimezoneOffset()) * 1000000n + nanotimestamp;
|
|
2043
|
-
}
|
|
2044
|
-
/** format nanotimestamp value (bigint) to string
|
|
2045
|
-
- nanotimestamp: bigint value
|
|
2046
|
-
- format?:
|
|
2047
|
-
格式串,默认是 `YYYY.MM.DD HH:mm:ss.SSSSSSSSS` format string, default is `YYYY.MM.DD HH:mm:ss.SSSSSSSSS`
|
|
2048
|
-
秒的格式为 ss (必须包含); 纳秒的格式为 SSSSSSSSS (必须包含) Seconds are in the format ss (must be included); nanoseconds are in the format SSSSSSSSS (must be included)
|
|
2049
|
-
https://day.js.org/docs/en/parse/string-format#list-of-all-available-parsing-tokens
|
|
2050
|
-
*/
|
|
2051
|
-
export function nanotimestamp2str(nanotimestamp, format = 'YYYY.MM.DD HH:mm:ss.SSSSSSSSS') {
|
|
2052
|
-
// tests:
|
|
2053
|
-
// nanotimestamp2str(0n)
|
|
2054
|
-
// nanotimestamp2str(-1n)
|
|
2055
|
-
// nanotimestamp2str(-9_9999_9999n)
|
|
2056
|
-
// nanotimestamp2str(-10_0000_0000n)
|
|
2057
|
-
// nanotimestamp2str(-10_0000_0001n)
|
|
2058
|
-
if (nanotimestamp === null || nanotimestamp === nulls.int64)
|
|
2059
|
-
return 'null';
|
|
2060
|
-
const i_second_start = format.indexOf('ss');
|
|
2061
|
-
assert(i_second_start !== -1, t('格式串必须包含秒的格式 (ss)'));
|
|
2062
|
-
const i_second_end = i_second_start + 2;
|
|
2063
|
-
const i_nanosecond_start = format.indexOf('SSSSSSSSS', i_second_end);
|
|
2064
|
-
assert(i_nanosecond_start !== -1, t('格式串必须包含纳秒的格式 (SSSSSSSSS)'));
|
|
2065
|
-
const remainder = nanotimestamp % 1000000000n;
|
|
2066
|
-
const borrow = remainder < 0n;
|
|
2067
|
-
const ms = Number(nanotimestamp / 1000000n);
|
|
2068
|
-
return (dayjs(1000 * 60 * new Date(ms).getTimezoneOffset() +
|
|
2069
|
-
// 去掉 9 位的纳秒部分,转化为毫秒
|
|
2070
|
-
Number((nanotimestamp - remainder + (borrow ? -1000000000n : 0n)) / 1000000n)).format(format.slice(0, i_second_end)) +
|
|
2071
|
-
format.slice(i_second_end, i_nanosecond_start) +
|
|
2072
|
-
String(borrow ?
|
|
2073
|
-
(remainder + 1000000000n) % 1000000000n
|
|
2074
|
-
:
|
|
2075
|
-
remainder).padStart(9, '0'));
|
|
2076
|
-
}
|
|
2077
|
-
/** parse nano timestamp string to bigint value
|
|
2078
|
-
- str: nano timestamp string, 如果为空字符串或 'null' 会返回对应的空值 (nulls.int64)
|
|
2079
|
-
nano timestamp string, If it is an empty string or 'null', it will return the corresponding empty value (nulls.int64)
|
|
2080
|
-
- format?:
|
|
2081
|
-
对应传入字符串的格式串,默认是 `YYYY.MM.DD HH:mm:ss.SSSSSSSSS`
|
|
2082
|
-
秒的格式为 ss (必须包含); 纳秒的格式为 SSSSSSSSS (必须包含)
|
|
2083
|
-
https://day.js.org/docs/en/parse/string-format#list-of-all-available-parsing-tokens
|
|
2084
|
-
The format string corresponding to the incoming string, the default is `YYYY.MM.DD HH:mm:ss.SSSSSSSSS`
|
|
2085
|
-
Seconds are in the format ss (must be included); nanoseconds are in the format SSSSSSSSS (must be included) */
|
|
2086
|
-
export function str2nanotimestamp(str, format = 'YYYY.MM.DD HH:mm:ss.SSSSSSSSS') {
|
|
2087
|
-
if (!str || str === 'null')
|
|
2088
|
-
return nulls.int64;
|
|
2089
|
-
assert(str.length === format.length, t('nanotimestamp 字符串长度必须等于格式串长度'));
|
|
2090
|
-
const i_second_start = format.indexOf('ss');
|
|
2091
|
-
assert(i_second_start !== -1, t('格式串必须包含秒的格式 (ss)'));
|
|
2092
|
-
const i_second_end = i_second_start + 2;
|
|
2093
|
-
const i_nanosecond_start = format.indexOf('SSSSSSSSS', i_second_end);
|
|
2094
|
-
assert(i_nanosecond_start !== -1, t('格式串必须包含纳秒的格式 (SSSSSSSSS)'));
|
|
2095
|
-
const ms = dayjs(str.slice(0, i_second_end), format.slice(0, i_second_end)).valueOf();
|
|
2096
|
-
return (BigInt(-(1000 * 60 * new Date(ms).getTimezoneOffset()) +
|
|
2097
|
-
ms) * 1000000n
|
|
2098
|
-
+
|
|
2099
|
-
BigInt(str.slice(i_nanosecond_start, i_nanosecond_start + 9)));
|
|
2100
|
-
}
|
|
2101
|
-
export function ipaddr2str(buffer, le = true, ipv6) {
|
|
2102
|
-
let buf = buffer;
|
|
2103
|
-
if (le)
|
|
2104
|
-
buf = buffer.slice().reverse();
|
|
2105
|
-
const i_non_zero = buf.findIndex(x => x);
|
|
2106
|
-
if (ipv6 ||
|
|
2107
|
-
i_non_zero !== -1 && i_non_zero < 12) // ipv6
|
|
2108
|
-
return buf2ipaddr([...buf]).toString();
|
|
2109
|
-
else // ipv4
|
|
2110
|
-
return buf.subarray(12).join('.');
|
|
2111
|
-
}
|
|
2112
|
-
export function uuid2str(buffer, le = true) {
|
|
2113
|
-
const str = int1282str(buffer, le);
|
|
2114
|
-
return `${str.slice(0, 8)}-${str.slice(8, 12)}-${str.slice(12, 16)}-${str.slice(16, 20)}-${str.slice(20)}`;
|
|
2115
|
-
}
|
|
2116
|
-
export function int1282str(buffer, le = true) {
|
|
2117
|
-
let buf = buffer;
|
|
2118
|
-
if (le)
|
|
2119
|
-
buf = buffer.slice().reverse();
|
|
2120
|
-
return [...buf].map(x => x.toString(16)
|
|
2121
|
-
.padStart(2, '0')).join('');
|
|
2122
|
-
}
|
|
2123
|
-
export const winsize = 10_0000;
|
|
2124
|
-
export class DdbConnectionError extends Error {
|
|
2125
|
-
name = 'DdbConnectionError';
|
|
2126
|
-
ddb;
|
|
2127
|
-
constructor(ddb, error_options) {
|
|
2128
|
-
super(error_options?.cause ?
|
|
2129
|
-
error_options.cause.message
|
|
2130
|
-
:
|
|
2131
|
-
`${ddb.url} ${t('连接出错了,可能由于网络原因连接已被关闭,或服务器断开连接')}`, error_options);
|
|
2132
|
-
this.ddb = ddb;
|
|
2133
|
-
}
|
|
2134
|
-
}
|
|
2135
|
-
export class DdbDatabaseError extends Error {
|
|
2136
|
-
name = 'DdbDatabaseError';
|
|
2137
|
-
ddb;
|
|
2138
|
-
type;
|
|
2139
|
-
options;
|
|
2140
|
-
constructor(message, ddb, type, options) {
|
|
2141
|
-
super(message);
|
|
2142
|
-
this.ddb = ddb;
|
|
2143
|
-
this.type = type;
|
|
2144
|
-
this.options = options;
|
|
2145
|
-
}
|
|
2146
|
-
}
|
|
2147
|
-
export class DDB {
|
|
2148
|
-
/** 当前的 session id (http 或 tcp) */
|
|
2149
|
-
sid = '0';
|
|
2150
|
-
/** utf-8 text decoder */
|
|
2151
|
-
dec = new TextDecoder('utf-8');
|
|
2152
|
-
enc = new TextEncoder();
|
|
2153
|
-
/** DolphinDB WebSocket URL
|
|
2154
|
-
e.g. `ws://127.0.0.1:8848/`, `wss://dolphindb.com`
|
|
2155
|
-
*/
|
|
2156
|
-
url;
|
|
2157
|
-
websocket = null;
|
|
2158
|
-
/** little endian (server) */
|
|
2159
|
-
le = true;
|
|
2160
|
-
/** little endian (client) */
|
|
2161
|
-
static le_client = Boolean(new Uint8Array(Uint32Array.of(1).buffer)[0]);
|
|
2162
|
-
/** 是否在建立连接后自动登录,默认 true Whether to automatically log in after the connection is established, the default is true */
|
|
2163
|
-
autologin = true;
|
|
2164
|
-
/** DolphinDB 登录用户名 DolphinDB username */
|
|
2165
|
-
username = 'admin';
|
|
2166
|
-
/** DolphinDB 登录密码 DolphinDB password */
|
|
2167
|
-
password = '123456';
|
|
2168
|
-
/** python session flag (2048) */
|
|
2169
|
-
python = false;
|
|
2170
|
-
/** 是否为流数据连接,非流数据这个字段恒为 null Whether it is a streaming data connection, this field is always null for non-streaming data */
|
|
2171
|
-
streaming = null;
|
|
2172
|
-
// --- 内部选项, 状态
|
|
2173
|
-
print_message_buffer = false;
|
|
2174
|
-
print_object_buffer = false;
|
|
2175
|
-
print_message = true;
|
|
2176
|
-
parse_object = true;
|
|
2177
|
-
pnode_run_defined = false;
|
|
2178
|
-
/** DdbMessage listeners */
|
|
2179
|
-
listeners = [];
|
|
2180
|
-
pconnect = Promise.resolve();
|
|
2181
|
-
ppnoderun = Promise.resolve();
|
|
2182
|
-
presult = Promise.resolve(null);
|
|
2183
|
-
get connected() {
|
|
2184
|
-
return this.websocket?.readyState === WebSocket.OPEN;
|
|
2185
|
-
}
|
|
2186
|
-
/**
|
|
2187
|
-
使用 WebSocket URL 初始化连接到 DolphinDB 的实例(不建立实际的网络连接)
|
|
2188
|
-
Initialize an instance of DolphinDB Client using the WebSocket URL (without establishing an actual network connection)
|
|
2189
|
-
- url?: DolphinDB WebSocket URL,如:`ws://127.0.0.1:8848`, 默认为当前页面 URL
|
|
2190
|
-
DolphinDB WebSocket URL. e.g.:`ws://127.0.0.1:8848`, Defaults to the current page URL
|
|
2191
|
-
- options?:
|
|
2192
|
-
- autologin?: 是否在建立连接后自动登录,默认 `true` Whether to log in automatically after establishing a connection, default `true`
|
|
2193
|
-
- username?: DolphinDB 登录用户名,默认 `'admin'` DolphinDB username, default `'admin'`
|
|
2194
|
-
- password?: DolphinDB 登录密码,默认 `'123456'` DolphinDB password, default `'123456'`
|
|
2195
|
-
- python?: 设置 python session flag,默认 `false` set python session flag, default `false`
|
|
2196
|
-
- streaming?: 设置该选项后,该 WebSocket 连接只用于流数据 When this option is set, the WebSocket connection is only used for streaming data
|
|
2197
|
-
|
|
2198
|
-
@example
|
|
2199
|
-
let ddb = new DDB('ws://127.0.0.1:8848')
|
|
2200
|
-
|
|
2201
|
-
// 使用 HTTPS 加密 Encrypt with HTTPS
|
|
2202
|
-
let ddbsecure = new DDB('wss://dolphindb.com', {
|
|
2203
|
-
autologin: true,
|
|
2204
|
-
username: 'admin',
|
|
2205
|
-
password: '123456',
|
|
2206
|
-
python: false
|
|
2207
|
-
})
|
|
2208
|
-
*/
|
|
2209
|
-
constructor(url, options = {}) {
|
|
2210
|
-
if (!url) {
|
|
2211
|
-
const _url = new URL(location.href);
|
|
2212
|
-
const dev = _url.pathname.endsWith('/console/');
|
|
2213
|
-
const hostname = _url.searchParams.get('hostname') || (dev ? '127.0.0.1' : location.hostname);
|
|
2214
|
-
const port = _url.searchParams.get('port') || (dev ? '8848' : location.port);
|
|
2215
|
-
url = `${dev ? (_url.searchParams.get('tls') === '1' ? 'wss' : 'ws') : (location.protocol === 'https:' ? 'wss' : 'ws')}://${hostname}${port ? `:${port}` : ''}/`;
|
|
2216
|
-
}
|
|
2217
|
-
this.url = url;
|
|
2218
|
-
if (options.autologin !== undefined)
|
|
2219
|
-
this.autologin = options.autologin;
|
|
2220
|
-
if (options.username !== undefined)
|
|
2221
|
-
this.username = options.username;
|
|
2222
|
-
if (options.password !== undefined)
|
|
2223
|
-
this.password = options.password;
|
|
2224
|
-
if (options.python !== undefined)
|
|
2225
|
-
this.python = options.python;
|
|
2226
|
-
if (options.streaming !== undefined)
|
|
2227
|
-
this.streaming = options.streaming;
|
|
2228
|
-
}
|
|
2229
|
-
on_message(buffer) {
|
|
2230
|
-
// 这里的实现一定会被 connect 中的实现覆盖
|
|
2231
|
-
}
|
|
2232
|
-
/** 建立实际的 WebSocket 连接到 URL 对应的 DolphinDB Establish a actual websocket connection to the DolphindB corresponding to the URL
|
|
2233
|
-
是幂等的,调用后会确保已连接到数据库 (确保 websocket.readyState 为 open),否则报错 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
|
|
2234
|
-
this.autologin 为 true 时自动登录 this.autologin automatically log in when it is true */
|
|
2235
|
-
async connect() {
|
|
2236
|
-
if (this.connected)
|
|
2237
|
-
return;
|
|
2238
|
-
const ptail = this.pconnect;
|
|
2239
|
-
let resolve;
|
|
2240
|
-
this.pconnect = new Promise((_resolve, _reject) => {
|
|
2241
|
-
resolve = _resolve;
|
|
2242
|
-
});
|
|
2243
|
-
await ptail;
|
|
2244
|
-
try {
|
|
2245
|
-
if (!this.connected) {
|
|
2246
|
-
this.on_message = buffer => {
|
|
2247
|
-
assert(false, t('这是在调用 this.rpc 之前默认的 on_message, 不应该被调用到,除非建立连接后 server 先推送了 message'));
|
|
2248
|
-
};
|
|
2249
|
-
this.presult = Promise.resolve(null);
|
|
2250
|
-
this.pnode_run_defined = false;
|
|
2251
|
-
try {
|
|
2252
|
-
this.websocket = await connect_websocket(this.url, {
|
|
2253
|
-
protocols: (() => {
|
|
2254
|
-
if (this.streaming)
|
|
2255
|
-
return 'streaming';
|
|
2256
|
-
if (this.python)
|
|
2257
|
-
return 'python';
|
|
2258
|
-
})(),
|
|
2259
|
-
on_message: (buffer) => {
|
|
2260
|
-
this.on_message(buffer);
|
|
2261
|
-
}
|
|
2262
|
-
});
|
|
2263
|
-
}
|
|
2264
|
-
catch (error) {
|
|
2265
|
-
if (error instanceof WebSocketConnectionError)
|
|
2266
|
-
throw new DdbConnectionError(this, { cause: error });
|
|
2267
|
-
else
|
|
2268
|
-
throw error;
|
|
2269
|
-
}
|
|
2270
|
-
if (this.streaming)
|
|
2271
|
-
await this.subscribe();
|
|
2272
|
-
else {
|
|
2273
|
-
await this.rpc('connect', {});
|
|
2274
|
-
if (this.autologin)
|
|
2275
|
-
await this.call('login', [this.username, this.password], { urgent: true });
|
|
2276
|
-
}
|
|
2277
|
-
}
|
|
2278
|
-
}
|
|
2279
|
-
finally {
|
|
2280
|
-
resolve();
|
|
2281
|
-
}
|
|
2282
|
-
}
|
|
2283
|
-
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, } = {}) {
|
|
2284
|
-
let flag = 0;
|
|
2285
|
-
if (urgent)
|
|
2286
|
-
flag += 1;
|
|
2287
|
-
if (secondary)
|
|
2288
|
-
flag += 2;
|
|
2289
|
-
if (_async)
|
|
2290
|
-
flag += 4;
|
|
2291
|
-
if (pickle)
|
|
2292
|
-
flag += 8;
|
|
2293
|
-
if (clear)
|
|
2294
|
-
flag += 16;
|
|
2295
|
-
if (api)
|
|
2296
|
-
flag += 32;
|
|
2297
|
-
if (compress)
|
|
2298
|
-
flag += 64;
|
|
2299
|
-
// python session
|
|
2300
|
-
if (this.python)
|
|
2301
|
-
flag += 2048;
|
|
2302
|
-
const options = [
|
|
2303
|
-
flag,
|
|
2304
|
-
cancellable ? 1 : 0,
|
|
2305
|
-
priority,
|
|
2306
|
-
parallelism,
|
|
2307
|
-
...limit ? [
|
|
2308
|
-
root_id,
|
|
2309
|
-
limit,
|
|
2310
|
-
] : [],
|
|
2311
|
-
];
|
|
2312
|
-
return options.join('_');
|
|
2313
|
-
}
|
|
2314
|
-
disconnect() {
|
|
2315
|
-
if (this.connected)
|
|
2316
|
-
this.websocket.close(1000);
|
|
2317
|
-
}
|
|
2318
|
-
/** rpc through websocket (function/script/variable command)
|
|
2319
|
-
未连接到 DDB 时调用会自动连接,连接断开时调用会抛出 DdbConnectionError
|
|
2320
|
-
When the DDB is not connected, the call will be automatically connected. When the connection is disconnected, the call will throw the DdbConnectionError
|
|
2321
|
-
- type: API 类型: 'script' | 'function' | 'variable'
|
|
2322
|
-
- options:
|
|
2323
|
-
- urgent?: 决定 `行为标识` 那一行字符串的取值(只适用于 script 和 function)
|
|
2324
|
-
- vars?: type === 'variable' 时必传,variable 指令中待上传的变量名
|
|
2325
|
-
- listener?: 处理本次 rpc 期间的消息 (DdbMessage)
|
|
2326
|
-
- parse_object?: 在本次 rpc 期间设置 parse_object, 结束后恢复原有
|
|
2327
|
-
为 false 时返回的 DdbObj 仅含有 buffer 和 le,不做解析,以便后续转发、序列化
|
|
2328
|
-
*/
|
|
2329
|
-
async rpc(type, options) {
|
|
2330
|
-
if (!this.websocket)
|
|
2331
|
-
await this.connect();
|
|
2332
|
-
if (!this.connected)
|
|
2333
|
-
throw new DdbConnectionError(this);
|
|
2334
|
-
const { script, func, vars = [], urgent, listener, } = options;
|
|
2335
|
-
let { args = [] } = options;
|
|
2336
|
-
if (func === 'pnode_run' && !this.pnode_run_defined) {
|
|
2337
|
-
// 保证并发调用 rpc 时只定义一次 pnode_run
|
|
2338
|
-
const ptail = this.ppnoderun;
|
|
2339
|
-
let resolve;
|
|
2340
|
-
this.ppnoderun = new Promise((_resolve, _reject) => {
|
|
2341
|
-
resolve = _resolve;
|
|
2342
|
-
});
|
|
2343
|
-
await ptail;
|
|
2344
|
-
try {
|
|
2345
|
-
if (!this.pnode_run_defined)
|
|
2346
|
-
await this.eval(this.python ?
|
|
2347
|
-
'def pnode_run (nodes, func_name, args, add_node_alias):\n' +
|
|
2348
|
-
' nargs = size(args)\n' +
|
|
2349
|
-
' func = funcByName(func_name)\n' +
|
|
2350
|
-
' \n' +
|
|
2351
|
-
' if not nargs:\n' +
|
|
2352
|
-
' return pnodeRun(func, nodes, add_node_alias)\n' +
|
|
2353
|
-
' \n' +
|
|
2354
|
-
' args_partial = [ ]\n' +
|
|
2355
|
-
' args_partial.append(func)\n' +
|
|
2356
|
-
' for a in args:\n' +
|
|
2357
|
-
' args_partial.append(a)\n' +
|
|
2358
|
-
' \n' +
|
|
2359
|
-
' return pnodeRun(\n' +
|
|
2360
|
-
' unifiedCall(partial, args_partial),\n' +
|
|
2361
|
-
' nodes,\n' +
|
|
2362
|
-
' add_node_alias\n' +
|
|
2363
|
-
' )\n'
|
|
2364
|
-
:
|
|
2365
|
-
'def pnode_run (nodes, func_name, args, add_node_alias = true) {\n' +
|
|
2366
|
-
' nargs = size(args)\n' +
|
|
2367
|
-
' func = funcByName(func_name)\n' +
|
|
2368
|
-
' \n' +
|
|
2369
|
-
' if (!nargs)\n' +
|
|
2370
|
-
' return pnodeRun(func, nodes, add_node_alias)\n' +
|
|
2371
|
-
' \n' +
|
|
2372
|
-
' args_partial = array(any, 1 + nargs, 1 + nargs)\n' +
|
|
2373
|
-
' args_partial[0] = func\n' +
|
|
2374
|
-
' args_partial[1:] = args\n' +
|
|
2375
|
-
' return pnodeRun(\n' +
|
|
2376
|
-
' unifiedCall(partial, args_partial),\n' +
|
|
2377
|
-
' nodes,\n' +
|
|
2378
|
-
' add_node_alias\n' +
|
|
2379
|
-
' )\n' +
|
|
2380
|
-
'}\n', { urgent: true });
|
|
2381
|
-
}
|
|
2382
|
-
finally {
|
|
2383
|
-
resolve();
|
|
2384
|
-
}
|
|
2385
|
-
}
|
|
2386
|
-
// this 上的当前配置需要在 message 到达后使用,先保存起来
|
|
2387
|
-
const _handlers = [...this.listeners].reverse();
|
|
2388
|
-
let error = new DdbDatabaseError('', this, type, options);
|
|
2389
|
-
// 临界区:保证多个 rpc 并发时形成 promise 链
|
|
2390
|
-
// ddb 世界观:需要等待上一个 rpc 结果从 server 返回之后才能发起下一个调用
|
|
2391
|
-
// 违反世界观可能造成:
|
|
2392
|
-
// 1. 并发多个请求只返回第一个结果(阻塞,需后续请求疏通)
|
|
2393
|
-
// 2. windows 下 ddb server 返回多个相同的结果
|
|
2394
|
-
const ptail = this.presult;
|
|
2395
|
-
let resolve;
|
|
2396
|
-
let reject;
|
|
2397
|
-
const presult = this.presult = new Promise((_resolve, _reject) => {
|
|
2398
|
-
resolve = _resolve;
|
|
2399
|
-
reject = _reject;
|
|
2400
|
-
});
|
|
2401
|
-
try {
|
|
2402
|
-
await ptail;
|
|
2403
|
-
}
|
|
2404
|
-
catch { }
|
|
2405
|
-
// 临界区结束,只有一个 rpc 函数调用运行到这里,可以独占 this.on_message 然后写 WebSocket
|
|
2406
|
-
this.on_message = (buffer) => {
|
|
2407
|
-
try {
|
|
2408
|
-
const buf = new Uint8Array(buffer);
|
|
2409
|
-
if (this.print_message_buffer)
|
|
2410
|
-
console.log(buf);
|
|
2411
|
-
const message = this.parse_message(buf, error);
|
|
2412
|
-
listener?.(message, this);
|
|
2413
|
-
for (const listener of _handlers)
|
|
2414
|
-
listener(message, this);
|
|
2415
|
-
const { type, data } = message;
|
|
2416
|
-
switch (type) {
|
|
2417
|
-
case 'print':
|
|
2418
|
-
if (this.print_message)
|
|
2419
|
-
console.log(data);
|
|
2420
|
-
return;
|
|
2421
|
-
case 'object':
|
|
2422
|
-
resolve(data);
|
|
2423
|
-
return;
|
|
2424
|
-
case 'error':
|
|
2425
|
-
reject(data);
|
|
2426
|
-
return;
|
|
2427
|
-
}
|
|
2428
|
-
}
|
|
2429
|
-
catch (error) {
|
|
2430
|
-
reject(error);
|
|
2431
|
-
}
|
|
2432
|
-
};
|
|
2433
|
-
args = DdbObj.to_ddbobjs(args);
|
|
2434
|
-
const command = this.enc.encode((() => {
|
|
2435
|
-
switch (type) {
|
|
2436
|
-
case 'function':
|
|
2437
|
-
return 'function\n' +
|
|
2438
|
-
`${func}\n` +
|
|
2439
|
-
`${args.length}\n` +
|
|
2440
|
-
`${Number(DDB.le_client)}\n`;
|
|
2441
|
-
case 'script':
|
|
2442
|
-
return 'script\n' +
|
|
2443
|
-
script;
|
|
2444
|
-
case 'variable':
|
|
2445
|
-
return 'variable\n' +
|
|
2446
|
-
`${vars.join(',')}\n` +
|
|
2447
|
-
`${vars.length}\n` +
|
|
2448
|
-
`${Number(DDB.le_client)}\n`;
|
|
2449
|
-
case 'connect':
|
|
2450
|
-
return 'connect\n';
|
|
2451
|
-
}
|
|
2452
|
-
})());
|
|
2453
|
-
this.websocket.send(concat([
|
|
2454
|
-
this.enc.encode(`API2 ${this.sid} ${command.length} / ${this.get_rpc_options({ urgent })}\n`),
|
|
2455
|
-
command,
|
|
2456
|
-
...args.map((arg) => arg.pack())
|
|
2457
|
-
]));
|
|
2458
|
-
return presult;
|
|
2459
|
-
}
|
|
2460
|
-
/** eval script through websocket (script command)
|
|
2461
|
-
- script?: 执行的脚本 Script to execute
|
|
2462
|
-
- options?: 执行选项 execution options
|
|
2463
|
-
- urgent?: 紧急 flag,确保提交的脚本使用 urgent worker 处理,防止被其它作业阻塞
|
|
2464
|
-
Urgent flag to ensure that submitted scripts are processed by urgent workers to prevent being blocked by other jobs
|
|
2465
|
-
- listener?: 处理本次 rpc 期间的消息 (DdbMessage) Process messages during this rpc (DdbMessage)
|
|
2466
|
-
- parse_object?: 在该次 rpc 期间设置 parse_object, 结束后恢复原有,为 false 时返回的 DdbObj 仅含有 buffer 和 le,
|
|
2467
|
-
不做解析,以便后续转发、序列化
|
|
2468
|
-
Set parse_object during this rpc, and restore the original after the end.
|
|
2469
|
-
When it is false, the returned DdbObj only contains buffer and le without parsing,
|
|
2470
|
-
so as to facilitate subsequent forwarding and serialization
|
|
2471
|
-
*/
|
|
2472
|
-
async eval(script, { urgent, listener, parse_object, } = {}) {
|
|
2473
|
-
return this.rpc('script', { script, urgent, listener, parse_object });
|
|
2474
|
-
}
|
|
2475
|
-
/** call function through websocket (function command)
|
|
2476
|
-
- func: 函数名 function name
|
|
2477
|
-
- args?: `[ ]` 调用参数 (传入的原生 string 和 boolean 会被自动转换为 DdbObj<string> 和 DdbObj<boolean>)
|
|
2478
|
-
Call parameters (the incoming native string and boolean will be automatically converted to DdbObj<string> and DdbObj<boolean>)
|
|
2479
|
-
- options?: 调用选项 call options
|
|
2480
|
-
- urgent?: 紧急 flag。使用 urgent worker 执行,防止被其它作业阻塞
|
|
2481
|
-
Emergency flag. Use urgent worker execution to prevent being blocked by other jobs
|
|
2482
|
-
- node?: 设置结点 alias 时发送到集群中对应的结点执行 (使用 DolphinDB 中的 rpc 方法)
|
|
2483
|
-
When the node alias is set, it is sent to the corresponding node in the cluster for execution (using the rpc method in DolphinDB)
|
|
2484
|
-
- nodes?: 设置多个结点 alias 时发送到集群中对应的多个结点执行 (使用 DolphinDB 中的 pnodeRun 方法)
|
|
2485
|
-
When setting multiple node aliases, send them to the corresponding multiple nodes in the cluster for execution (using the pnodeRun method in DolphinDB)
|
|
2486
|
-
- func_type?: 设置 node 参数时必传,需指定函数类型,其它情况下不传
|
|
2487
|
-
It must be passed when setting the node parameter, the function type needs to be specified, and it is not passed in other cases
|
|
2488
|
-
- add_node_alias?: 设置 nodes 参数时选传,其它情况不传
|
|
2489
|
-
Select to pass when setting the nodes parameter, otherwise not pass
|
|
2490
|
-
- listener?: 处理本次 rpc 期间的消息 (DdbMessage)
|
|
2491
|
-
Process messages during this rpc (DdbMessage)
|
|
2492
|
-
- parse_object?: 在该次 rpc 期间设置 parse_object, 结束后恢复原有,为 false 时返回的 DdbObj 仅含有 buffer 和 le,
|
|
2493
|
-
不做解析,以便后续转发、序列化
|
|
2494
|
-
Set parse_object during this rpc, and restore the original after the end.
|
|
2495
|
-
When it is false, the returned DdbObj only contains buffer and le without parsing,
|
|
2496
|
-
so as to facilitate subsequent forwarding and serialization
|
|
2497
|
-
*/
|
|
2498
|
-
async call(func, args = [], { urgent, node, nodes, func_type, add_node_alias, listener, parse_object, } = {}) {
|
|
2499
|
-
if (node) {
|
|
2500
|
-
assert(func_type in DdbFunctionType, t('指定 node 时必须设置 func_type'));
|
|
2501
|
-
args = [
|
|
2502
|
-
node,
|
|
2503
|
-
new DdbFunction(func, func_type),
|
|
2504
|
-
...args
|
|
2505
|
-
];
|
|
2506
|
-
func = 'rpc';
|
|
2507
|
-
}
|
|
2508
|
-
if (nodes) {
|
|
2509
|
-
args = [
|
|
2510
|
-
new DdbVectorString(nodes),
|
|
2511
|
-
func,
|
|
2512
|
-
new DdbVectorAny(args),
|
|
2513
|
-
...(() => {
|
|
2514
|
-
if (typeof add_node_alias !== 'undefined')
|
|
2515
|
-
return [add_node_alias];
|
|
2516
|
-
if (this.python)
|
|
2517
|
-
return [true];
|
|
2518
|
-
return [];
|
|
2519
|
-
})()
|
|
2520
|
-
];
|
|
2521
|
-
func = 'pnode_run';
|
|
2522
|
-
}
|
|
2523
|
-
return this.rpc('function', {
|
|
2524
|
-
func,
|
|
2525
|
-
args,
|
|
2526
|
-
urgent,
|
|
2527
|
-
listener,
|
|
2528
|
-
parse_object
|
|
2529
|
-
});
|
|
2530
|
-
}
|
|
2531
|
-
/** upload variable through websocket (variable command) */
|
|
2532
|
-
async upload(
|
|
2533
|
-
/** 上传的变量名 Uploaded variables' name */
|
|
2534
|
-
vars,
|
|
2535
|
-
/** 上传的变量值 Uploaded variables' value */
|
|
2536
|
-
args, { listener, parse_object, } = {}) {
|
|
2537
|
-
assert(args.length && args.length === vars.length, t('variable 指令参数不能为空且参数名不能为空,且数量应该匹配'));
|
|
2538
|
-
return this.rpc('variable', { vars, args, listener, parse_object });
|
|
2539
|
-
}
|
|
2540
|
-
/** 取消当前 session id 对应的所有 console jobs Cancel all console jobs corresponding to the current session id */
|
|
2541
|
-
async cancel() {
|
|
2542
|
-
let ddb = new DDB(this.url, this);
|
|
2543
|
-
try {
|
|
2544
|
-
// 因为是新建的连接,而且执行完脚本之后马上就关闭了,所以不用考虑变量泄漏的问题
|
|
2545
|
-
await ddb.eval(`jobs = exec rootJobId from getConsoleJobs() where sessionId = ${this.sid}\n` +
|
|
2546
|
-
(this.python ? 'if size(jobs):\n' : 'if (size(jobs))\n') +
|
|
2547
|
-
' cancelConsoleJob(jobs)\n', { urgent: true });
|
|
2548
|
-
}
|
|
2549
|
-
finally {
|
|
2550
|
-
ddb.disconnect();
|
|
2551
|
-
}
|
|
2552
|
-
}
|
|
2553
|
-
/** 解析服务端响应报文,返回去掉 header 的 data buf */
|
|
2554
|
-
parse_message(buf, error) {
|
|
2555
|
-
// MSG\n
|
|
2556
|
-
// <message>\0
|
|
2557
|
-
// 'M'.codePointAt(0).to_hex_str()
|
|
2558
|
-
if (buf[0] === 0x4d && buf[1] === 0x53 && buf[2] === 0x47 && buf[3] === 0x0a) {
|
|
2559
|
-
assert(buf.at(-1) === 0, t('print 消息的 buffer 应该以 \\0 结束'));
|
|
2560
|
-
if (buf.indexOf(0) !== buf.length - 1)
|
|
2561
|
-
console.warn(t('print 消息的 buffer 中间不应该有 \\0'));
|
|
2562
|
-
return {
|
|
2563
|
-
type: 'print',
|
|
2564
|
-
data: this.dec.decode(buf.subarray(4, -1))
|
|
2565
|
-
};
|
|
2566
|
-
}
|
|
2567
|
-
// '1166953221 1 1\n'
|
|
2568
|
-
// 'OK\n'
|
|
2569
|
-
// '\x04\x00\x02\x00\x00\x00'
|
|
2570
|
-
/** index of line feed 0 */
|
|
2571
|
-
const ilf0 = buf.indexOf(0x0a); // '\n'
|
|
2572
|
-
const parts = this.dec.decode(buf.subarray(0, ilf0)).split(' ');
|
|
2573
|
-
/** session id */
|
|
2574
|
-
const sid = parts[0];
|
|
2575
|
-
if (sid !== this.sid) {
|
|
2576
|
-
console.log(t('session id 从 {{sid}} 变为 {{sid_}}', { sid: this.sid, sid_: sid }));
|
|
2577
|
-
this.sid = sid;
|
|
2578
|
-
}
|
|
2579
|
-
/** 返回对象的数量 */
|
|
2580
|
-
const nobj = Number(parts[1]);
|
|
2581
|
-
/** 大小端: 协议中大端为 0, 小端为 1 */
|
|
2582
|
-
this.le = Number(parts[2]) !== 0;
|
|
2583
|
-
const ils1 = ilf0 + 1;
|
|
2584
|
-
const ilf1 = buf.indexOf(0x0a, ils1); // '\n'
|
|
2585
|
-
/** 'OK' 表示成功,其它文本表示失败 */
|
|
2586
|
-
const message = this.dec.decode(buf.subarray(ils1, ilf1));
|
|
2587
|
-
if (message !== 'OK') {
|
|
2588
|
-
error.message = message;
|
|
2589
|
-
return { type: 'error', data: error };
|
|
2590
|
-
}
|
|
2591
|
-
const bufobj = buf.subarray(ilf1 + 1);
|
|
2592
|
-
if (this.print_object_buffer)
|
|
2593
|
-
console.log(bufobj);
|
|
2594
|
-
return {
|
|
2595
|
-
type: 'object',
|
|
2596
|
-
data: error.options.parse_object ?? this.parse_object ?
|
|
2597
|
-
DdbObj.parse(bufobj, this.le)
|
|
2598
|
-
:
|
|
2599
|
-
new DdbObj({
|
|
2600
|
-
form: DdbForm.scalar,
|
|
2601
|
-
type: DdbType.void,
|
|
2602
|
-
length: 0,
|
|
2603
|
-
le: this.le,
|
|
2604
|
-
buffer: bufobj,
|
|
2605
|
-
})
|
|
2606
|
-
};
|
|
2607
|
-
}
|
|
2608
|
-
/** 内部的流订阅方法 Internal stream subscription method */
|
|
2609
|
-
async subscribe() {
|
|
2610
|
-
await this.rpc('connect', {});
|
|
2611
|
-
if (this.autologin)
|
|
2612
|
-
await this.call('login', [this.username, this.password]);
|
|
2613
|
-
console.log(t('订阅流表成功') + ', colnames:',
|
|
2614
|
-
// string[3](['time', 'stock', 'price'])
|
|
2615
|
-
this.streaming.colnames = (await this.call('publishTable', [
|
|
2616
|
-
'localhost',
|
|
2617
|
-
new DdbInt(0),
|
|
2618
|
-
this.streaming.table,
|
|
2619
|
-
(this.streaming.action ||= `api_js_${new Date().getTime()}`),
|
|
2620
|
-
// new DdbInt(-1), // offset
|
|
2621
|
-
// filter
|
|
2622
|
-
// allow exists
|
|
2623
|
-
])).value);
|
|
2624
|
-
this.streaming.window = {
|
|
2625
|
-
offset: 0,
|
|
2626
|
-
rows: 0,
|
|
2627
|
-
segments: [],
|
|
2628
|
-
};
|
|
2629
|
-
// 先准备好收到 websocket message 的 callback
|
|
2630
|
-
this.on_message = buffer => {
|
|
2631
|
-
let { streaming } = this;
|
|
2632
|
-
try {
|
|
2633
|
-
const dv = new DataView(buffer);
|
|
2634
|
-
const buf = new Uint8Array(buffer);
|
|
2635
|
-
streaming.time = dv.getBigInt64(1, this.le);
|
|
2636
|
-
streaming.id = dv.getBigInt64(9, this.le);
|
|
2637
|
-
const i_topic_end = buf.indexOf(0, 17);
|
|
2638
|
-
streaming.topic = this.dec.decode(buf.subarray(17, i_topic_end));
|
|
2639
|
-
// 是 column 片段组成的 any vector
|
|
2640
|
-
const data = streaming.data = DdbObj.parse(buf.subarray(i_topic_end + 1), this.le);
|
|
2641
|
-
let { window: win } = streaming;
|
|
2642
|
-
win.rows += streaming.rows = data.value[0].rows;
|
|
2643
|
-
win.segments.push(data);
|
|
2644
|
-
if (win.rows >= winsize * 2 && win.segments.length >= 2) {
|
|
2645
|
-
let winsize_ = 0;
|
|
2646
|
-
let i = win.segments.length - 1;
|
|
2647
|
-
// 往前移动至首个累计 winsize_ 超过 winsize 的位置
|
|
2648
|
-
for (; winsize_ < winsize; i--)
|
|
2649
|
-
winsize_ += win.segments[i].value[0].rows;
|
|
2650
|
-
win.segments = win.segments.slice(i);
|
|
2651
|
-
win.offset += win.rows - winsize_;
|
|
2652
|
-
win.rows = winsize_;
|
|
2653
|
-
}
|
|
2654
|
-
}
|
|
2655
|
-
catch (error) {
|
|
2656
|
-
// 将 error 交给 handler 处理
|
|
2657
|
-
streaming.error = error;
|
|
2658
|
-
}
|
|
2659
|
-
this.streaming.handler(streaming);
|
|
2660
|
-
};
|
|
2661
|
-
return this.streaming;
|
|
2662
|
-
}
|
|
2663
|
-
}
|
|
2664
|
-
export let ddb = window.ddb = new DDB();
|
|
2665
|
-
//# sourceMappingURL=browser.js.map
|