dolphindb 3.0.22 → 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 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 StreamingData
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 StreamingData, as follows:
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: StreamingData): any
469
+ handler (message: StreamingMessage): any
470
470
  }
471
471
 
472
- export interface StreamingData extends StreamingParams {
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
- data: DdbObj<DdbVectorObj[]>
488
+ obj: DdbObj<DdbVectorObj[]>
491
489
 
492
- /** Number of new streaming data rows */
493
- rows: number
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: DdbObj<DdbVectorObj[]>[]
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
@@ -51,6 +51,10 @@ https://www.npmjs.com/package/dolphindb
51
51
  console.log(
52
52
  await ddb.execute('1 + 1')
53
53
  )
54
+
55
+ console.log(
56
+ await ddb.invoke('add', [1, 1])
57
+ )
54
58
  </script>
55
59
  </body>
56
60
  </html>
@@ -395,7 +399,7 @@ console.log(result.value === 2n) // true
395
399
 
396
400
  - result 是一个 `bigint`
397
401
 
398
- 只要 WebSocket 连接不断开,在后续的会话中 `foo` 这个自定义函数会一直存在,可复用,比如后续通过 `await ddb.call<DdbInt>('foo', [new DdbInt(1), new DdbInt(1)])` 调用这个自定义函数
402
+ 只要 WebSocket 连接不断开,在后续的会话中 `foo` 这个自定义函数会一直存在,可复用,比如后续通过 `await ddb.invoke<number>('foo', [1, 1])` 调用这个自定义函数
399
403
 
400
404
  ##### `execute` 方法声明
401
405
  ```ts
@@ -530,7 +534,7 @@ let sddb = new DDB('ws://192.168.0.43:8800', {
530
534
  streaming: {
531
535
  table: '要订阅的流表名称',
532
536
 
533
- // 流数据处理回调, message 的类型是 StreamingData
537
+ // 流数据处理回调, message 的类型是 StreamingMessage
534
538
  handler (message) {
535
539
  console.log(message)
536
540
  }
@@ -541,38 +545,30 @@ let sddb = new DDB('ws://192.168.0.43:8800', {
541
545
  await sddb.connect()
542
546
  ```
543
547
 
544
- 连接建立后接收到的流数据会作为 message 参数调用 handler, message 的类型是 StreamingData, 如下:
548
+ 连接建立后接收到的流数据会作为 message 参数调用 handler, message 的类型是 StreamingMessage, 如下:
545
549
 
546
550
  ```ts
547
551
  export interface StreamingParams {
548
552
  table: string
549
553
  action?: string
550
554
 
551
- handler (message: StreamingData): any
555
+ handler (message: StreamingMessage): any
552
556
  }
553
557
 
554
- export interface StreamingData extends StreamingParams {
555
- /**
556
- server 发送消息的时间 (nano seconds since epoch)
557
- std::chrono::system_clock::now().time_since_epoch() / std::chrono::nanoseconds(1)
558
- */
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) */
559
561
  time: bigint
560
562
 
561
563
  /** message id */
562
564
  id: bigint
563
565
 
564
- colnames: string[]
565
-
566
566
  /** 订阅主题,即一个订阅的名称。
567
- 它是一个字符串,由订阅表所在节点的别名、流数据表名称和订阅任务名称(如果指定了 actionName)组合而成,使用 `/` 分隔
568
- */
567
+ 它是一个字符串,由订阅表所在节点的别名、流数据表名称和订阅任务名称(如果指定了 actionName)组合而成,使用 `/` 分隔 */
569
568
  topic: string
570
569
 
571
- /** 流数据,类型是 any vector, 其中的每一个元素对应被订阅表的一个列 (没有 name),列 (DdbObj<DdbVectorValue>) 中的内容是新增的数据值 */
572
- data: DdbObj<DdbVectorObj[]>
573
-
574
- /** 新增的流数据行数 */
575
- rows: number
570
+ /** 流数据 */
571
+ data: DdbTableData<TRows>
576
572
 
577
573
  window: {
578
574
  /** 建立连接开始 offset = 0, 随着 window 的移动逐渐增加 */
@@ -582,7 +578,7 @@ export interface StreamingData extends StreamingParams {
582
578
  rows: number
583
579
 
584
580
  /** 每次接收到的 data 组成的数组 */
585
- segments: DdbObj<DdbVectorObj[]>[]
581
+ segments: DdbTableData<TRows>[]
586
582
  }
587
583
 
588
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 declare function convert(type: DdbType, value: DdbValue, le: boolean): 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[];
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
- data: DdbObj<DdbVectorObj[]>;
518
- /** 新增的流数据行数 Number of new streaming data rows */
519
- rows: number;
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: DdbObj<DdbVectorObj[]>[];
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,7 +1872,7 @@ 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: {
@@ -1884,7 +1885,7 @@ export function converts(type, value, rows, le) {
1884
1885
  });
1885
1886
  }
1886
1887
  case DdbType.any:
1887
- return value.map(x => x.data());
1888
+ return value.map(x => x.data(options));
1888
1889
  default:
1889
1890
  throw new Error(String(DdbType[type] || type) + '[]' + t(' 暂时不支持转换为 js 对象'));
1890
1891
  }
@@ -1898,16 +1899,16 @@ export function converts(type, value, rows, le) {
1898
1899
  case DdbType.decimal32:
1899
1900
  case DdbType.decimal64:
1900
1901
  case DdbType.decimal128:
1901
- 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);
1902
1903
  case DdbType.complex:
1903
1904
  case DdbType.point:
1904
- 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);
1905
1906
  case DdbType.uuid:
1906
1907
  case DdbType.int128:
1907
1908
  case DdbType.ipaddr:
1908
- 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);
1909
1910
  default:
1910
- 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);
1911
1912
  }
1912
1913
  })();
1913
1914
  acc_len += length;
@@ -3064,8 +3065,9 @@ export class DDB {
3064
3065
  rows: 0,
3065
3066
  segments: [],
3066
3067
  };
3067
- let schema;
3068
- const { value: colnames } = await this.call('publishTable', [
3068
+ // 流表推送过来的第一条数据是 schema,需要特殊处理
3069
+ let first = true;
3070
+ const { value: columns } = await this.call('publishTable', [
3069
3071
  'localhost',
3070
3072
  new DdbInt(0),
3071
3073
  this.streaming.table,
@@ -3079,41 +3081,56 @@ export class DDB {
3079
3081
  // 先准备好收到 websocket message 的 callback
3080
3082
  on_more_messages: buffer => {
3081
3083
  try {
3084
+ let data;
3082
3085
  const dv = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
3083
3086
  const i_topic_end = buffer.indexOf(0, 17);
3084
3087
  // 首个 message 一定是 table schema, 后续消息是 column 片段组成的 any vector
3085
- const data = DdbObj.parse(buffer.subarray(i_topic_end + 1), this.le);
3088
+ const obj = DdbObj.parse(buffer.subarray(i_topic_end + 1), this.le);
3086
3089
  // server 推数据时遇到错误会返回 string,一般格式为 error.xxx: 错误信息
3087
- if (data.form === DdbForm.scalar && data.type === DdbType.string) {
3090
+ if (obj.form === DdbForm.scalar && obj.type === DdbType.string) {
3088
3091
  this.disconnect();
3089
- const value = data.value;
3092
+ const value = obj.value;
3090
3093
  throw new Error(value.slice(value.indexOf(':') + 1).trim());
3091
3094
  }
3092
- if (!schema) {
3093
- schema = data;
3094
- return;
3095
+ if (first) {
3096
+ data = obj.data();
3097
+ data.name ||= this.streaming.table;
3098
+ first = false;
3095
3099
  }
3096
- const { rows } = data.value[0];
3097
- win.rows += rows;
3098
- win.segments.push(data);
3099
- if (win.rows >= winsize * 2 && win.segments.length >= 2) {
3100
- let winsize_ = 0;
3101
- let i = win.segments.length - 1;
3102
- // 往前移动至首个累计 winsize_ 超过 winsize 的位置
3103
- for (; winsize_ < winsize; i--)
3104
- winsize_ += win.segments[i].value[0].rows;
3105
- win.segments = win.segments.slice(i);
3106
- win.offset += win.rows - winsize_;
3107
- win.rows = winsize_;
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
+ }
3108
3127
  }
3109
3128
  this.streaming.handler({
3110
3129
  ...this.streaming,
3111
3130
  id: dv.getBigInt64(9, this.le),
3112
3131
  time: dv.getBigInt64(1, this.le),
3113
- rows,
3114
3132
  topic: this.dec.decode(buffer.subarray(17, i_topic_end)),
3115
- colnames,
3116
- schema,
3133
+ obj,
3117
3134
  data,
3118
3135
  window: win,
3119
3136
  });
@@ -3124,9 +3141,9 @@ export class DDB {
3124
3141
  }
3125
3142
  }
3126
3143
  });
3127
- console.log(t('订阅流表成功') + ', colnames:',
3144
+ console.log(t('订阅流表成功') + ', columns:',
3128
3145
  // string[3](['time', 'stock', 'price'])
3129
- colnames);
3146
+ columns);
3130
3147
  }
3131
3148
  }
3132
3149
  /** https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements