dolphindb 3.0.0 → 3.0.2

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.
@@ -0,0 +1,2 @@
1
+ declare const _default: Linter.FlatConfig[];
2
+ export default _default;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eslint.config.js","sourceRoot":"","sources":["eslint.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAE9C,iDAAiD;AACjD,eAAe,CAAC,YAAY,CAAC,CAAA","sourcesContent":["import { xlint_config } from 'xshell/xlint.js'\n\n// eslint-disable-next-line no-restricted-exports\nexport default [xlint_config]\n"]}
package/i18n/dict.json CHANGED
@@ -11,8 +11,8 @@
11
11
  "this.form 必须是 DdbForm.dict, 否则不能调用 to_dict 转换为 js object": {
12
12
  "en": "this.form must be DdbForm.dict, otherwise to_dict cannot be called to convert to js object"
13
13
  },
14
- "当前只支持自动转换 dict<string, any> 为 js object": {
15
- "en": "currently api only supports automatic conversion of dict<string, any> to js object"
14
+ "当前只支持自动转换 dict<string, any | ...dictables> 为 js object": {
15
+ "en": "currently api only supports automatic conversion of dict<string, any | ...dictables> to js object"
16
16
  },
17
17
  "deep = true 时必须设置 strip = true": {
18
18
  "en": "strip = true must be set when deep = true"
@@ -74,8 +74,8 @@
74
74
  "new DdbBlob 不能传空的 value": {
75
75
  "en": "new DdbBlob cannot pass an empty value"
76
76
  },
77
- "vector<{{type}}> 暂时不支持解析": {
78
- "en": "cannot parse vector<{{type}}>"
77
+ "{{form}}<{{type}}> 暂时不支持解析": {
78
+ "en": "cannot parse {{form}}<{{type}}>"
79
79
  },
80
80
  "流数据订阅后一定先返回 schema": {
81
81
  "en": "After subscribing to streaming data, the schema must be returned first."
package/index.d.ts CHANGED
@@ -162,8 +162,7 @@ export declare class DdbObj<TValue extends DdbValue = DdbValue> {
162
162
  to_rows<T extends Record<string, any> = Record<string, any>>(): T[];
163
163
  /** 将 dict<string, any> 自动转换为 js object (Record<string, any>) Automatically convert dict<string, any> to js object (Record<string, any>)
164
164
  - options?:
165
- - strip?: `false` 是否将 DdbObj 中的 value 直接提取、剥离出来作为 js object 的 value (丢弃 DdbObj 中的其余信息,只保留 value)
166
- Whether to directly extract and strip the value in DdbObj as the value of js object (discard the rest of the information in DdbObj, only keep the value)
165
+ - strip?: `false` 是否将 dict<string, any> 中的 value 直接提取、剥离出来作为 js object 的 value (丢弃 DdbObj 中的其余信息,只保留 value)
167
166
  - deep?: `false` 是否递归转换
168
167
  Whether to convert recursively
169
168
  */
@@ -177,13 +176,14 @@ export declare class DdbObj<TValue extends DdbValue = DdbValue> {
177
176
  }): T;
178
177
  }
179
178
  export interface InspectOptions extends UtilInspectOptions {
179
+ /** `util.inspect.defaultOptions.colors` */
180
180
  colors?: boolean;
181
181
  /** `null` decimal places 小数位数 */
182
182
  decimals?: number;
183
183
  /** `true` 决定格式化后的数据是否有千分位 */
184
184
  grouping?: boolean;
185
185
  }
186
- /** 根据 DdbType 格式化单个元素 (value) 为字符串,空值返回 'null' 字符串 Formats a single element (value) as a string according to DdbType, null returns a 'null' string */
186
+ /** 根据 DdbType 格式化单个元素 (value) 为字符串,空值返回 'null' 字符串 */
187
187
  export declare function format(type: DdbType, value: DdbValue, le: boolean, options?: InspectOptions): string;
188
188
  /** 格式化向量、集合中的第 index 项为字符串,空值返回 'null' 字符串 formatted vector, the index-th item in the collection is a string, a null value returns a 'null' string */
189
189
  export declare function formati(obj: DdbVectorObj, index: number, options?: InspectOptions): string;
@@ -401,6 +401,7 @@ export interface DdbOptions {
401
401
  sql?: SqlStandard;
402
402
  streaming?: StreamingParams;
403
403
  verbose?: boolean;
404
+ proxy?: string;
404
405
  }
405
406
  export declare class DDB {
406
407
  /** 当前的 session id (http 或 tcp) */
@@ -409,8 +410,7 @@ export declare class DDB {
409
410
  dec: TextDecoder;
410
411
  enc: TextEncoder;
411
412
  /** DolphinDB WebSocket URL
412
- e.g. `ws://127.0.0.1:8848/`, `wss://dolphindb.com`
413
- */
413
+ e.g. `ws://127.0.0.1:8848/`, `wss://dolphindb.com` */
414
414
  url: string;
415
415
  /** 为所有 websocket 操作加锁,包括设置 this.on_message, this.on_error, websocket.send */
416
416
  lwebsocket: Lock<WebSocket>;
@@ -432,6 +432,8 @@ export declare class DDB {
432
432
  streaming: StreamingParams;
433
433
  /** 是否打印每个 rpc 的信息用于调试 */
434
434
  verbose: boolean;
435
+ /** websocket 连接所使用的 http 代理 */
436
+ proxy: string;
435
437
  print_message_buffer: boolean;
436
438
  print_object_buffer: boolean;
437
439
  print_message: boolean;
package/index.js CHANGED
@@ -9,14 +9,14 @@ import { t } from './i18n/index.js';
9
9
  import { DdbDecimal128Serializor } from './data-types/decimal-128.js';
10
10
  import { BigInt128Array } from './shared/bigint-128-array.js';
11
11
  import { is_decimal_type, is_decimal_null_value, get_duration_unit } from './shared/utils.js';
12
- import { nulls, DdbChartType, DdbDurationUnit, DdbForm, DdbFunctionType, DdbType, DdbVoidType } from './shared/constants.js';
12
+ import { nulls, DdbChartType, DdbDurationUnit, DdbForm, DdbFunctionType, DdbType, DdbVoidType, dictables } from './shared/constants.js';
13
13
  export * from './shared/constants.js';
14
14
  // Simulate other TypedArray behavior in nodejs
15
15
  BigInt128Array.prototype[inspect.custom] = function () {
16
16
  const values = [];
17
17
  for (const value of this)
18
18
  values.push(value);
19
- const value_str = values.length ? ` ${values.map(v => v.toString() + 'n').join(', ')} ` : '';
19
+ const value_str = values.length ? ` ${values.map(v => String(v) + 'n').join(', ')} ` : '';
20
20
  return `${this[Symbol.toStringTag]}(${this.length}) [${value_str}]`;
21
21
  };
22
22
  /** 可以表示所有 DolphinDB 数据库中的数据类型 Can represent data types in all DolphinDB databases */
@@ -127,6 +127,8 @@ export class DdbObj {
127
127
  let i_start = i_items_start + len_items;
128
128
  for (let i = 0; i < cols; i++) {
129
129
  const type = buf_data[i_start];
130
+ if (type === DdbType.compress)
131
+ throw new Error(t('{{form}}<{{type}}> 暂时不支持解析', { form: 'table', type: 'compress' }));
130
132
  let col = this.parse_vector(buf_data.subarray(i_start + 2), le, type);
131
133
  col.length += 2;
132
134
  col.name = colnames[i];
@@ -708,8 +710,16 @@ export class DdbObj {
708
710
  });
709
711
  return [8 * length, durations];
710
712
  }
713
+ case DdbType.compress:
714
+ return [
715
+ length,
716
+ new Uint8Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + length))
717
+ ];
711
718
  default:
712
- throw new Error(t('vector<{{type}}> 暂时不支持解析', { type: String(DdbType[type] || type) }));
719
+ throw new Error(t('{{form}}<{{type}}> 暂时不支持解析', {
720
+ form: 'vector',
721
+ type: String(DdbType[type] || type)
722
+ }));
713
723
  }
714
724
  }
715
725
  pack() {
@@ -940,6 +950,7 @@ export class DdbObj {
940
950
  case DdbType.uuid:
941
951
  case DdbType.ipaddr:
942
952
  case DdbType.int128:
953
+ case DdbType.compress:
943
954
  return [value];
944
955
  case DdbType.blob: {
945
956
  let bufs = new Array(length * 2);
@@ -1120,7 +1131,7 @@ export class DdbObj {
1120
1131
  return format_array(items, data.length > limit);
1121
1132
  }
1122
1133
  default: {
1123
- const limit = 50;
1134
+ const limit = this.type === DdbType.compress ? 5 : 50;
1124
1135
  let items = new Array(Math.min(limit, this.value.length));
1125
1136
  for (let i = 0; i < items.length; i++)
1126
1137
  items[i] = format(this.type, this.value[i], this.le, options);
@@ -1256,15 +1267,20 @@ export class DdbObj {
1256
1267
  to_dict({ strip, deep, } = {}) {
1257
1268
  assert(this.form === DdbForm.dict, t('this.form 必须是 DdbForm.dict, 否则不能调用 to_dict 转换为 js object'));
1258
1269
  const [{ value: keys, type: key_type }, { value: values, type: value_type }] = this.value;
1259
- assert(key_type === DdbType.string && value_type === DdbType.any, t('当前只支持自动转换 dict<string, any> 为 js object'));
1270
+ assert(key_type === DdbType.string && dictables.has(value_type), t('当前只支持自动转换 dict<string, any | ...dictables> 为 js object'));
1260
1271
  assert(!(deep && !strip), t('deep = true 时必须设置 strip = true'));
1261
1272
  let obj = {};
1262
1273
  for (let i = 0; i < this.rows; i++) {
1263
- let value = values[i];
1264
- if (deep && value.form === DdbForm.dict)
1265
- obj[keys[i]] = value.to_dict({ strip, deep });
1274
+ const key = keys[i];
1275
+ if (value_type === DdbType.any) {
1276
+ let value = values[i];
1277
+ if (deep && value.form === DdbForm.dict)
1278
+ obj[key] = value.to_dict({ strip, deep });
1279
+ else
1280
+ obj[key] = strip ? value.value : value;
1281
+ }
1266
1282
  else
1267
- obj[keys[i]] = strip ? value.value : value;
1283
+ obj[key] = values[i];
1268
1284
  }
1269
1285
  return obj;
1270
1286
  }
@@ -1277,7 +1293,7 @@ let _grouping = true;
1277
1293
  let _formatter = new Intl.NumberFormat('en-US', { maximumFractionDigits: 20 });
1278
1294
  /** 用来处理时差 To deal with jet lag */
1279
1295
  let _datetime_formatter = new Intl.DateTimeFormat('zh-CN', { dateStyle: 'short', timeStyle: 'medium', timeZone: 'UTC', hour12: false });
1280
- /** 根据 DdbType 格式化单个元素 (value) 为字符串,空值返回 'null' 字符串 Formats a single element (value) as a string according to DdbType, null returns a 'null' string */
1296
+ /** 根据 DdbType 格式化单个元素 (value) 为字符串,空值返回 'null' 字符串 */
1281
1297
  export function format(type, value, le, options = {}) {
1282
1298
  const formatter = (() => {
1283
1299
  const { grouping = true } = options;
@@ -2140,14 +2156,8 @@ export class DDB {
2140
2156
  /** utf-8 text decoder */
2141
2157
  dec = new TextDecoder('utf-8');
2142
2158
  enc = new TextEncoder();
2143
- // port = 8848
2144
- // /** ddb 连接状态 */
2145
- // state = '未连接'
2146
- // socket = null as Socket
2147
- // clients = new Set<Duplex>()
2148
2159
  /** DolphinDB WebSocket URL
2149
- e.g. `ws://127.0.0.1:8848/`, `wss://dolphindb.com`
2150
- */
2160
+ e.g. `ws://127.0.0.1:8848/`, `wss://dolphindb.com` */
2151
2161
  url;
2152
2162
  /** 为所有 websocket 操作加锁,包括设置 this.on_message, this.on_error, websocket.send */
2153
2163
  lwebsocket = new Lock();
@@ -2169,6 +2179,8 @@ export class DDB {
2169
2179
  streaming = null;
2170
2180
  /** 是否打印每个 rpc 的信息用于调试 */
2171
2181
  verbose = false;
2182
+ /** websocket 连接所使用的 http 代理 */
2183
+ proxy;
2172
2184
  // --- 内部选项, 状态
2173
2185
  print_message_buffer = false;
2174
2186
  print_object_buffer = false;
@@ -2227,6 +2239,8 @@ export class DDB {
2227
2239
  this.sql = options.sql;
2228
2240
  if (options.streaming !== undefined)
2229
2241
  this.streaming = options.streaming;
2242
+ if (options.proxy)
2243
+ this.proxy = options.proxy;
2230
2244
  }
2231
2245
  on_message(buffer, websocket) {
2232
2246
  throw new Error(t('这是在调用 this.rpc 之前默认的 on_message, 不应该被调用到,除非建立连接后 server 先推送了 message'));
@@ -2268,6 +2282,7 @@ export class DDB {
2268
2282
  // 连接建立之前应该不会有别的调用占用 this.lwebsocket
2269
2283
  this.lwebsocket.resource = await connect_websocket(url, {
2270
2284
  protocols: this.streaming ? ['streaming'] : this.python ? ['python'] : undefined,
2285
+ proxy: this.proxy,
2271
2286
  on_message: (buffer, websocket) => {
2272
2287
  this.on_message(new Uint8Array(buffer), websocket);
2273
2288
  },
@@ -2729,157 +2744,4 @@ export class DDB {
2729
2744
  colnames);
2730
2745
  }
2731
2746
  }
2732
- // const ddb_gateway = {
2733
- // server: null as SocketServer,
2734
- // clients: new Set<Socket>(),
2735
- // port: 8849,
2736
- // controllers: {
2737
- // /** alias */
2738
- // c0: {
2739
- // hostname: '127.0.0.1',
2740
- // port: 8850,
2741
- // },
2742
- // c1: {
2743
- // hostname: '127.0.0.1',
2744
- // port: 8851,
2745
- // },
2746
- // c2: {
2747
- // hostname: '127.0.0.1',
2748
- // port: 8852,
2749
- // }
2750
- // },
2751
- // master: '',
2752
- // sids: new Map<string, string>(),
2753
- // state: 'init',
2754
- // async start () {
2755
- // for (const alias in this.controllers) {
2756
- // this.master = alias
2757
- // break
2758
- // }
2759
- // this.server = create_socket_server(
2760
- // {
2761
- // allowHalfOpen: false,
2762
- // pauseOnConnect: false,
2763
- // },
2764
- // this.accept.bind(this)
2765
- // )
2766
- // this.server.on('error', error => {
2767
- // console.log(new Date(), 'gateway 出错:', error)
2768
- // })
2769
- // await new Promise<void>(resolve => {
2770
- // this.server.listen(this.port, resolve)
2771
- // })
2772
- // this.auto_switch_master()
2773
- // console.log(new Date(), 'gateway 成功启动')
2774
- // },
2775
- // async stop () {
2776
- // this.state = 'stopping'
2777
- // console.log(new Date(), '正在停止 auto_switch_master')
2778
- // for (const client of this.clients)
2779
- // client.end()
2780
- // await new Promise<void>((resolve, reject) => {
2781
- // this.server.close(error => {
2782
- // if (error) {
2783
- // reject(error)
2784
- // return
2785
- // }
2786
- // resolve()
2787
- // })
2788
- // })
2789
- // },
2790
- // /** 接收到 client tcp 连接 */
2791
- // async accept (client: Socket) {
2792
- // this.clients.add(client)
2793
- // const port = client.remotePort
2794
- // // ---
2795
- // console.log(port, new Date(), 'gateway accept client 连接,开始建立管道')
2796
- // let controller = new Socket({
2797
- // allowHalfOpen: false,
2798
- // readable: true,
2799
- // writable: true,
2800
- // })
2801
- // controller.on('lookup', (error, address, family, host) => {
2802
- // console.log(port, new Date(), 'controller 域名解析 (lookup) 完成', error, address, family, host)
2803
- // })
2804
- // controller.on('close', has_error => {
2805
- // console.log(port, new Date(), 'controller 关闭连接,是否出错:', has_error)
2806
- // })
2807
- // controller.on('timeout', () => {
2808
- // console.log(port, new Date(), 'controller 超时')
2809
- // })
2810
- // controller.on('error', error => {
2811
- // console.log(port, new Date(), 'controller 出错了:', error)
2812
- // client.end()
2813
- // })
2814
- // // --- client 错误处理
2815
- // client.on('error', error => {
2816
- // console.log(port, new Date(), 'client 出错,关闭与 controller 的连接', error)
2817
- // controller.end()
2818
- // })
2819
- // client.on('close', has_error => {
2820
- // this.clients.delete(client)
2821
- // console.log(port, new Date(), 'client 关闭连接,是否出错:', has_error)
2822
- // })
2823
- // // ---
2824
- // console.log(port, new Date(), 'gateway 开始连接到 controller')
2825
- // const { hostname, port: master_port } = this.controllers[this.master]
2826
- // await new Promise<void>(resolve => {
2827
- // // callback 会被 socket.once('connect', callback)
2828
- // controller.connect({
2829
- // port: master_port,
2830
- // host: hostname,
2831
- // // host: '127.0.0.1',
2832
- // family: 0,
2833
- // }, resolve)
2834
- // })
2835
- // console.log(port, new Date(), 'gateway 已连接到 controller')
2836
- // // ---
2837
- // console.log(port, new Date(), 'gateway 建立 client <-> controller')
2838
- // client.pipe(controller)
2839
- // controller.pipe(client)
2840
- // },
2841
- // /** https://www.dolphindb.cn/cn/help/FunctionsandCommands/FunctionReferences/g/getActiveMaster.html?highlight=getactivemaster */
2842
- // async get_active_master () {
2843
- // for (const alias in this.controllers) {
2844
- // const { hostname, port } = this.controllers[alias] as { hostname: string, port: number }
2845
- // const sid = this.sids.get(alias)
2846
- // try {
2847
- // const master = (
2848
- // await ddb.rpc_json('getActiveMaster()', { hostname, port, sid })
2849
- // ).value as string
2850
- // console.log(new Date(), `${alias}.getActiveMaster() -> ${this.master}`)
2851
- // this.sids.set(alias, sid)
2852
- // if (!master)
2853
- // throw new Error(`${new Date().toString()} getActiveMaster 得到的 master 为空`)
2854
- // return master
2855
- // } catch (error) {
2856
- // console.log(new Date(), error)
2857
- // }
2858
- // }
2859
- // return this.master
2860
- // },
2861
- // async auto_switch_master () {
2862
- // if (this.state === 'stopping') {
2863
- // this.state = 'running'
2864
- // console.log('gateway 恢复 auto_switch_master')
2865
- // return
2866
- // }
2867
- // this.state = 'running'
2868
- // for (; this.state === 'running'; ) {
2869
- // const master = this.master
2870
- // const master_ = await this.get_active_master()
2871
- // if (master === master_) {
2872
- // await delay(10 * 1000)
2873
- // continue
2874
- // }
2875
- // this.master = master_
2876
- // console.log(new Date(), `master 从 ${master} 切换为 ${master_}, 断开所有 clients`)
2877
- // for (const client of this.clients)
2878
- // client.end()
2879
- // await delay(3 * 1000)
2880
- // }
2881
- // console.log(new Date(), `gateway.state === ${this.state}, 停止 auto_switch_master`)
2882
- // this.state = 'stopped'
2883
- // }
2884
- // }
2885
2747
  //# sourceMappingURL=index.js.map