dolphindb 2.0.1022 → 2.0.1025

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/browser.d.ts CHANGED
@@ -163,6 +163,7 @@ export declare class DdbObj<TValue extends DdbValue = DdbValue> {
163
163
  dataIndex: string;
164
164
  render: (value: any) => string;
165
165
  }[];
166
+ /** 将 table 转换为 rows,空值转换为 null */
166
167
  to_rows<T extends Record<string, any> = Record<string, any>>(): T[];
167
168
  /** 将 dict<string, any> 自动转换为 js object (Record<string, any>) Automatically convert dict<string, any> to js object (Record<string, any>)
168
169
  - options?:
@@ -372,6 +373,7 @@ export interface DdbRpcOptions {
372
373
  listener?: DdbMessageListener;
373
374
  parse_object?: boolean;
374
375
  skip_connection_check?: boolean;
376
+ on_more_messages?: (buffer: Uint8Array) => void;
375
377
  }
376
378
  export declare class DdbConnectionError extends Error {
377
379
  name: string;
@@ -571,7 +573,7 @@ export declare class DDB {
571
573
  将这个 flag 设为 true 跳过连接状态检查
572
574
  (internal use) When await ddb.connect() establishes a connection for the first time, you cannot call await this.connect() again to ensure the connection status, which will lead to circular dependencies.
573
575
  Set this flag to true to skip connection status checks */
574
- call<TResult extends DdbObj>(func: string, args?: (DdbObj | string | boolean)[], { urgent, node, nodes, func_type, add_node_alias, listener, parse_object, skip_connection_check }?: {
576
+ call<TResult extends DdbObj>(func: string, args?: (DdbObj | string | boolean)[], { urgent, node, nodes, func_type, add_node_alias, listener, parse_object, skip_connection_check, on_more_messages }?: {
575
577
  urgent?: boolean;
576
578
  node?: string;
577
579
  nodes?: string[];
@@ -580,6 +582,7 @@ export declare class DDB {
580
582
  listener?: DdbMessageListener;
581
583
  parse_object?: boolean;
582
584
  skip_connection_check?: boolean;
585
+ on_more_messages?: DdbRpcOptions['on_more_messages'];
583
586
  }): Promise<TResult>;
584
587
  /** upload variable through websocket (variable command) */
585
588
  upload(
package/browser.js CHANGED
@@ -1176,6 +1176,7 @@ export class DdbObj {
1176
1176
  render: value => format(col.type, value, col.le, { nullstr: false, quote: false })
1177
1177
  }));
1178
1178
  }
1179
+ /** 将 table 转换为 rows,空值转换为 null */
1179
1180
  to_rows() {
1180
1181
  assert(this.form === DdbForm.table, t('form 必须是 DdbForm.table, 否则不能 to_rows'));
1181
1182
  let rows = new Array(this.rows);
@@ -1192,6 +1193,42 @@ export class DdbObj {
1192
1193
  Boolean(value);
1193
1194
  break;
1194
1195
  }
1196
+ case DdbType.char:
1197
+ row[name] = values[i] === nulls.int8 ? null : values[i];
1198
+ break;
1199
+ case DdbType.short:
1200
+ row[name] = values[i] === nulls.int16 ? null : values[i];
1201
+ break;
1202
+ case DdbType.int:
1203
+ case DdbType.date:
1204
+ case DdbType.month:
1205
+ case DdbType.time:
1206
+ case DdbType.minute:
1207
+ case DdbType.second:
1208
+ case DdbType.datetime:
1209
+ case DdbType.datehour:
1210
+ row[name] = values[i] === nulls.int32 ? null : values[i];
1211
+ break;
1212
+ case DdbType.long:
1213
+ case DdbType.timestamp:
1214
+ case DdbType.nanotime:
1215
+ case DdbType.nanotimestamp:
1216
+ row[name] = values[i] === nulls.int64 ? null : values[i];
1217
+ break;
1218
+ case DdbType.int128:
1219
+ row[name] = values[i] === nulls.int128 ? null : values[i];
1220
+ break;
1221
+ case DdbType.float:
1222
+ row[name] = values[i] === nulls.float32 ? null : values[i];
1223
+ break;
1224
+ case DdbType.double:
1225
+ row[name] = values[i] === nulls.double ? null : values[i];
1226
+ break;
1227
+ case DdbType.decimal32:
1228
+ case DdbType.decimal64:
1229
+ case DdbType.decimal128:
1230
+ row[name] = is_decimal_null_value(type, values[i]) ? null : values[i];
1231
+ break;
1195
1232
  case DdbType.ipaddr:
1196
1233
  row[name] = values.subarray(16 * i, 16 * (i + 1));
1197
1234
  break;
@@ -2256,7 +2293,7 @@ export class DDB {
2256
2293
  this.lwebsocket.resource = await connect_websocket(this.url, {
2257
2294
  protocols: this.streaming ? ['streaming'] : this.python ? ['python'] : undefined,
2258
2295
  on_message: (buffer, websocket) => {
2259
- this.on_message(buffer, websocket);
2296
+ this.on_message(new Uint8Array(buffer), websocket);
2260
2297
  },
2261
2298
  on_error: error => {
2262
2299
  this.error ??= new DdbConnectionError(this.url, error);
@@ -2342,7 +2379,7 @@ export class DDB {
2342
2379
  let error = new DdbDatabaseError('', this.url, type, options, id);
2343
2380
  if (!options.skip_connection_check)
2344
2381
  await this.connect();
2345
- const { script, func, args: _args = [], vars = [], urgent, listener, } = options;
2382
+ const { script, func, args: _args = [], vars = [], urgent, listener, on_more_messages, } = options;
2346
2383
  if (func === 'pnode_run')
2347
2384
  await (this.ppnode_run ??= this.eval(this.python ?
2348
2385
  '\n' +
@@ -2443,37 +2480,42 @@ export class DDB {
2443
2480
  })());
2444
2481
  // 使用资源发送请求并等待请求完成
2445
2482
  const result = await new Promise((resolve, reject) => {
2483
+ let first_message = true;
2446
2484
  this.on_error = () => {
2447
2485
  // 这里一定有了 this.error, 不需要再 || new DdbConnectionError(this)
2448
2486
  reject(this.error);
2449
2487
  };
2450
2488
  this.on_message = buffer => {
2451
- try {
2452
- const buf = new Uint8Array(buffer);
2453
- if (this.print_message_buffer)
2454
- console.log(buf);
2455
- const message = this.parse_message(buf, error);
2456
- listener?.(message, this);
2457
- for (const listener of _listeners)
2458
- listener(message, this);
2459
- const { type, data } = message;
2460
- switch (type) {
2461
- case 'print':
2462
- if (this.print_message)
2463
- console.log(data);
2464
- break;
2465
- case 'object':
2466
- resolve(data);
2467
- break;
2468
- case 'error':
2469
- reject(data);
2470
- break;
2489
+ if (!on_more_messages || first_message)
2490
+ try {
2491
+ if (this.print_message_buffer)
2492
+ console.log(buffer);
2493
+ const message = this.parse_message(buffer, error);
2494
+ listener?.(message, this);
2495
+ for (const listener of _listeners)
2496
+ listener(message, this);
2497
+ const { type, data } = message;
2498
+ switch (type) {
2499
+ case 'print':
2500
+ if (this.print_message)
2501
+ console.log(data);
2502
+ break;
2503
+ case 'object':
2504
+ first_message = false;
2505
+ resolve(data);
2506
+ break;
2507
+ case 'error':
2508
+ first_message = false;
2509
+ reject(data);
2510
+ break;
2511
+ }
2471
2512
  }
2472
- }
2473
- catch (error) {
2474
- // 这里的错误并非 websocket 错误,而是 rpc 错误
2475
- reject(error);
2476
- }
2513
+ catch (error) {
2514
+ // 这里的错误并非 websocket 错误,而是 rpc 错误
2515
+ reject(error);
2516
+ }
2517
+ else
2518
+ on_more_messages(buffer);
2477
2519
  };
2478
2520
  websocket.send(concat([
2479
2521
  this.enc.encode(`API2 ${this.sid} ${command.length} / ${this.get_rpc_options({ urgent })}\n`),
@@ -2527,7 +2569,7 @@ export class DDB {
2527
2569
  将这个 flag 设为 true 跳过连接状态检查
2528
2570
  (internal use) When await ddb.connect() establishes a connection for the first time, you cannot call await this.connect() again to ensure the connection status, which will lead to circular dependencies.
2529
2571
  Set this flag to true to skip connection status checks */
2530
- async call(func, args = [], { urgent, node, nodes, func_type, add_node_alias, listener, parse_object, skip_connection_check } = {}) {
2572
+ async call(func, args = [], { urgent, node, nodes, func_type, add_node_alias, listener, parse_object, skip_connection_check, on_more_messages } = {}) {
2531
2573
  if (node) {
2532
2574
  assert(func_type in DdbFunctionType, t('指定 node 时必须设置 func_type'));
2533
2575
  args = [
@@ -2558,7 +2600,8 @@ export class DDB {
2558
2600
  urgent,
2559
2601
  listener,
2560
2602
  parse_object,
2561
- skip_connection_check
2603
+ skip_connection_check,
2604
+ on_more_messages
2562
2605
  });
2563
2606
  }
2564
2607
  /** upload variable through websocket (variable command) */
@@ -2640,6 +2683,12 @@ export class DDB {
2640
2683
  }
2641
2684
  /** 内部的流订阅方法 Internal stream subscription method */
2642
2685
  async subscribe() {
2686
+ let win = {
2687
+ offset: 0,
2688
+ rows: 0,
2689
+ segments: [],
2690
+ };
2691
+ let schema;
2643
2692
  const { value: colnames } = await this.call('publishTable', [
2644
2693
  'localhost',
2645
2694
  new DdbInt(0),
@@ -2648,58 +2697,54 @@ export class DDB {
2648
2697
  // new DdbInt(-1), // offset
2649
2698
  // filter
2650
2699
  // allow exists
2651
- ], { skip_connection_check: true });
2652
- console.log(t('订阅流表成功') + ', colnames:',
2653
- // string[3](['time', 'stock', 'price'])
2654
- colnames);
2655
- let win = {
2656
- offset: 0,
2657
- rows: 0,
2658
- segments: [],
2659
- };
2660
- let schema;
2661
- // 先准备好收到 websocket message 的 callback
2662
- this.on_message = buffer => {
2663
- try {
2664
- const dv = new DataView(buffer);
2665
- const buf = new Uint8Array(buffer);
2666
- const i_topic_end = buf.indexOf(0, 17);
2667
- // 首个 message 可能是 table schema, 后续消息是 column 片段组成的 any vector
2668
- const data = DdbObj.parse(buf.subarray(i_topic_end + 1), this.le);
2669
- if (data.form === DdbForm.table) {
2670
- schema = data;
2671
- return;
2700
+ ], {
2701
+ skip_connection_check: true,
2702
+ // 先准备好收到 websocket message 的 callback
2703
+ on_more_messages: buffer => {
2704
+ try {
2705
+ const dv = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
2706
+ const i_topic_end = buffer.indexOf(0, 17);
2707
+ // 首个 message 一定是 table schema, 后续消息是 column 片段组成的 any vector
2708
+ const data = DdbObj.parse(buffer.subarray(i_topic_end + 1), this.le);
2709
+ if (data.form === DdbForm.table) {
2710
+ schema = data;
2711
+ return;
2712
+ }
2713
+ assert(schema, t('流数据订阅后一定先返回 schema'));
2714
+ const { rows } = data.value[0];
2715
+ win.rows += rows;
2716
+ win.segments.push(data);
2717
+ if (win.rows >= winsize * 2 && win.segments.length >= 2) {
2718
+ let winsize_ = 0;
2719
+ let i = win.segments.length - 1;
2720
+ // 往前移动至首个累计 winsize_ 超过 winsize 的位置
2721
+ for (; winsize_ < winsize; i--)
2722
+ winsize_ += win.segments[i].value[0].rows;
2723
+ win.segments = win.segments.slice(i);
2724
+ win.offset += win.rows - winsize_;
2725
+ win.rows = winsize_;
2726
+ }
2727
+ this.streaming.handler({
2728
+ ...this.streaming,
2729
+ id: dv.getBigInt64(9, this.le),
2730
+ time: dv.getBigInt64(1, this.le),
2731
+ rows,
2732
+ topic: this.dec.decode(buffer.subarray(17, i_topic_end)),
2733
+ colnames,
2734
+ schema,
2735
+ data,
2736
+ window: win,
2737
+ });
2672
2738
  }
2673
- const { rows } = data.value[0];
2674
- win.rows += rows;
2675
- win.segments.push(data);
2676
- if (win.rows >= winsize * 2 && win.segments.length >= 2) {
2677
- let winsize_ = 0;
2678
- let i = win.segments.length - 1;
2679
- // 往前移动至首个累计 winsize_ 超过 winsize 的位置
2680
- for (; winsize_ < winsize; i--)
2681
- winsize_ += win.segments[i].value[0].rows;
2682
- win.segments = win.segments.slice(i);
2683
- win.offset += win.rows - winsize_;
2684
- win.rows = winsize_;
2739
+ catch (error) {
2740
+ // 将 error 交给 handler 处理
2741
+ this.streaming.handler({ ...this.streaming, error });
2685
2742
  }
2686
- this.streaming.handler({
2687
- ...this.streaming,
2688
- id: dv.getBigInt64(9, this.le),
2689
- time: dv.getBigInt64(1, this.le),
2690
- rows,
2691
- topic: this.dec.decode(buf.subarray(17, i_topic_end)),
2692
- colnames,
2693
- schema,
2694
- data,
2695
- window: win,
2696
- });
2697
- }
2698
- catch (error) {
2699
- // 将 error 交给 handler 处理
2700
- this.streaming.handler({ ...this.streaming, error });
2701
2743
  }
2702
- };
2744
+ });
2745
+ console.log(t('订阅流表成功') + ', colnames:',
2746
+ // string[3](['time', 'stock', 'price'])
2747
+ colnames);
2703
2748
  }
2704
2749
  }
2705
2750
  //# sourceMappingURL=browser.js.map