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/index.js CHANGED
@@ -1176,6 +1176,7 @@ export class DdbObj {
1176
1176
  static to_ddbobjs(values) {
1177
1177
  return values.map(value => this.to_ddbobj(value));
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;
@@ -2255,7 +2292,7 @@ export class DDB {
2255
2292
  this.lwebsocket.resource = await connect_websocket(this.url, {
2256
2293
  protocols: this.streaming ? ['streaming'] : this.python ? ['python'] : undefined,
2257
2294
  on_message: (buffer, websocket) => {
2258
- this.on_message(buffer, websocket);
2295
+ this.on_message(new Uint8Array(buffer), websocket);
2259
2296
  },
2260
2297
  on_error: error => {
2261
2298
  this.error ??= new DdbConnectionError(this.url, error);
@@ -2341,7 +2378,7 @@ export class DDB {
2341
2378
  let error = new DdbDatabaseError('', this.url, type, options, id);
2342
2379
  if (!options.skip_connection_check)
2343
2380
  await this.connect();
2344
- const { script, func, args: _args = [], vars = [], urgent, listener, } = options;
2381
+ const { script, func, args: _args = [], vars = [], urgent, listener, on_more_messages, } = options;
2345
2382
  if (func === 'pnode_run')
2346
2383
  await (this.ppnode_run ??= this.eval(this.python ?
2347
2384
  '\n' +
@@ -2442,37 +2479,42 @@ export class DDB {
2442
2479
  })());
2443
2480
  // 使用资源发送请求并等待请求完成
2444
2481
  const result = await new Promise((resolve, reject) => {
2482
+ let first_message = true;
2445
2483
  this.on_error = () => {
2446
2484
  // 这里一定有了 this.error, 不需要再 || new DdbConnectionError(this)
2447
2485
  reject(this.error);
2448
2486
  };
2449
2487
  this.on_message = buffer => {
2450
- try {
2451
- const buf = new Uint8Array(buffer);
2452
- if (this.print_message_buffer)
2453
- console.log(typed_array_to_buffer(buf));
2454
- const message = this.parse_message(buf, error);
2455
- listener?.(message, this);
2456
- for (const listener of _listeners)
2457
- listener(message, this);
2458
- const { type, data } = message;
2459
- switch (type) {
2460
- case 'print':
2461
- if (this.print_message)
2462
- console.log(data);
2463
- break;
2464
- case 'object':
2465
- resolve(data);
2466
- break;
2467
- case 'error':
2468
- reject(data);
2469
- break;
2488
+ if (!on_more_messages || first_message)
2489
+ try {
2490
+ if (this.print_message_buffer)
2491
+ console.log(typed_array_to_buffer(buffer));
2492
+ const message = this.parse_message(buffer, error);
2493
+ listener?.(message, this);
2494
+ for (const listener of _listeners)
2495
+ listener(message, this);
2496
+ const { type, data } = message;
2497
+ switch (type) {
2498
+ case 'print':
2499
+ if (this.print_message)
2500
+ console.log(data);
2501
+ break;
2502
+ case 'object':
2503
+ first_message = false;
2504
+ resolve(data);
2505
+ break;
2506
+ case 'error':
2507
+ first_message = false;
2508
+ reject(data);
2509
+ break;
2510
+ }
2470
2511
  }
2471
- }
2472
- catch (error) {
2473
- // 这里的错误并非 websocket 错误,而是 rpc 错误
2474
- reject(error);
2475
- }
2512
+ catch (error) {
2513
+ // 这里的错误并非 websocket 错误,而是 rpc 错误
2514
+ reject(error);
2515
+ }
2516
+ else
2517
+ on_more_messages(buffer);
2476
2518
  };
2477
2519
  websocket.send(concat([
2478
2520
  this.enc.encode(`API2 ${this.sid} ${command.length} / ${this.get_rpc_options({ urgent })}\n`),
@@ -2526,7 +2568,7 @@ export class DDB {
2526
2568
  将这个 flag 设为 true 跳过连接状态检查
2527
2569
  (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.
2528
2570
  Set this flag to true to skip connection status checks */
2529
- async call(func, args = [], { urgent, node, nodes, func_type, add_node_alias, listener, parse_object, skip_connection_check } = {}) {
2571
+ async call(func, args = [], { urgent, node, nodes, func_type, add_node_alias, listener, parse_object, skip_connection_check, on_more_messages } = {}) {
2530
2572
  if (node) {
2531
2573
  assert(func_type in DdbFunctionType, t('指定 node 时必须设置 func_type'));
2532
2574
  args = [
@@ -2557,7 +2599,8 @@ export class DDB {
2557
2599
  urgent,
2558
2600
  listener,
2559
2601
  parse_object,
2560
- skip_connection_check
2602
+ skip_connection_check,
2603
+ on_more_messages
2561
2604
  });
2562
2605
  }
2563
2606
  /** upload variable through websocket (variable command) */
@@ -2639,6 +2682,12 @@ export class DDB {
2639
2682
  }
2640
2683
  /** 内部的流订阅方法 Internal stream subscription method */
2641
2684
  async subscribe() {
2685
+ let win = {
2686
+ offset: 0,
2687
+ rows: 0,
2688
+ segments: [],
2689
+ };
2690
+ let schema;
2642
2691
  const { value: colnames } = await this.call('publishTable', [
2643
2692
  'localhost',
2644
2693
  new DdbInt(0),
@@ -2647,58 +2696,54 @@ export class DDB {
2647
2696
  // new DdbInt(-1), // offset
2648
2697
  // filter
2649
2698
  // allow exists
2650
- ], { skip_connection_check: true });
2651
- console.log(t('订阅流表成功') + ', colnames:',
2652
- // string[3](['time', 'stock', 'price'])
2653
- colnames);
2654
- let win = {
2655
- offset: 0,
2656
- rows: 0,
2657
- segments: [],
2658
- };
2659
- let schema;
2660
- // 先准备好收到 websocket message 的 callback
2661
- this.on_message = buffer => {
2662
- try {
2663
- const dv = new DataView(buffer);
2664
- const buf = new Uint8Array(buffer);
2665
- const i_topic_end = buf.indexOf(0, 17);
2666
- // 首个 message 可能是 table schema, 后续消息是 column 片段组成的 any vector
2667
- const data = DdbObj.parse(buf.subarray(i_topic_end + 1), this.le);
2668
- if (data.form === DdbForm.table) {
2669
- schema = data;
2670
- return;
2699
+ ], {
2700
+ skip_connection_check: true,
2701
+ // 先准备好收到 websocket message 的 callback
2702
+ on_more_messages: buffer => {
2703
+ try {
2704
+ const dv = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
2705
+ const i_topic_end = buffer.indexOf(0, 17);
2706
+ // 首个 message 一定是 table schema, 后续消息是 column 片段组成的 any vector
2707
+ const data = DdbObj.parse(buffer.subarray(i_topic_end + 1), this.le);
2708
+ if (data.form === DdbForm.table) {
2709
+ schema = data;
2710
+ return;
2711
+ }
2712
+ assert(schema, t('流数据订阅后一定先返回 schema'));
2713
+ const { rows } = data.value[0];
2714
+ win.rows += rows;
2715
+ win.segments.push(data);
2716
+ if (win.rows >= winsize * 2 && win.segments.length >= 2) {
2717
+ let winsize_ = 0;
2718
+ let i = win.segments.length - 1;
2719
+ // 往前移动至首个累计 winsize_ 超过 winsize 的位置
2720
+ for (; winsize_ < winsize; i--)
2721
+ winsize_ += win.segments[i].value[0].rows;
2722
+ win.segments = win.segments.slice(i);
2723
+ win.offset += win.rows - winsize_;
2724
+ win.rows = winsize_;
2725
+ }
2726
+ this.streaming.handler({
2727
+ ...this.streaming,
2728
+ id: dv.getBigInt64(9, this.le),
2729
+ time: dv.getBigInt64(1, this.le),
2730
+ rows,
2731
+ topic: this.dec.decode(buffer.subarray(17, i_topic_end)),
2732
+ colnames,
2733
+ schema,
2734
+ data,
2735
+ window: win,
2736
+ });
2671
2737
  }
2672
- const { rows } = data.value[0];
2673
- win.rows += rows;
2674
- win.segments.push(data);
2675
- if (win.rows >= winsize * 2 && win.segments.length >= 2) {
2676
- let winsize_ = 0;
2677
- let i = win.segments.length - 1;
2678
- // 往前移动至首个累计 winsize_ 超过 winsize 的位置
2679
- for (; winsize_ < winsize; i--)
2680
- winsize_ += win.segments[i].value[0].rows;
2681
- win.segments = win.segments.slice(i);
2682
- win.offset += win.rows - winsize_;
2683
- win.rows = winsize_;
2738
+ catch (error) {
2739
+ // 将 error 交给 handler 处理
2740
+ this.streaming.handler({ ...this.streaming, error });
2684
2741
  }
2685
- this.streaming.handler({
2686
- ...this.streaming,
2687
- id: dv.getBigInt64(9, this.le),
2688
- time: dv.getBigInt64(1, this.le),
2689
- rows,
2690
- topic: this.dec.decode(buf.subarray(17, i_topic_end)),
2691
- colnames,
2692
- schema,
2693
- data,
2694
- window: win,
2695
- });
2696
- }
2697
- catch (error) {
2698
- // 将 error 交给 handler 处理
2699
- this.streaming.handler({ ...this.streaming, error });
2700
2742
  }
2701
- };
2743
+ });
2744
+ console.log(t('订阅流表成功') + ', colnames:',
2745
+ // string[3](['time', 'stock', 'price'])
2746
+ colnames);
2702
2747
  }
2703
2748
  }
2704
2749
  // const ddb_gateway = {