dolphindb 2.0.800 → 2.0.801

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
@@ -262,7 +262,7 @@ export declare class DdbObj<TValue extends DdbValue = DdbValue> {
262
262
  to_cols(): {
263
263
  title: string;
264
264
  dataIndex: string;
265
- render?: any;
265
+ render: (value: any) => string;
266
266
  }[];
267
267
  to_rows<T extends Record<string, any> = Record<string, any>>(): T[];
268
268
  /** Automatically convert dict<string, any> to js object (Record<string, any>)
@@ -283,10 +283,14 @@ export interface InspectOptions {
283
283
  colors?: boolean;
284
284
  /** decimal places */
285
285
  decimals?: number;
286
+ /** `false` 决定 null 值如何返回. nullstr ? 'null' : '' */
287
+ nullstr?: boolean;
288
+ /** `false` 决定 string, symbol, char 类型是否加引号 */
289
+ quote?: boolean;
286
290
  }
287
291
  /** Formats a single element (value) as a string according to DdbType, null returns a 'null' string */
288
292
  export declare function format(type: DdbType, value: DdbValue, le: boolean, options?: InspectOptions): string;
289
- /** formatted vector, the index-th item in the collection is a string, a null value returns a 'null' string */
293
+ /** formatted vector, the index-th item in the collection is a string */
290
294
  export declare function formati(obj: DdbVectorObj, index: number, options?: InspectOptions): string;
291
295
  export declare class DdbVoid extends DdbObj<undefined> {
292
296
  constructor();
@@ -442,6 +446,10 @@ export interface StreamingData extends StreamingParams {
442
446
  };
443
447
  }
444
448
  export declare const winsize: 40;
449
+ export declare class ConnectionError extends Error {
450
+ ddb: DDB;
451
+ constructor(ddb: DDB);
452
+ }
445
453
  export declare class DDB {
446
454
  /** 当前的 session id (http 或 tcp) */
447
455
  sid: string;
@@ -508,23 +516,10 @@ export declare class DDB {
508
516
  streaming?: StreamingParams;
509
517
  });
510
518
  private on_message;
