dolphindb 3.0.21 → 3.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -10
- package/README.zh.md +112 -31
- package/browser.d.ts +13 -12
- package/browser.js +70 -47
- package/browser.js.map +1 -1
- package/index.d.ts +13 -12
- package/index.js +70 -47
- package/index.js.map +1 -1
- package/package.json +4 -4
- package/test.js +13 -10
- package/test.js.map +1 -1
package/README.md
CHANGED
|
@@ -448,7 +448,7 @@ let sddb = new DDB('ws://192.168.0.43:8800', {
|
|
|
448
448
|
streaming: {
|
|
449
449
|
table: 'Streaming table name to subscribe to',
|
|
450
450
|
|
|
451
|
-
// Streaming data processing callback, the type of message is
|
|
451
|
+
// Streaming data processing callback, the type of message is StreamingMessage
|
|
452
452
|
handler (message) {
|
|
453
453
|
console.log(message)
|
|
454
454
|
}
|
|
@@ -459,17 +459,17 @@ let sddb = new DDB('ws://192.168.0.43:8800', {
|
|
|
459
459
|
await sddb.connect()
|
|
460
460
|
```
|
|
461
461
|
|
|
462
|
-
The streaming data received after the connection is established will be used as the message parameter of the handler. The type of the message is
|
|
462
|
+
The streaming data received after the connection is established will be used as the message parameter of the handler. The type of the message is StreamingMessage, as follows:
|
|
463
463
|
|
|
464
464
|
```ts
|
|
465
465
|
export interface StreamingParams {
|
|
466
466
|
table: string
|
|
467
467
|
action?: string
|
|
468
468
|
|
|
469
|
-
handler (message:
|
|
469
|
+
handler (message: StreamingMessage): any
|
|
470
470
|
}
|
|
471
471
|
|
|
472
|
-
export interface
|
|
472
|
+
export interface StreamingMessage <TRows = any> extends StreamingParams {
|
|
473
473
|
/**
|
|
474
474
|
The time the server sent the message (nano seconds since epoch)
|
|
475
475
|
std::chrono::system_clock::now().time_since_epoch() / std::chrono::nanoseconds(1)
|
|
@@ -479,18 +479,16 @@ export interface StreamingData extends StreamingParams {
|
|
|
479
479
|
/** message id */
|
|
480
480
|
id: bigint
|
|
481
481
|
|
|
482
|
-
colnames: string[]
|
|
483
|
-
|
|
484
482
|
/** Subscription topic, which is the name of a subscription.
|
|
485
483
|
It is a string consisting of the alias of the node where the subscription table is located, the stream data table name, and the subscription task name (if actionName is specified), separated by `/`
|
|
486
484
|
*/
|
|
487
485
|
topic: string
|
|
488
486
|
|
|
489
487
|
/** Streaming data, the type is any vector, each element of which corresponds to a column (without name) of the subscribed table, and the content in the column (DdbObj<DdbVectorValue>) is the new data value */
|
|
490
|
-
|
|
488
|
+
obj: DdbObj<DdbVectorObj[]>
|
|
491
489
|
|
|
492
|
-
/**
|
|
493
|
-
|
|
490
|
+
/** Streaming data, each element of the data attribute in the object corresponds to a row in the incremental data of the subscribed table */
|
|
491
|
+
data: DdbTableData<TRows>
|
|
494
492
|
|
|
495
493
|
window: {
|
|
496
494
|
/** The establishment of the connection starts offset = 0, and gradually increases as the window moves */
|
|
@@ -500,7 +498,7 @@ export interface StreamingData extends StreamingParams {
|
|
|
500
498
|
rows: number
|
|
501
499
|
|
|
502
500
|
/** An array of data received each time */
|
|
503
|
-
segments:
|
|
501
|
+
segments: DdbTableData<TRows>[]
|
|
504
502
|
}
|
|
505
503
|
|
|
506
504
|
/** After successfully subscribed, if the subsequently pushed message is parsed incorrectly, the error will be set and the handler will be called. */
|
package/README.zh.md
CHANGED
|
@@ -49,7 +49,11 @@ https://www.npmjs.com/package/dolphindb
|
|
|
49
49
|
await ddb.connect()
|
|
50
50
|
|
|
51
51
|
console.log(
|
|
52
|
-
await ddb.
|
|
52
|
+
await ddb.execute('1 + 1')
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
console.log(
|
|
56
|
+
await ddb.invoke('add', [1, 1])
|
|
53
57
|
)
|
|
54
58
|
</script>
|
|
55
59
|
</body>
|
|
@@ -127,7 +131,54 @@ let ddb = new DDB('ws://127.0.0.1:8848', {
|
|
|
127
131
|
|
|
128
132
|
|
|
129
133
|
### 调用函数
|
|
130
|
-
####
|
|
134
|
+
#### `invoke` 方法
|
|
135
|
+
##### `invoke` 方法代码示例
|
|
136
|
+
```ts
|
|
137
|
+
const result = await ddb.invoke('add', [1, 1])
|
|
138
|
+
// TypeScript: const result = await ddb.invoke<number>('add', [1, 1])
|
|
139
|
+
|
|
140
|
+
console.log(result === 2) // true
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
上面例子中,上传了两个参数 1 (对应 DolphinDB 中的 int 类型) 到 DolphinDB 数据库,作为 add 函数的参数,并接收函数调用的结果 result
|
|
144
|
+
|
|
145
|
+
`<number>` 用于 TypeScript 推断返回值的类型
|
|
146
|
+
|
|
147
|
+
##### `invoke` 方法声明
|
|
148
|
+
```ts
|
|
149
|
+
/** 调用 dolphindb 函数,传入 js 原生数组作为参数,返回 js 原生对象或值(调用 DdbObj.data() 后的结果)*/
|
|
150
|
+
async invoke <TResult = any> (
|
|
151
|
+
/** 函数名 */
|
|
152
|
+
func: string,
|
|
153
|
+
|
|
154
|
+
/** `[ ]` 调用参数,可以是 js 原生数组 */
|
|
155
|
+
args?: any[],
|
|
156
|
+
|
|
157
|
+
/** 调用选项 */
|
|
158
|
+
options?: {
|
|
159
|
+
/** 紧急 flag。使用 urgent worker 执行,防止被其它作业阻塞 */
|
|
160
|
+
urgent?: boolean
|
|
161
|
+
|
|
162
|
+
/** 设置结点 alias 时发送到集群中对应的结点执行 (使用 DolphinDB 中的 rpc 方法) */
|
|
163
|
+
node?: string
|
|
164
|
+
|
|
165
|
+
/** 设置多个结点 alias 时发送到集群中对应的多个结点执行 (使用 DolphinDB 中的 pnodeRun 方法) */
|
|
166
|
+
nodes?: string[]
|
|
167
|
+
|
|
168
|
+
/** 设置 node 参数且参数数组为空时必传,需指定函数类型,其它情况下不传 */
|
|
169
|
+
func_type?: DdbFunctionType
|
|
170
|
+
|
|
171
|
+
/** 设置 nodes 参数时选传,其它情况不传 */
|
|
172
|
+
add_node_alias?: boolean
|
|
173
|
+
|
|
174
|
+
/** 处理本次 rpc 期间的消息 (DdbMessage) */
|
|
175
|
+
listener?: DdbMessageListener
|
|
176
|
+
} = { }
|
|
177
|
+
): Promise<TResult>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
#### `call` 方法
|
|
181
|
+
##### `call` 方法代码示例
|
|
131
182
|
```ts
|
|
132
183
|
import { DdbInt } from 'dolphindb'
|
|
133
184
|
|
|
@@ -137,7 +188,7 @@ const result = await ddb.call('add', [new DdbInt(1), new DdbInt(1)])
|
|
|
137
188
|
console.log(result.value === 2) // true
|
|
138
189
|
```
|
|
139
190
|
|
|
140
|
-
|
|
191
|
+
###### 用 DdbObj 对象来表示 DolphinDB 中的数据类型
|
|
141
192
|
|
|
142
193
|
上面例子中,上传了两个参数 1 (对应 DolphinDB 中的 int 类型) 到 DolphinDB 数据库,作为 add 函数的参数,并接收函数调用的结果 result
|
|
143
194
|
|
|
@@ -244,7 +295,7 @@ enum DdbType {
|
|
|
244
295
|
}
|
|
245
296
|
```
|
|
246
297
|
|
|
247
|
-
|
|
298
|
+
###### 无快捷类的类型
|
|
248
299
|
|
|
249
300
|
对于没有快捷类的类型,可指定 form 和 type 手动创建 DdbObj 对象
|
|
250
301
|
|
|
@@ -284,7 +335,7 @@ const obj = new DdbSetInt(
|
|
|
284
335
|
)
|
|
285
336
|
```
|
|
286
337
|
|
|
287
|
-
|
|
338
|
+
###### scalar 形式的 NULL 对象
|
|
288
339
|
|
|
289
340
|
scalar 形式的 NULL 对象,其对应 DdbObj 的 value 为 JavaScript 中的 null:
|
|
290
341
|
|
|
@@ -296,8 +347,7 @@ new DdbInt(null)
|
|
|
296
347
|
new DdbDouble(null)
|
|
297
348
|
```
|
|
298
349
|
|
|
299
|
-
|
|
300
|
-
#### `call` 方法声明
|
|
350
|
+
##### `call` 方法声明
|
|
301
351
|
```ts
|
|
302
352
|
async call <T extends DdbObj> (
|
|
303
353
|
/** 函数名 */
|
|
@@ -326,9 +376,50 @@ async call <T extends DdbObj> (
|
|
|
326
376
|
): Promise<T>
|
|
327
377
|
```
|
|
328
378
|
|
|
329
|
-
|
|
330
379
|
### 执行脚本
|
|
331
|
-
####
|
|
380
|
+
#### `execute` 方法
|
|
381
|
+
##### `execute` 方法代码示例
|
|
382
|
+
```ts
|
|
383
|
+
const result = await ddb.execute(
|
|
384
|
+
'def foo (a, b) {\n' +
|
|
385
|
+
' return a + b\n' +
|
|
386
|
+
'}\n' +
|
|
387
|
+
'foo(1l, 1l)\n'
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
// TypeScript:
|
|
391
|
+
// const result = await ddb.execute<bigint>(...)
|
|
392
|
+
|
|
393
|
+
console.log(result.value === 2n) // true
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
上面例子中,通过字符串上传了一段脚本到 DolphinDB 数据库执行,并接收最后一条语句 `foo(1l, 1l)` 执行结果 result
|
|
397
|
+
|
|
398
|
+
`<bigint>` 用于 TypeScript 推断返回值的类型
|
|
399
|
+
|
|
400
|
+
- result 是一个 `bigint`
|
|
401
|
+
|
|
402
|
+
只要 WebSocket 连接不断开,在后续的会话中 `foo` 这个自定义函数会一直存在,可复用,比如后续通过 `await ddb.invoke<number>('foo', [1, 1])` 调用这个自定义函数
|
|
403
|
+
|
|
404
|
+
##### `execute` 方法声明
|
|
405
|
+
```ts
|
|
406
|
+
/** 执行 dolphindb 脚本,返回 js 原生对象或值(调用 DdbObj.data() 后的结果)*/
|
|
407
|
+
async execute <TResult = any> (
|
|
408
|
+
/** 执行的脚本 */
|
|
409
|
+
script: string,
|
|
410
|
+
|
|
411
|
+
/** 执行选项 */
|
|
412
|
+
options?: {
|
|
413
|
+
/** 紧急 flag,确保提交的脚本使用 urgent worker 处理,防止被其它作业阻塞 */
|
|
414
|
+
urgent?: boolean
|
|
415
|
+
/** listener?: 处理本次 rpc 期间的消息 (DdbMessage) */
|
|
416
|
+
listener?: DdbMessageListener
|
|
417
|
+
}
|
|
418
|
+
): Promise<TResult>
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
#### `eval` 方法
|
|
422
|
+
##### `eval` 方法代码示例
|
|
332
423
|
```ts
|
|
333
424
|
const result = await ddb.eval(
|
|
334
425
|
'def foo (a, b) {\n' +
|
|
@@ -353,10 +444,9 @@ console.log(result.value === 2n) // true
|
|
|
353
444
|
- result.type 是 `DdbType.long`
|
|
354
445
|
- result.value 是 JavaScript 中原生的 `bigint` (long 的精度不能用 JavaScript 的 number 准确表示,但可以用 bigint 表示)
|
|
355
446
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
#### `eval` 方法声明
|
|
447
|
+
##### `eval` 方法声明
|
|
359
448
|
```ts
|
|
449
|
+
/** 执行 dolphindb 脚本,返回 DdbObj 对象)*/
|
|
360
450
|
async eval <T extends DdbObj> (
|
|
361
451
|
/** 执行的脚本 */
|
|
362
452
|
script: string,
|
|
@@ -369,7 +459,6 @@ async eval <T extends DdbObj> (
|
|
|
369
459
|
): Promise<T>
|
|
370
460
|
```
|
|
371
461
|
|
|
372
|
-
|
|
373
462
|
### 上传变量
|
|
374
463
|
#### 例子
|
|
375
464
|
```ts
|
|
@@ -445,7 +534,7 @@ let sddb = new DDB('ws://192.168.0.43:8800', {
|
|
|
445
534
|
streaming: {
|
|
446
535
|
table: '要订阅的流表名称',
|
|
447
536
|
|
|
448
|
-
// 流数据处理回调, message 的类型是
|
|
537
|
+
// 流数据处理回调, message 的类型是 StreamingMessage
|
|
449
538
|
handler (message) {
|
|
450
539
|
console.log(message)
|
|
451
540
|
}
|
|
@@ -456,38 +545,30 @@ let sddb = new DDB('ws://192.168.0.43:8800', {
|
|
|
456
545
|
await sddb.connect()
|
|
457
546
|
```
|
|
458
547
|
|
|
459
|
-
连接建立后接收到的流数据会作为 message 参数调用 handler, message 的类型是
|
|
548
|
+
连接建立后接收到的流数据会作为 message 参数调用 handler, message 的类型是 StreamingMessage, 如下:
|
|
460
549
|
|
|
461
550
|
```ts
|
|
462
551
|
export interface StreamingParams {
|
|
463
552
|
table: string
|
|
464
553
|
action?: string
|
|
465
554
|
|
|
466
|
-
handler (message:
|
|
555
|
+
handler (message: StreamingMessage): any
|
|
467
556
|
}
|
|
468
557
|
|
|
469
|
-
export interface
|
|
470
|
-
/**
|
|
471
|
-
|
|
472
|
-
std::chrono::system_clock::now().time_since_epoch() / std::chrono::nanoseconds(1)
|
|
473
|
-
*/
|
|
558
|
+
export interface StreamingMessage <TRows = any> extends StreamingParams {
|
|
559
|
+
/** server 发送消息的时间 (nano seconds since epoch)
|
|
560
|
+
std::chrono::system_clock::now().time_since_epoch() / std::chrono::nanoseconds(1) */
|
|
474
561
|
time: bigint
|
|
475
562
|
|
|
476
563
|
/** message id */
|
|
477
564
|
id: bigint
|
|
478
565
|
|
|
479
|
-
colnames: string[]
|
|
480
|
-
|
|
481
566
|
/** 订阅主题,即一个订阅的名称。
|
|
482
|
-
它是一个字符串,由订阅表所在节点的别名、流数据表名称和订阅任务名称(如果指定了 actionName)组合而成,使用 `/` 分隔
|
|
483
|
-
*/
|
|
567
|
+
它是一个字符串,由订阅表所在节点的别名、流数据表名称和订阅任务名称(如果指定了 actionName)组合而成,使用 `/` 分隔 */
|
|
484
568
|
topic: string
|
|
485
569
|
|
|
486
|
-
/**
|
|
487
|
-
data:
|
|
488
|
-
|
|
489
|
-
/** 新增的流数据行数 */
|
|
490
|
-
rows: number
|
|
570
|
+
/** 流数据 */
|
|
571
|
+
data: DdbTableData<TRows>
|
|
491
572
|
|
|
492
573
|
window: {
|
|
493
574
|
/** 建立连接开始 offset = 0, 随着 window 的移动逐渐增加 */
|
|
@@ -497,7 +578,7 @@ export interface StreamingData extends StreamingParams {
|
|
|
497
578
|
rows: number
|
|
498
579
|
|
|
499
580
|
/** 每次接收到的 data 组成的数组 */
|
|
500
|
-
segments:
|
|
581
|
+
segments: DdbTableData<TRows>[]
|
|
501
582
|
}
|
|
502
583
|
|
|
503
584
|
/** 成功订阅后,后续推送过来的 message 解析错误,则会设置 error 并调用 handler */
|
package/browser.d.ts
CHANGED
|
@@ -300,8 +300,8 @@ export declare class DdbObj<TValue extends DdbValue = DdbValue> {
|
|
|
300
300
|
- 矩阵对应 DdbMatrixData
|
|
301
301
|
- 字典对应普通的 js 对象 Record<string, any>
|
|
302
302
|
- 图对应 DdbChartValue */
|
|
303
|
-
data<TResult extends any[]>(this: DdbVectorObj): TResult;
|
|
304
|
-
data<TResult = any>(this: DdbObj): TResult;
|
|
303
|
+
data<TResult extends any[]>(this: DdbVectorObj, options?: ConvertOptions): TResult;
|
|
304
|
+
data<TResult = any>(this: DdbObj, options?: ConvertOptions): TResult;
|
|
305
305
|
toString(options?: InspectOptions): string;
|
|
306
306
|
inspect_type(): string;
|
|
307
307
|
/** 自动转换 js string, boolean 为 DdbObj */
|
|
@@ -353,9 +353,13 @@ export interface InspectOptions {
|
|
|
353
353
|
export declare function format(type: DdbType, value: DdbValue, le: boolean, options?: InspectOptions): string;
|
|
354
354
|
/** 格式化向量、集合中的第 index 项为字符串,空值返回 'null' 字符串 formatted vector, the index-th item in the collection is a string, a null value returns a 'null' string */
|
|
355
355
|
export declare function formati(obj: DdbVectorObj, index: number, options?: InspectOptions): string;
|
|
356
|
-
export
|
|
356
|
+
export interface ConvertOptions {
|
|
357
|
+
/** `'string'` blob 类型数据的格式 */
|
|
358
|
+
blob?: 'string' | 'binary';
|
|
359
|
+
}
|
|
360
|
+
export declare function convert(type: DdbType, value: DdbValue, le: boolean, { blob }?: ConvertOptions): string | number | bigint | boolean | Uint8Array | DdbFunctionDefValue | DdbDurationValue | DdbDecimal32Value | DdbDecimal64Value | DdbDecimal32VectorValue | Int32Array | DdbDecimal64VectorValue | BigInt64Array | DdbDecimal128VectorValue | BigInt128Array | DdbSymbolExtendedValue | string[] | Int8Array | Int16Array | Float32Array | Float64Array | DdbArrayVectorValue | DdbMatrixValue | Uint8Array[] | DdbObj<DdbValue>[] | DdbDurationVectorValue | DdbChartValue | number[];
|
|
357
361
|
/** 转换一个向量到 js 原生数组 */
|
|
358
|
-
export declare function converts(type: DdbType, value: DdbVectorValue, rows: number, le: boolean): any[];
|
|
362
|
+
export declare function converts(type: DdbType, value: DdbVectorValue, rows: number, le: boolean, options?: ConvertOptions): any[];
|
|
359
363
|
export declare class DdbVoid extends DdbObj<undefined> {
|
|
360
364
|
constructor(value?: DdbVoidType);
|
|
361
365
|
}
|
|
@@ -499,31 +503,28 @@ export interface StreamingParams {
|
|
|
499
503
|
};
|
|
500
504
|
handler(message: StreamingMessage): any;
|
|
501
505
|
}
|
|
502
|
-
export interface StreamingMessage extends StreamingParams {
|
|
506
|
+
export interface StreamingMessage<TRows = any> extends StreamingParams {
|
|
503
507
|
/** server 发送消息的时间 (nano seconds since epoch) The time the server sent the message (nano seconds since epoch)
|
|
504
508
|
std::chrono::system_clock::now().time_since_epoch() / std::chrono::nanoseconds(1) */
|
|
505
509
|
time: bigint;
|
|
506
510
|
/** message id */
|
|
507
511
|
id: bigint;
|
|
508
|
-
colnames: string[];
|
|
509
|
-
/** 最新的 server 有可能先推一个 table schema 过来 */
|
|
510
|
-
schema?: DdbTableObj;
|
|
511
512
|
/** 订阅主题,即一个订阅的名称。 Subscription topic, which is the name of a subscription.
|
|
512
513
|
它是一个字符串,由订阅表所在节点的别名、流数据表名称和订阅任务名称(如果指定了 actionName)组合而成,使用 `/` 分隔
|
|
513
514
|
It is a string consisting of the alias of the node where the subscription table is located, the stream data table name, and the subscription task name (if actionName is specified), separated by `/` */
|
|
514
515
|
topic: string;
|
|
515
516
|
/** 流数据,类型是 any vector, 其中的每一个元素对应被订阅表的一个列 (没有 name),列 (DdbObj<DdbVectorValue>) 中的内容是新增的数据值
|
|
516
517
|
Stream data, the type is any vector, each element of which corresponds to a column (without name) of the subscribed table, and the content in the column (DdbObj<DdbVectorValue>) is the new data value */
|
|
517
|
-
|
|
518
|
-
/**
|
|
519
|
-
|
|
518
|
+
obj: DdbObj<DdbVectorObj[]>;
|
|
519
|
+
/** 流数据 */
|
|
520
|
+
data: DdbTableData<TRows>;
|
|
520
521
|
window: {
|
|
521
522
|
/** 建立连接开始 offset = 0, 随着 window 的移动逐渐增加 The establishment of the connection starts offset = 0, and gradually increases as the window moves */
|
|
522
523
|
offset: number;
|
|
523
524
|
/** segments 中 segment.row 的总和 sum of segment.row in segments */
|
|
524
525
|
rows: number;
|
|
525
526
|
/** 每次接收到的 data 组成的数组 An array of data received each time */
|
|
526
|
-
segments:
|
|
527
|
+
segments: DdbTableData<TRows>[];
|
|
527
528
|
};
|
|
528
529
|
/** 成功订阅后,后续推送过来的 message 解析错误,则会设置 error 并调用 handler
|
|
529
530
|
After successfully subscribed, if the subsequently pushed message is parsed incorrectly, the error will be set and the handler will be called. */
|
package/browser.js
CHANGED
|
@@ -5,7 +5,7 @@ import ipaddrjs from 'ipaddr.js';
|
|
|
5
5
|
const { fromByteArray: buf2ipaddr } = ipaddrjs;
|
|
6
6
|
import 'xshell/prototype.browser.js';
|
|
7
7
|
import { blue, cyan, green, grey, magenta } from 'xshell/chalk.browser.js';
|
|
8
|
-
import { concat, assert, Lock, genid, seq, zip_object } from 'xshell/utils.browser.js';
|
|
8
|
+
import { concat, assert, Lock, genid, seq, zip_object, decode } from 'xshell/utils.browser.js';
|
|
9
9
|
import { connect_websocket } from 'xshell/net.browser.js';
|
|
10
10
|
import { t } from './i18n/index.js';
|
|
11
11
|
export const nulls = {
|
|
@@ -1125,20 +1125,20 @@ export class DdbObj {
|
|
|
1125
1125
|
throw new Error(t('vector {{type}} 暂不支持序列化', { type: get_type_name(type) }));
|
|
1126
1126
|
}
|
|
1127
1127
|
}
|
|
1128
|
-
data() {
|
|
1128
|
+
data(options) {
|
|
1129
1129
|
const { form, type, value, le, rows, name } = this;
|
|
1130
1130
|
switch (form) {
|
|
1131
1131
|
case DdbForm.scalar:
|
|
1132
|
-
return convert(type, value, le);
|
|
1132
|
+
return convert(type, value, le, options);
|
|
1133
1133
|
case DdbForm.vector:
|
|
1134
1134
|
case DdbForm.pair:
|
|
1135
1135
|
case DdbForm.set: {
|
|
1136
|
-
const data = converts(type, value, rows, le);
|
|
1136
|
+
const data = converts(type, value, rows, le, options);
|
|
1137
1137
|
return (form === DdbForm.set ? new Set(data) : data);
|
|
1138
1138
|
}
|
|
1139
1139
|
case DdbForm.table: {
|
|
1140
1140
|
const cols = value;
|
|
1141
|
-
const jscols = cols.map(col => col.data());
|
|
1141
|
+
const jscols = cols.map(col => col.data(options));
|
|
1142
1142
|
const keys = cols.map(({ name }) => name);
|
|
1143
1143
|
return {
|
|
1144
1144
|
name: name || '',
|
|
@@ -1149,20 +1149,20 @@ export class DdbObj {
|
|
|
1149
1149
|
}
|
|
1150
1150
|
case DdbForm.dict: {
|
|
1151
1151
|
const [keys, values] = value;
|
|
1152
|
-
return zip_object(keys.data(), values.data());
|
|
1152
|
+
return zip_object(keys.data(options), values.data(options));
|
|
1153
1153
|
}
|
|
1154
1154
|
case DdbForm.chart:
|
|
1155
1155
|
return value;
|
|
1156
1156
|
case DdbForm.matrix: {
|
|
1157
1157
|
const ncolumns = this.cols;
|
|
1158
1158
|
const { rows: _rows, cols: _cols, data } = value;
|
|
1159
|
-
const jsdata = converts(type, data, rows * ncolumns, le);
|
|
1159
|
+
const jsdata = converts(type, data, rows * ncolumns, le, options);
|
|
1160
1160
|
return {
|
|
1161
1161
|
type,
|
|
1162
1162
|
nrows: rows,
|
|
1163
1163
|
ncolumns,
|
|
1164
|
-
rows: _rows?.data(),
|
|
1165
|
-
columns: _cols?.data(),
|
|
1164
|
+
rows: _rows?.data(options),
|
|
1165
|
+
columns: _cols?.data(options),
|
|
1166
1166
|
data: seq(rows, i => seq(ncolumns, j => jsdata[j * rows + i]))
|
|
1167
1167
|
};
|
|
1168
1168
|
}
|
|
@@ -1768,7 +1768,7 @@ export function formati(obj, index, options = {}) {
|
|
|
1768
1768
|
}
|
|
1769
1769
|
}
|
|
1770
1770
|
}
|
|
1771
|
-
export function convert(type, value, le) {
|
|
1771
|
+
export function convert(type, value, le, { blob = 'string' } = {}) {
|
|
1772
1772
|
switch (type) {
|
|
1773
1773
|
case DdbType.void:
|
|
1774
1774
|
return value === DdbVoidType.null ? null : undefined;
|
|
@@ -1794,8 +1794,9 @@ export function convert(type, value, le) {
|
|
|
1794
1794
|
case DdbType.handle:
|
|
1795
1795
|
case DdbType.datasource:
|
|
1796
1796
|
case DdbType.resource:
|
|
1797
|
-
case DdbType.blob:
|
|
1798
1797
|
return value;
|
|
1798
|
+
case DdbType.blob:
|
|
1799
|
+
return blob === 'string' ? decode(value) : value;
|
|
1799
1800
|
case DdbType.complex:
|
|
1800
1801
|
case DdbType.point: {
|
|
1801
1802
|
const [x, y] = value;
|
|
@@ -1828,7 +1829,7 @@ export function convert(type, value, le) {
|
|
|
1828
1829
|
}
|
|
1829
1830
|
}
|
|
1830
1831
|
/** 转换一个向量到 js 原生数组 */
|
|
1831
|
-
export function converts(type, value, rows, le) {
|
|
1832
|
+
export function converts(type, value, rows, le, options) {
|
|
1832
1833
|
if (type < 64 || type >= 128)
|
|
1833
1834
|
switch (type) {
|
|
1834
1835
|
// 可以直接用下标取值再转换的类型
|
|
@@ -1858,7 +1859,7 @@ export function converts(type, value, rows, le) {
|
|
|
1858
1859
|
case DdbType.resource:
|
|
1859
1860
|
case DdbType.functiondef:
|
|
1860
1861
|
case DdbType.blob:
|
|
1861
|
-
return Array.prototype.map.call(value, (x) => convert(type, x, le));
|
|
1862
|
+
return Array.prototype.map.call(value, (x) => convert(type, x, le, options));
|
|
1862
1863
|
case DdbType.void:
|
|
1863
1864
|
return [];
|
|
1864
1865
|
case DdbType.symbol_extended: {
|
|
@@ -1871,14 +1872,12 @@ export function converts(type, value, rows, le) {
|
|
|
1871
1872
|
case DdbType.uuid:
|
|
1872
1873
|
case DdbType.ipaddr:
|
|
1873
1874
|
case DdbType.int128:
|
|
1874
|
-
return seq(rows, i => convert(type, value.subarray(16 * i, 16 * (i + 1)), le));
|
|
1875
|
+
return seq(rows, i => convert(type, value.subarray(16 * i, 16 * (i + 1)), le, options));
|
|
1875
1876
|
case DdbType.decimal32:
|
|
1876
1877
|
case DdbType.decimal64:
|
|
1877
1878
|
case DdbType.decimal128: {
|
|
1878
1879
|
const { scale, data } = value;
|
|
1879
|
-
|
|
1880
|
-
return seq(rows, i => {
|
|
1881
|
-
const x = data[i];
|
|
1880
|
+
return Array.prototype.map.call(data, (x) => {
|
|
1882
1881
|
if (is_decimal_null_value(type, x))
|
|
1883
1882
|
return '';
|
|
1884
1883
|
const s = String(x < 0 ? -x : x).padStart(scale, '0');
|
|
@@ -1886,7 +1885,7 @@ export function converts(type, value, rows, le) {
|
|
|
1886
1885
|
});
|
|
1887
1886
|
}
|
|
1888
1887
|
case DdbType.any:
|
|
1889
|
-
return value.map(x => x.data());
|
|
1888
|
+
return value.map(x => x.data(options));
|
|
1890
1889
|
default:
|
|
1891
1890
|
throw new Error(String(DdbType[type] || type) + '[]' + t(' 暂时不支持转换为 js 对象'));
|
|
1892
1891
|
}
|
|
@@ -1900,16 +1899,16 @@ export function converts(type, value, rows, le) {
|
|
|
1900
1899
|
case DdbType.decimal32:
|
|
1901
1900
|
case DdbType.decimal64:
|
|
1902
1901
|
case DdbType.decimal128:
|
|
1903
|
-
return converts(type_, { scale: value.scale, data: data.subarray(acc_len, acc_len + length) }, length, le);
|
|
1902
|
+
return converts(type_, { scale: value.scale, data: data.subarray(acc_len, acc_len + length) }, length, le, options);
|
|
1904
1903
|
case DdbType.complex:
|
|
1905
1904
|
case DdbType.point:
|
|
1906
|
-
return converts(type_, data.subarray(acc_len, acc_len + 2 * length), length, le);
|
|
1905
|
+
return converts(type_, data.subarray(acc_len, acc_len + 2 * length), length, le, options);
|
|
1907
1906
|
case DdbType.uuid:
|
|
1908
1907
|
case DdbType.int128:
|
|
1909
1908
|
case DdbType.ipaddr:
|
|
1910
|
-
return converts(type_, data.subarray(acc_len, acc_len + 16 * length), length, le);
|
|
1909
|
+
return converts(type_, data.subarray(acc_len, acc_len + 16 * length), length, le, options);
|
|
1911
1910
|
default:
|
|
1912
|
-
return converts(type_, data.subarray(acc_len, acc_len + length), length, le);
|
|
1911
|
+
return converts(type_, data.subarray(acc_len, acc_len + length), length, le, options);
|
|
1913
1912
|
}
|
|
1914
1913
|
})();
|
|
1915
1914
|
acc_len += length;
|
|
@@ -3066,8 +3065,9 @@ export class DDB {
|
|
|
3066
3065
|
rows: 0,
|
|
3067
3066
|
segments: [],
|
|
3068
3067
|
};
|
|
3069
|
-
|
|
3070
|
-
|
|
3068
|
+
// 流表推送过来的第一条数据是 schema,需要特殊处理
|
|
3069
|
+
let first = true;
|
|
3070
|
+
const { value: columns } = await this.call('publishTable', [
|
|
3071
3071
|
'localhost',
|
|
3072
3072
|
new DdbInt(0),
|
|
3073
3073
|
this.streaming.table,
|
|
@@ -3081,41 +3081,56 @@ export class DDB {
|
|
|
3081
3081
|
// 先准备好收到 websocket message 的 callback
|
|
3082
3082
|
on_more_messages: buffer => {
|
|
3083
3083
|
try {
|
|
3084
|
+
let data;
|
|
3084
3085
|
const dv = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
3085
3086
|
const i_topic_end = buffer.indexOf(0, 17);
|
|
3086
3087
|
// 首个 message 一定是 table schema, 后续消息是 column 片段组成的 any vector
|
|
3087
|
-
const
|
|
3088
|
+
const obj = DdbObj.parse(buffer.subarray(i_topic_end + 1), this.le);
|
|
3088
3089
|
// server 推数据时遇到错误会返回 string,一般格式为 error.xxx: 错误信息
|
|
3089
|
-
if (
|
|
3090
|
+
if (obj.form === DdbForm.scalar && obj.type === DdbType.string) {
|
|
3090
3091
|
this.disconnect();
|
|
3091
|
-
const value =
|
|
3092
|
+
const value = obj.value;
|
|
3092
3093
|
throw new Error(value.slice(value.indexOf(':') + 1).trim());
|
|
3093
3094
|
}
|
|
3094
|
-
if (
|
|
3095
|
-
|
|
3096
|
-
|
|
3095
|
+
if (first) {
|
|
3096
|
+
data = obj.data();
|
|
3097
|
+
data.name ||= this.streaming.table;
|
|
3098
|
+
first = false;
|
|
3097
3099
|
}
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3100
|
+
else {
|
|
3101
|
+
const { rows } = obj.value[0];
|
|
3102
|
+
const types = [];
|
|
3103
|
+
const js_cols = [];
|
|
3104
|
+
// 遍历每一列
|
|
3105
|
+
obj.value.forEach(({ type, value }) => {
|
|
3106
|
+
types.push(type);
|
|
3107
|
+
js_cols.push(converts(type, value, rows, obj.le));
|
|
3108
|
+
});
|
|
3109
|
+
data = {
|
|
3110
|
+
name: this.streaming.table || '',
|
|
3111
|
+
columns,
|
|
3112
|
+
types,
|
|
3113
|
+
data: seq(rows, i => zip_object(columns, seq(columns.length, j => js_cols[j][i])))
|
|
3114
|
+
};
|
|
3115
|
+
win.rows += rows;
|
|
3116
|
+
win.segments.push(data);
|
|
3117
|
+
if (win.rows >= winsize * 2 && win.segments.length >= 2) {
|
|
3118
|
+
let winsize_ = 0;
|
|
3119
|
+
let i = win.segments.length - 1;
|
|
3120
|
+
// 往前移动至首个累计 winsize_ 超过 winsize 的位置
|
|
3121
|
+
for (; winsize_ < winsize; i--)
|
|
3122
|
+
winsize_ += win.segments[i].data.length;
|
|
3123
|
+
win.segments = win.segments.slice(i);
|
|
3124
|
+
win.offset += win.rows - winsize_;
|
|
3125
|
+
win.rows = winsize_;
|
|
3126
|
+
}
|
|
3110
3127
|
}
|
|
3111
3128
|
this.streaming.handler({
|
|
3112
3129
|
...this.streaming,
|
|
3113
3130
|
id: dv.getBigInt64(9, this.le),
|
|
3114
3131
|
time: dv.getBigInt64(1, this.le),
|
|
3115
|
-
rows,
|
|
3116
3132
|
topic: this.dec.decode(buffer.subarray(17, i_topic_end)),
|
|
3117
|
-
|
|
3118
|
-
schema,
|
|
3133
|
+
obj,
|
|
3119
3134
|
data,
|
|
3120
3135
|
window: win,
|
|
3121
3136
|
});
|
|
@@ -3126,9 +3141,9 @@ export class DDB {
|
|
|
3126
3141
|
}
|
|
3127
3142
|
}
|
|
3128
3143
|
});
|
|
3129
|
-
console.log(t('订阅流表成功') + ',
|
|
3144
|
+
console.log(t('订阅流表成功') + ', columns:',
|
|
3130
3145
|
// string[3](['time', 'stock', 'price'])
|
|
3131
|
-
|
|
3146
|
+
columns);
|
|
3132
3147
|
}
|
|
3133
3148
|
}
|
|
3134
3149
|
/** https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements
|
|
@@ -3206,6 +3221,14 @@ export class BigInt128Array {
|
|
|
3206
3221
|
return true;
|
|
3207
3222
|
}
|
|
3208
3223
|
return Reflect.set(target, key, value);
|
|
3224
|
+
},
|
|
3225
|
+
has(target, key) {
|
|
3226
|
+
if (typeof key === 'string') {
|
|
3227
|
+
const index = Number(key);
|
|
3228
|
+
if (Number.isInteger(index) && index >= 0 && index < target.length)
|
|
3229
|
+
return true;
|
|
3230
|
+
}
|
|
3231
|
+
return Reflect.has(target, key);
|
|
3209
3232
|
}
|
|
3210
3233
|
});
|
|
3211
3234
|
}
|