511
- /** Establish the actual WebSocket connection to the DolphinDB corresponding to the URL
512
- - options?:
513
- - url?: DolphinDB WebSocket URL. By default, the WebSocket URL passed in when the instance is initialized is used
514
- - autologin?: Whether to log in automatically after establishing a connection, default `true`
515
- - username?: DolphinDB username, default `'admin'`
516
- - password?: DolphinDB password, default `'123456'`
517
- - python?: set python session flag, default `false`
518
- - streaming?: When this option is set, the WebSocket connection is only used for streaming data
519
- */
520
- connect({ url, autologin, username, password, python, streaming }?: {
521
- url?: string;
522
- autologin?: boolean;
523
- username?: string;
524
- password?: string;
525
- python?: boolean;
526
- streaming?: StreamingParams;
527
- }): Promise<void>;
519
+ /** Establish a actual websocket connection to the DolphindB corresponding to the URL
520
+ After calling, it will ensure that it has been connected to the database (ensure that websocket.ReadyState is open), otherwise an error will be reported
521
+ this.autologin automatically log in when it is true */
522
+ connect(): Promise<void>;
528
523
  get_rpc_options({ urgent, secondary, async: _async, pickle, clear, api, compress, cancellable, priority, parallelism, root_id, limit, }?: {
529
524
  urgent?: boolean;
530
525
  /** API 提交的任务, secondary 必须为 false */
@@ -550,6 +545,7 @@ export declare class DDB {
550
545
  }): string;
551
546
  disconnect(): void;
552
547
  /** rpc through websocket (function/script/variable command)
548
+ When the DDB is not connected, the call will be automatically connected. When the connection is disconnected, the call will throw the Connectionerror
553
549
  - type: API 类型: 'script' | 'function' | 'variable'
554
550
  - options:
555
551
  - urgent?: 决定 `行为标识` 那一行字符串的取值(只适用于 script 和 function)
package/browser.js CHANGED
@@ -4,7 +4,7 @@ dayjs.extend(DayjsCustomParseFormat);
4
4
  import ipaddrjs from 'ipaddr.js';
5
5
  const { fromByteArray: buf2ipaddr } = ipaddrjs;
6
6
  import 'xshell/prototype.browser.js';
7
- import { blue } from 'xshell/chalk.browser.js';
7
+ import { blue, cyan, green, grey, magenta } from 'xshell/chalk.browser.js';
8
8
  import { concat, assert } from 'xshell/utils.browser.js';
9
9
  import { connect_websocket } from 'xshell/net.browser.js';
10
10
  export var DdbForm;
@@ -1018,7 +1018,7 @@ export class DdbObj {
1018
1018
  throw new Error(`vector ${DdbType[type]} 暂不支持序列化`);
1019
1019
  }
1020
1020
  }
1021
- toString(options) {
1021
+ toString(options = { nullstr: true, quote: true }) {
1022
1022
  const type = this.inspect_type();
1023
1023
  const data = (() => {
1024
1024
  switch (this.form) {
@@ -1165,27 +1165,11 @@ export class DdbObj {
1165
1165
  }
1166
1166
  to_cols() {
1167
1167
  assert(this.form === DdbForm.table, 'form must be DdbForm.table, otherwise it cannot to_cols');
1168
- return this.value.map(col => {
1169
- let col_ = {
1170
- title: col.name,
1171
- dataIndex: col.name,
1172
- };
1173
- switch (col.type) {
1174
- case DdbType.char:
1175
- col_.render = (value) => format(DdbType.char, value, this.le);
1176
- break;
1177
- case DdbType.timestamp:
1178
- col_.render = (value) => timestamp2str(value);
1179
- break;
1180
- case DdbType.date:
1181
- col_.render = (value) => date2str(value);
1182
- break;
1183
- case DdbType.ipaddr:
1184
- col_.render = (value) => ipaddr2str(value, this.le);
1185
- break;
1186
- }
1187
- return col_;
1188
- });
1168
+ return this.value.map(col => ({
1169
+ title: col.name,
1170
+ dataIndex: col.name,
1171
+ render: (value) => format(col.type, value, col.le, { nullstr: false, quote: false })
1172
+ }));
1189
1173
  }
1190
1174
  to_rows() {
1191
1175
  assert(this.form === DdbForm.table, 'form must be DdbForm.table, otherwise it cannot to_rows');
@@ -1242,8 +1226,8 @@ let _decimals = 20;
1242
1226
  let _formatter = Intl.NumberFormat('en-US', { maximumFractionDigits: 20 });
1243
1227
  /** Formats a single element (value) as a string according to DdbType, null returns a 'null' string */
1244
1228
  export function format(type, value, le, options = {}) {
1229
+ const { decimals, nullstr = false, colors = false, quote = false } = options;
1245
1230
  const formatter = (() => {
1246
- const { decimals } = options;
1247
1231
  if (decimals === undefined || decimals === null)
1248
1232
  return default_formatter;
1249
1233
  if (decimals !== _decimals) {
@@ -1252,117 +1236,176 @@ export function format(type, value, le, options = {}) {
1252
1236
  }
1253
1237
  return _formatter;
1254
1238
  })();
1239
+ function get_nullstr() {
1240
+ return nullstr ?
1241
+ colors ? grey('null') : 'null'
1242
+ :
1243
+ '';
1244
+ }
1255
1245
  switch (type) {
1256
1246
  case DdbType.bool:
1257
- return String((value === null || value === nulls.int8) ?
1258
- null
1259
- :
1260
- Boolean(value));
1247
+ if (value === null || value === nulls.int8)
1248
+ return get_nullstr();
1249
+ else {
1250
+ const str = String(Boolean(value));
1251
+ return colors ? blue(str) : str;
1252
+ }
1261
1253
  case DdbType.char:
1262
- return String((value === null || value === nulls.int8) ?
1263
- null
1264
- :
1265
- // ascii printable
1266
- // http://facweb.cs.depaul.edu/sjost/it212/documents/ascii-pr.htm
1267
- (32 <= value && value <= 126) ?
1268
- String.fromCharCode(value).quote()
1269
- :
1270
- value);
1254
+ if (value === null || value === nulls.int8)
1255
+ return get_nullstr();
1256
+ else {
1257
+ let str =
1258
+ // ascii printable
1259
+ // http://facweb.cs.depaul.edu/sjost/it212/documents/ascii-pr.htm
1260
+ (32 <= value && value <= 126) ?
1261
+ String.fromCharCode(value)
1262
+ :
1263
+ '\\' + String(value);
1264
+ if (quote)
1265
+ str = str.quote();
1266
+ return colors ? green(str) : str;
1267
+ }
1271
1268
  case DdbType.short:
1272
- return (value === null || value === nulls.int16) ?
1273
- 'null'
1274
- :
1275
- default_formatter.format(value);
1269
+ if (value === null || value === nulls.int16)
1270
+ return get_nullstr();
1271
+ else {
1272
+ const str = default_formatter.format(value);
1273
+ return colors ? green(str) : str;
1274
+ }
1276
1275
  case DdbType.int:
1277
- return (value === null || value === nulls.int32) ?
1278
- 'null'
1279
- :
1280
- default_formatter.format(value);
1276
+ if (value === null || value === nulls.int32)
1277
+ return get_nullstr();
1278
+ else {
1279
+ const str = default_formatter.format(value);
1280
+ return colors ? green(str) : str;
1281
+ }
1281
1282
  case DdbType.long:
1282
- return (value === null || value === nulls.int64) ?
1283
- 'null'
1284
- :
1285
- default_formatter.format(value);
1283
+ if (value === null || value === nulls.int64)
1284
+ return get_nullstr();
1285
+ else {
1286
+ const str = default_formatter.format(value);
1287
+ return colors ? green(str) : str;
1288
+ }
1286
1289
  case DdbType.date:
1287
- return (value === null || value === nulls.int32) ?
1288
- 'null'
1289
- :
1290
- date2str(value);
1290
+ if (value === null || value === nulls.int16)
1291
+ return get_nullstr();
1292
+ else {
1293
+ const str = date2str(value);
1294
+ return colors ? magenta(str) : str;
1295
+ }
1291
1296
  case DdbType.month:
1292
- return (value === null || value === nulls.int32) ?
1293
- 'null'
1294
- :
1295
- month2str(value);
1297
+ if (value === null || value === nulls.int32)
1298
+ return get_nullstr();
1299
+ else {
1300
+ const str = month2str(value);
1301
+ return colors ? magenta(str) : str;
1302
+ }
1296
1303
  case DdbType.time:
1297
- return (value === null || value === nulls.int32) ?
1298
- 'null'
1299
- :
1300
- time2str(value);
1304
+ if (value === null || value === nulls.int32)
1305
+ return get_nullstr();
1306
+ else {
1307
+ const str = time2str(value);
1308
+ return colors ? magenta(str) : str;
1309
+ }
1301
1310
  case DdbType.minute:
1302
- return (value === null || value === nulls.int32) ?
1303
- 'null'
1304
- :
1305
- minute2str(value);
1311
+ if (value === null || value === nulls.int16)
1312
+ return get_nullstr();
1313
+ else {
1314
+ const str = minute2str(value);
1315
+ return colors ? magenta(str) : str;
1316
+ }
1306
1317
  case DdbType.second:
1307
- return (value === null || value === nulls.int32) ?
1308
- 'null'
1309
- :
1310
- second2str(value);
1318
+ if (value === null || value === nulls.int32)
1319
+ return get_nullstr();
1320
+ else {
1321
+ const str = second2str(value);
1322
+ return colors ? magenta(str) : str;
1323
+ }
1311
1324
  case DdbType.datetime:
1312
- return (value === null || value === nulls.int32) ?
1313
- 'null'
1314
- :
1315
- datetime2str(value);
1325
+ if (value === null || value === nulls.int32)
1326
+ return get_nullstr();
1327
+ else {
1328
+ const str = datetime2str(value);
1329
+ return colors ? magenta(str) : str;
1330
+ }
1316
1331
  case DdbType.timestamp:
1317
- return (value === null || value === nulls.int64) ?
1318
- 'null'
1319
- :
1320
- timestamp2str(value);
1332
+ if (value === null || value === nulls.int64)
1333
+ return get_nullstr();
1334
+ else {
1335
+ const str = timestamp2str(value);
1336
+ return colors ? magenta(str) : str;
1337
+ }
1321
1338
  case DdbType.nanotime:
1322
- return (value === null || value === nulls.int64) ?
1323
- 'null'
1324
- :
1325
- nanotime2str(value);
1339
+ if (value === null || value === nulls.int64)
1340
+ return get_nullstr();
1341
+ else {
1342
+ const str = nanotime2str(value);
1343
+ return colors ? magenta(str) : str;
1344
+ }
1326
1345
  case DdbType.nanotimestamp:
1327
- return (value === null || value === nulls.int64) ?
1328
- 'null'
1329
- :
1330
- nanotimestamp2str(value);
1346
+ if (value === null || value === nulls.int64)
1347
+ return get_nullstr();
1348
+ else {
1349
+ const str = nanotimestamp2str(value);
1350
+ return colors ? magenta(str) : str;
1351
+ }
1331
1352
  case DdbType.float:
1332
- return (value === null || value === nulls.float32) ?
1333
- 'null'
1334
- :
1335
- formatter.format(value);
1353
+ if (value === null || value === nulls.float32)
1354
+ return get_nullstr();
1355
+ else {
1356
+ const str = formatter.format(value);
1357
+ return colors ? green(str) : str;
1358
+ }
1336
1359
  case DdbType.double:
1337
- return (value === null || value === nulls.double) ?
1338
- 'null'
1339
- :
1340
- formatter.format(value);
1360
+ if (value === null || value === nulls.double)
1361
+ return get_nullstr();
1362
+ else {
1363
+ const str = formatter.format(value);
1364
+ return colors ? green(str) : str;
1365
+ }
1341
1366
  case DdbType.symbol:
1342
- case DdbType.string:
1343
- return value.quote('single');
1344
- case DdbType.uuid:
1345
- return uuid2str(value, le);
1346
- case DdbType.functiondef:
1347
- return value.name.quote('single');
1367
+ case DdbType.string: {
1368
+ let str = value;
1369
+ if (quote)
1370
+ str = str.quote('single');
1371
+ return colors ? cyan(str) : str;
1372
+ }
1373
+ case DdbType.uuid: {
1374
+ const str = uuid2str(value, le);
1375
+ return colors ? cyan(str) : str;
1376
+ }
1377
+ case DdbType.functiondef: {
1378
+ const str = value.name.quote('single');
1379
+ return colors ? cyan(str) : str;
1380
+ }
1348
1381
  case DdbType.handle:
1349
1382
  case DdbType.code:
1350
- case DdbType.resource:
1351
- return value.quote('single');
1383
+ case DdbType.resource: {
1384
+ const str = value.quote('single');
1385
+ return colors ? cyan(str) : str;
1386
+ }
1352
1387
  case DdbType.datehour:
1353
- return (value === null || value === nulls.int32) ?
1354
- 'null'
1355
- :
1356
- datehour2str(value);
1357
- case DdbType.ipaddr:
1358
- return ipaddr2str(value, le);
1359
- case DdbType.int128:
1360
- return int1282str(value, le);
1361
- case DdbType.blob:
1362
- return (value.length > 100 ?
1388
+ if (value === null || value === nulls.int32)
1389
+ return get_nullstr();
1390
+ else {
1391
+ const str = datehour2str(value);
1392
+ return colors ? magenta(str) : str;
1393
+ }
1394
+ case DdbType.ipaddr: {
1395
+ const str = ipaddr2str(value, le);
1396
+ return colors ? cyan(str) : str;
1397
+ }
1398
+ case DdbType.int128: {
1399
+ const str = int1282str(value, le);
1400
+ return colors ? cyan(str) : str;
1401
+ }
1402
+ case DdbType.blob: {
1403
+ const str = value.length > 100 ?
1363
1404
  DdbObj.dec.decode(value.subarray(0, 98)) + '…'
1364
1405
  :
1365
- DdbObj.dec.decode(value)).quote('single');
1406
+ DdbObj.dec.decode(value);
1407
+ return colors ? cyan(str) : str;
1408
+ }
1366
1409
  case DdbType.point: {
1367
1410
  const [x, y] = value;
1368
1411
  return `(${format(DdbType.double, x, le, options)}, ${format(DdbType.double, y, le, options)})`;
@@ -1373,7 +1416,8 @@ export function format(type, value, le, options = {}) {
1373
1416
  }
1374
1417
  case DdbType.duration: {
1375
1418
  const { data, unit } = value;
1376
- return `${data}${DdbDurationUnit[unit]}`;
1419
+ const str = `${data}${DdbDurationUnit[unit]}`;
1420
+ return colors ? magenta(str) : str;
1377
1421
  }
1378
1422
  case DdbType.decimal32:
1379
1423
  case DdbType.decimal64: {
@@ -1381,15 +1425,16 @@ export function format(type, value, le, options = {}) {
1381
1425
  if (data === null ||
1382
1426
  (data === nulls.int64 && type === DdbType.decimal64) ||
1383
1427
  (data === nulls.int32 && type === DdbType.decimal32))
1384
- return 'null';
1428
+ return get_nullstr();
1385
1429
  const s = String(data < 0 ? -data : data).padStart(scale, '0');
1386
- return (data < 0 ? '-' : '') + (scale ? `${s.slice(0, -scale) || '0'}.${s.slice(-scale)}` : s);
1430
+ const str = (data < 0 ? '-' : '') + (scale ? `${s.slice(0, -scale) || '0'}.${s.slice(-scale)}` : s);
1431
+ return colors ? green(str) : str;
1387
1432
  }
1388
1433
  default:
1389
1434
  return String(value);
1390
1435
  }
1391
1436
  }
1392
- /** formatted vector, the index-th item in the collection is a string, a null value returns a 'null' string */
1437
+ /** formatted vector, the index-th item in the collection is a string */
1393
1438
  export function formati(obj, index, options = {}) {
1394
1439
  if (64 <= obj.type && obj.type < 128) { // array vector
1395
1440
  // 因为 array vector 目前只支持:Logical, Integral(不包括 INT128, COMPRESS 类型), Floating, Temporal
@@ -1424,12 +1469,9 @@ export function formati(obj, index, options = {}) {
1424
1469
  }
1425
1470
  }
1426
1471
  switch (obj.type) {
1427
- case DdbType.string:
1428
- case DdbType.symbol:
1429
- return obj.value[index];
1430
1472
  case DdbType.symbol_extended: {
1431
1473
  const { base, data } = obj.value;
1432
- return base[data[index]];
1474
+ return format(DdbType.string, base[data[index]], obj.le, options);
1433
1475
  }
1434
1476
  case DdbType.uuid:
1435
1477
  case DdbType.int128:
@@ -1453,7 +1495,8 @@ export function formati(obj, index, options = {}) {
1453
1495
  x === nulls.int32 && obj.type === DdbType.decimal32)
1454
1496
  return '';
1455
1497
  const s = String(x < 0 ? -x : x).padStart(scale, '0');
1456
- return (x < 0 ? '-' : '') + (scale ? `${s.slice(0, -scale) || '0'}.${s.slice(-scale)}` : s);
1498
+ const str = (x < 0 ? '-' : '') + (scale ? `${s.slice(0, -scale) || '0'}.${s.slice(-scale)}` : s);
1499
+ return options.colors ? green(str) : str;
1457
1500
  }
1458
1501
  default:
1459
1502
  return format(obj.type, obj.value[index], obj.le, options);
@@ -1972,6 +2015,13 @@ export function int1282str(buffer, le = true) {
1972
2015
  .padStart(2, '0')).join('');
1973
2016
  }
1974
2017
  export const winsize = 40;
2018
+ export class ConnectionError extends Error {
2019
+ ddb;
2020
+ constructor(ddb) {
2021
+ super(`websocket is disconnected: ${ddb.url}`);
2022
+ this.ddb = ddb;
2023
+ }
2024
+ }
1975
2025
  export class DDB {
1976
2026
  /** 当前的 session id (http 或 tcp) */
1977
2027
  sid = '0';
@@ -2053,52 +2103,50 @@ export class DDB {
2053
2103
  this.streaming = options.streaming;
2054
2104
  }
2055
2105
  on_message(event) {
2056
- console.log('This is the default on_message before calling this.rpc, it should not be called unless the server pushes the message first after the connection is established');
2057
- console.log(event.data);
2106
+ // 这里的实现一定会被 connect 中的实现覆盖
2058
2107
  }
2059
- /** Establish the actual WebSocket connection to the DolphinDB corresponding to the URL
2060
- - options?:
2061
- - url?: DolphinDB WebSocket URL. By default, the WebSocket URL passed in when the instance is initialized is used
2062
- - autologin?: Whether to log in automatically after establishing a connection, default `true`
2063
- - username?: DolphinDB username, default `'admin'`
2064
- - password?: DolphinDB password, default `'123456'`
2065
- - python?: set python session flag, default `false`
2066
- - streaming?: When this option is set, the WebSocket connection is only used for streaming data
2067
- */
2068
- async connect({ url, autologin, username, password, python, streaming } = {}) {
2069
- if (url !== undefined)
2070
- this.url = url;
2071
- if (autologin !== undefined)
2072
- this.autologin = autologin;
2073
- if (username !== undefined)
2074
- this.username = username;
2075
- if (password !== undefined)
2076
- this.password = password;
2077
- if (python !== undefined)
2078
- this.python = python;
2079
- if (streaming !== undefined)
2080
- this.streaming = streaming;
2081
- this.disconnect();
2082
- await connect_websocket(this.url, {
2083
- protocols: (() => {
2084
- if (this.streaming)
2085
- return 'streaming';
2086
- if (this.python)
2087
- return 'python';
2088
- })(),
2089
- on_open: async (event, websocket) => {
2090
- this.websocket = websocket;
2108
+ /** Establish a actual websocket connection to the DolphindB corresponding to the URL
2109
+ After calling, it will ensure that it has been connected to the database (ensure that websocket.ReadyState is open), otherwise an error will be reported
2110
+ this.autologin automatically log in when it is true */
2111
+ async connect() {
2112
+ if (this.connected)
2113
+ return;
2114
+ const ptail = this.pconnect;
2115
+ let resolve;
2116
+ this.pconnect = new Promise((_resolve, _reject) => {
2117
+ resolve = _resolve;
2118
+ });
2119
+ await ptail;
2120
+ try {
2121
+ if (!this.connected) {
2122
+ this.on_message = (event) => {
2123
+ assert(false, 'This is the default on_message before calling this.rpc, and it should not be called. Unless the server pushed message first after the connection is established');
2124
+ };
2125
+ this.presult = Promise.resolve(null);
2126
+ this.pnode_run_defined = false;
2127
+ this.websocket = await connect_websocket(this.url, {
2128
+ protocols: (() => {
2129
+ if (this.streaming)
2130
+ return 'streaming';
2131
+ if (this.python)
2132
+ return 'python';
2133
+ })(),
2134
+ on_message: (event) => {
2135
+ this.on_message(event);
2136
+ }
2137
+ });
2091
2138
  if (this.streaming)
2092
2139
  await this.subscribe();
2093
- else
2140
+ else {
2094
2141
  await this.rpc('connect', {});
2095
- },
2096
- on_message: (event) => {
2097
- this.on_message(event);
2142
+ if (this.autologin)
2143
+ await this.call('login', [this.username, this.password], { urgent: true });
2144
+ }
2098
2145
  }
2099
- });
2100
- if (!this.streaming && this.autologin)
2101
- await this.call('login', [this.username, this.password], { urgent: true });
2146
+ }
2147
+ finally {
2148
+ resolve();
2149
+ }
2102
2150
  }
2103
2151
  get_rpc_options({ urgent = false, secondary = false, async: _async = false, pickle = false, clear = false, api = false, compress = false, cancellable = true, priority = urgent ? 8 : 4, parallelism = 8, root_id = '', limit, } = {}) {
2104
2152
  let flag = 0;
@@ -2134,12 +2182,9 @@ export class DDB {
2134
2182
  disconnect() {
2135
2183
  if (this.connected)
2136
2184
  this.websocket.close(1000);
2137
- this.on_message = () => { };
2138
- this.presult = Promise.resolve(null);
2139
- this.pconnect = Promise.resolve();
2140
- this.pnode_run_defined = false;
2141
2185
  }
2142
2186
  /** rpc through websocket (function/script/variable command)
2187
+ When the DDB is not connected, the call will be automatically connected. When the connection is disconnected, the call will throw the Connectionerror
2143
2188
  - type: API 类型: 'script' | 'function' | 'variable'
2144
2189
  - options:
2145
2190
  - urgent?: 决定 `行为标识` 那一行字符串的取值(只适用于 script 和 function)
@@ -2149,24 +2194,12 @@ export class DDB {
2149
2194
  为 false 时返回的 DdbObj 仅含有 buffer 和 le,不做解析,以便后续转发、序列化
2150
2195
  */
2151
2196
  async rpc(type, { script, func, args = [], vars = [], urgent, listener, parse_object, }) {
2152
- if (!this.websocket) {
2153
- const ptail = this.pconnect;
2154
- let resolve;
2155
- this.pconnect = new Promise((_resolve, _reject) => {
2156
- resolve = _resolve;
2157
- });
2158
- await ptail;
2159
- try {
2160
- if (!this.websocket)
2161
- await this.connect();
2162
- }
2163
- finally {
2164
- resolve();
2165
- }
2166
- }
2197
+ if (!this.websocket)
2198
+ await this.connect();
2167
2199
  if (!this.connected)
2168
- throw new Error(`${this.url} is already disconnected`);
2200
+ throw new ConnectionError(this);
2169
2201
  if (func === 'pnode_run' && !this.pnode_run_defined) {
2202
+ // 保证并发调用 rpc 时只定义一次 pnode_run
2170
2203
  const ptail = this.ppnoderun;
2171
2204
  let resolve;
2172
2205
  this.ppnoderun = new Promise((_resolve, _reject) => {
@@ -2464,7 +2497,7 @@ export class DDB {
2464
2497
  if (status === StreamingStatusCode.ok)
2465
2498
  console.log('Subscribed to streaming table:', { status: StreamingStatusCode[status], result: objs[0] });
2466
2499
  else
2467
- reject(new Error(`Failed to subscribe to streaming table: { status: ${StreamingStatusCode[status]}, error: ${objs[0]?.value} }`));
2500
+ reject(new Error(`Failed to subscribe to streaming table: { status: ${StreamingStatusCode[status]}, error: '${objs[0]?.value}' }`));
2468
2501
  }
2469
2502
  catch (error) {
2470
2503
  reject(error);
@@ -2496,7 +2529,7 @@ export class DDB {
2496
2529
  // 是 column 片段组成的 any vector
2497
2530
  const data = streaming.data = DdbObj.parse(buf.subarray(i_topic_end + 1), this.le);
2498
2531
  let { window: win } = streaming;
2499
- win.rows += data.rows;
2532
+ win.rows += data.value[0].rows;
2500
2533
  win.segments.push(data);
2501
2534
  if (win.rows >= winsize * 2 && win.segments.length >= 2) {
2502
2535
  let winsize_ = 0;