@naturalcycles/db-lib 8.24.1 → 8.25.0

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.
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CacheDB = void 0;
4
4
  const stream_1 = require("stream");
5
5
  const base_common_db_1 = require("../../base.common.db");
6
- const isGAE = !!process.env['GAE_INSTANCE'];
7
6
  /**
8
7
  * CommonDB implementation that proxies requests to downstream CommonDB
9
8
  * and does in-memory caching.
@@ -14,7 +13,7 @@ class CacheDB extends base_common_db_1.BaseCommonDB {
14
13
  constructor(cfg) {
15
14
  super();
16
15
  this.cfg = {
17
- logger: isGAE ? undefined : console,
16
+ logger: console,
18
17
  ...cfg,
19
18
  };
20
19
  }
@@ -33,10 +33,7 @@ export interface CacheDBCfg {
33
33
  */
34
34
  logDownstream?: boolean;
35
35
  /**
36
- * Pass noopLogger (or undefined) to skip logging completely.
37
- *
38
- * Defaults to `console` in dev.
39
- * Default to noop in AppEngine.
36
+ * Defaults to `console`.
40
37
  */
41
38
  logger?: CommonLogger;
42
39
  }
@@ -5,7 +5,6 @@ const js_lib_1 = require("@naturalcycles/js-lib");
5
5
  const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
6
6
  const colors_1 = require("@naturalcycles/nodejs-lib/dist/colors");
7
7
  const __1 = require("../..");
8
- const isGAE = !!process.env['GAE_INSTANCE'];
9
8
  /**
10
9
  * Provides barebone implementation for "whole file" based CommonDB.
11
10
  * "whole file" means that the persistence layer doesn't allow any querying,
@@ -22,7 +21,7 @@ class FileDB extends __1.BaseCommonDB {
22
21
  this.cfg = {
23
22
  sortObjects: true,
24
23
  logFinished: true,
25
- logger: isGAE ? undefined : console,
24
+ logger: console,
26
25
  ...cfg,
27
26
  };
28
27
  }
@@ -19,8 +19,7 @@ export interface FileDBCfg {
19
19
  */
20
20
  sortObjects?: boolean;
21
21
  /**
22
- * Defaults to `console` in dev.
23
- * Default to noop in AppEngine.
22
+ * Defaults to `console`.
24
23
  */
25
24
  logger?: CommonLogger;
26
25
  /**
@@ -31,8 +31,7 @@ export interface InMemoryDBCfg {
31
31
  */
32
32
  persistZip: boolean;
33
33
  /**
34
- * Defaults to `console` in dev.
35
- * Default to noop in AppEngine.
34
+ * Defaults to `console`.
36
35
  */
37
36
  logger?: CommonLogger;
38
37
  }
@@ -8,7 +8,6 @@ const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
8
8
  const colors_1 = require("@naturalcycles/nodejs-lib/dist/colors");
9
9
  const fs = require("fs-extra");
10
10
  const __1 = require("../..");
11
- const isGAE = !!process.env['GAE_INSTANCE'];
12
11
  class InMemoryDB {
13
12
  constructor(cfg) {
14
13
  // data[table][id] > {id: 'a', created: ... }
@@ -19,7 +18,7 @@ class InMemoryDB {
19
18
  persistenceEnabled: false,
20
19
  persistZip: true,
21
20
  persistentStoragePath: './tmp/inmemorydb',
22
- logger: isGAE ? undefined : console,
21
+ logger: console,
23
22
  ...cfg,
24
23
  };
25
24
  }
@@ -1,4 +1,4 @@
1
- import { AsyncMapper, JsonSchemaObject, JsonSchemaRootObject, Saved, ObjectWithId } from '@naturalcycles/js-lib';
1
+ import { AsyncMapper, JsonSchemaObject, JsonSchemaRootObject, ObjectWithId, Saved } from '@naturalcycles/js-lib';
2
2
  import { AjvSchema, ObjectSchemaTyped, ReadableTyped } from '@naturalcycles/nodejs-lib';
3
3
  import { DBModelType, RunQueryResult } from '../db.model';
4
4
  import { DBQuery, RunnableDBQuery } from '../query/dbQuery';
@@ -137,7 +137,7 @@ export declare class CommonDao<BM extends Partial<ObjectWithId>, DBM extends Obj
137
137
  *
138
138
  * Does NOT mutate the object.
139
139
  */
140
- validateAndConvert<IN, OUT = IN>(obj: IN, schema?: ObjectSchemaTyped<IN> | AjvSchema<IN>, modelType?: DBModelType, opt?: CommonDaoOptions): OUT;
140
+ validateAndConvert<IN, OUT = IN>(obj: Partial<IN>, schema: ObjectSchemaTyped<IN> | AjvSchema<IN> | undefined, modelType: DBModelType, opt?: CommonDaoOptions): OUT;
141
141
  getTableSchema(): Promise<JsonSchemaRootObject<DBM>>;
142
142
  createTable(schema: JsonSchemaObject<DBM>, opt?: CommonDaoCreateOptions): Promise<void>;
143
143
  /**
@@ -9,6 +9,7 @@ const dbQuery_1 = require("../query/dbQuery");
9
9
  const common_dao_model_1 = require("./common.dao.model");
10
10
  /* eslint-disable no-dupe-class-members */
11
11
  const isGAE = !!process.env['GAE_INSTANCE'];
12
+ const isCI = !!process.env['CI'];
12
13
  /**
13
14
  * Lowest common denominator API between supported Databases.
14
15
  *
@@ -20,9 +21,12 @@ class CommonDao {
20
21
  constructor(cfg) {
21
22
  this.cfg = cfg;
22
23
  this.cfg = {
23
- logLevel: common_dao_model_1.CommonDaoLogLevel.OPERATIONS,
24
+ // Default is to NOT log in AppEngine and in CI,
25
+ // otherwise to log Operations
26
+ // e.g in Dev (local machine), Test - it will log operations (useful for debugging)
27
+ logLevel: isGAE || isCI ? common_dao_model_1.CommonDaoLogLevel.NONE : common_dao_model_1.CommonDaoLogLevel.OPERATIONS,
24
28
  createdUpdated: true,
25
- logger: isGAE ? undefined : console,
29
+ logger: console,
26
30
  ...cfg,
27
31
  hooks: {
28
32
  createId: () => (0, nodejs_lib_1.stringId)(),
@@ -52,7 +56,17 @@ class CommonDao {
52
56
  const op = `getById(${id})`;
53
57
  const table = opt.table || this.cfg.table;
54
58
  const started = this.logStarted(op, table);
55
- const [dbm] = await this.cfg.db.getByIds(table, [id]);
59
+ let dbm;
60
+ if (opt.timeout) {
61
+ // todo: possibly remove it after debugging is done
62
+ dbm = (await (0, js_lib_1.pTimeout)(this.cfg.db.getByIds(table, [id]), {
63
+ timeout: opt.timeout,
64
+ name: `getById(${table})`,
65
+ }))[0];
66
+ }
67
+ else {
68
+ dbm = (await this.cfg.db.getByIds(table, [id]))[0];
69
+ }
56
70
  const bm = opt.raw ? dbm : await this.dbmToBM(dbm, opt);
57
71
  this.logResult(started, op, bm, table);
58
72
  return bm || null;
@@ -733,8 +747,6 @@ class CommonDao {
733
747
  async ping() {
734
748
  await this.cfg.db.ping();
735
749
  }
736
- // todo: logging
737
- // todo: bmToDBM, etc. How?
738
750
  // transaction(): DBTransaction {
739
751
  // return this.cfg.db.transaction()
740
752
  // }
@@ -746,7 +758,7 @@ class CommonDao {
746
758
  if (Array.isArray(res)) {
747
759
  logRes = `${res.length} row(s)`;
748
760
  if (res.length && this.cfg.logLevel >= common_dao_model_1.CommonDaoLogLevel.DATA_FULL) {
749
- args.push('\n', res.slice(0, 10)); // max 10 items
761
+ args.push('\n', ...res.slice(0, 10)); // max 10 items
750
762
  }
751
763
  }
752
764
  else if (res) {
@@ -758,7 +770,7 @@ class CommonDao {
758
770
  else {
759
771
  logRes = `undefined`;
760
772
  }
761
- this.cfg.logger?.log(...[`<< ${table}.${op}: ${logRes} in ${(0, js_lib_1._since)(started)}`].concat(args));
773
+ this.cfg.logger?.log(`<< ${table}.${op}: ${logRes} in ${(0, js_lib_1._since)(started)}`, ...args);
762
774
  }
763
775
  logSaveResult(started, op, table) {
764
776
  if (!this.cfg.logLevel)
@@ -1,4 +1,4 @@
1
- import { CommonLogger, ErrorMode, ObjectWithId } from '@naturalcycles/js-lib';
1
+ import { CommonLogger, ErrorMode, ObjectWithId, Saved } from '@naturalcycles/js-lib';
2
2
  import { AjvSchema, AjvValidationError, JoiValidationError, ObjectSchemaTyped, TransformLogProgressOptions, TransformMapOptions } from '@naturalcycles/nodejs-lib';
3
3
  import { CommonDB } from '../common.db';
4
4
  import { CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions } from '../db.model';
@@ -34,11 +34,20 @@ export declare enum CommonDaoLogLevel {
34
34
  * Same as undefined
35
35
  */
36
36
  NONE = 0,
37
+ /**
38
+ * Log operations (e.g "getById returned 1 row"), but not data
39
+ */
37
40
  OPERATIONS = 10,
41
+ /**
42
+ * Log operations and data for single operations (e.g getById), but not batch operations.
43
+ */
38
44
  DATA_SINGLE = 20,
45
+ /**
46
+ * Log EVERYTHING - all data passing in and out (max 10 rows). Very verbose!
47
+ */
39
48
  DATA_FULL = 30
40
49
  }
41
- export interface CommonDaoCfg<BM extends Partial<ObjectWithId>, DBM extends ObjectWithId, TM> {
50
+ export interface CommonDaoCfg<BM extends Partial<ObjectWithId>, DBM extends ObjectWithId = Saved<BM>, TM = BM> {
42
51
  db: CommonDB;
43
52
  table: string;
44
53
  /**
@@ -54,10 +63,7 @@ export interface CommonDaoCfg<BM extends Partial<ObjectWithId>, DBM extends Obje
54
63
  */
55
64
  readOnly?: boolean;
56
65
  /**
57
- * Pass undefined (or noopLogger) to disable logging completely.
58
- *
59
- * Defaults to `console` in dev.
60
- * Default to noop in AppEngine.
66
+ * Defaults to `console`
61
67
  */
62
68
  logger?: CommonLogger;
63
69
  /**
@@ -129,6 +135,13 @@ export interface CommonDaoOptions extends CommonDBOptions {
129
135
  * Useful e.g in AirtableDB where you can have one Dao to control multiple tables.
130
136
  */
131
137
  table?: string;
138
+ /**
139
+ * If set - wraps the method in `pTimeout` with a timeout of given number of milliseconds.
140
+ * Currently, it is only used to debug an ongoing GCP infra issue.
141
+ *
142
+ * @experimental
143
+ */
144
+ timeout?: number;
132
145
  }
133
146
  /**
134
147
  * All properties default to undefined.
@@ -7,7 +7,16 @@ var CommonDaoLogLevel;
7
7
  * Same as undefined
8
8
  */
9
9
  CommonDaoLogLevel[CommonDaoLogLevel["NONE"] = 0] = "NONE";
10
+ /**
11
+ * Log operations (e.g "getById returned 1 row"), but not data
12
+ */
10
13
  CommonDaoLogLevel[CommonDaoLogLevel["OPERATIONS"] = 10] = "OPERATIONS";
14
+ /**
15
+ * Log operations and data for single operations (e.g getById), but not batch operations.
16
+ */
11
17
  CommonDaoLogLevel[CommonDaoLogLevel["DATA_SINGLE"] = 20] = "DATA_SINGLE";
18
+ /**
19
+ * Log EVERYTHING - all data passing in and out (max 10 rows). Very verbose!
20
+ */
12
21
  CommonDaoLogLevel[CommonDaoLogLevel["DATA_FULL"] = 30] = "DATA_FULL";
13
22
  })(CommonDaoLogLevel = exports.CommonDaoLogLevel || (exports.CommonDaoLogLevel = {}));
@@ -78,7 +78,7 @@ async function dbPipelineRestore(opt) {
78
78
  ...opt,
79
79
  metric: table,
80
80
  }),
81
- (0, nodejs_lib_1.transformLimit)(limit),
81
+ (0, nodejs_lib_1.transformLimit)({ limit }),
82
82
  ...(sinceUpdated
83
83
  ? [(0, nodejs_lib_1.transformFilterSync)(r => r.updated >= sinceUpdated)]
84
84
  : []),
package/package.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "devDependencies": {
13
13
  "@naturalcycles/bench-lib": "^1.0.0",
14
14
  "@naturalcycles/dev-lib": "^12.0.1",
15
- "@types/node": "^16.0.0",
15
+ "@types/node": "^17.0.0",
16
16
  "jest": "^27.0.3"
17
17
  },
18
18
  "files": [
@@ -42,7 +42,7 @@
42
42
  "engines": {
43
43
  "node": ">=14.15"
44
44
  },
45
- "version": "8.24.1",
45
+ "version": "8.25.0",
46
46
  "description": "Lowest Common Denominator API to supported Databases",
47
47
  "keywords": [
48
48
  "db",
@@ -40,10 +40,7 @@ export interface CacheDBCfg {
40
40
  logDownstream?: boolean
41
41
 
42
42
  /**
43
- * Pass noopLogger (or undefined) to skip logging completely.
44
- *
45
- * Defaults to `console` in dev.
46
- * Default to noop in AppEngine.
43
+ * Defaults to `console`.
47
44
  */
48
45
  logger?: CommonLogger
49
46
  }
@@ -16,8 +16,6 @@ import {
16
16
  CacheDBStreamOptions,
17
17
  } from './cache.db.model'
18
18
 
19
- const isGAE = !!process.env['GAE_INSTANCE']
20
-
21
19
  /**
22
20
  * CommonDB implementation that proxies requests to downstream CommonDB
23
21
  * and does in-memory caching.
@@ -28,7 +26,7 @@ export class CacheDB extends BaseCommonDB implements CommonDB {
28
26
  constructor(cfg: CacheDBCfg) {
29
27
  super()
30
28
  this.cfg = {
31
- logger: isGAE ? undefined : console,
29
+ logger: console,
32
30
  ...cfg,
33
31
  }
34
32
  }
@@ -24,8 +24,7 @@ export interface FileDBCfg {
24
24
  sortObjects?: boolean
25
25
 
26
26
  /**
27
- * Defaults to `console` in dev.
28
- * Default to noop in AppEngine.
27
+ * Defaults to `console`.
29
28
  */
30
29
  logger?: CommonLogger
31
30
 
@@ -28,8 +28,6 @@ import { DBQuery } from '../../query/dbQuery'
28
28
  import { DBTransaction } from '../../transaction/dbTransaction'
29
29
  import { FileDBCfg } from './file.db.model'
30
30
 
31
- const isGAE = !!process.env['GAE_INSTANCE']
32
-
33
31
  /**
34
32
  * Provides barebone implementation for "whole file" based CommonDB.
35
33
  * "whole file" means that the persistence layer doesn't allow any querying,
@@ -46,7 +44,7 @@ export class FileDB extends BaseCommonDB implements CommonDB {
46
44
  this.cfg = {
47
45
  sortObjects: true,
48
46
  logFinished: true,
49
- logger: isGAE ? undefined : console,
47
+ logger: console,
50
48
  ...cfg,
51
49
  }
52
50
  }
@@ -65,14 +65,11 @@ export interface InMemoryDBCfg {
65
65
  persistZip: boolean
66
66
 
67
67
  /**
68
- * Defaults to `console` in dev.
69
- * Default to noop in AppEngine.
68
+ * Defaults to `console`.
70
69
  */
71
70
  logger?: CommonLogger
72
71
  }
73
72
 
74
- const isGAE = !!process.env['GAE_INSTANCE']
75
-
76
73
  export class InMemoryDB implements CommonDB {
77
74
  constructor(cfg?: Partial<InMemoryDBCfg>) {
78
75
  this.cfg = {
@@ -81,7 +78,7 @@ export class InMemoryDB implements CommonDB {
81
78
  persistenceEnabled: false,
82
79
  persistZip: true,
83
80
  persistentStoragePath: './tmp/inmemorydb',
84
- logger: isGAE ? undefined : console,
81
+ logger: console,
85
82
  ...cfg,
86
83
  }
87
84
  }
@@ -1,4 +1,4 @@
1
- import { CommonLogger, ErrorMode, ObjectWithId } from '@naturalcycles/js-lib'
1
+ import { CommonLogger, ErrorMode, ObjectWithId, Saved } from '@naturalcycles/js-lib'
2
2
  import {
3
3
  AjvSchema,
4
4
  AjvValidationError,
@@ -46,12 +46,25 @@ export enum CommonDaoLogLevel {
46
46
  * Same as undefined
47
47
  */
48
48
  NONE = 0,
49
+ /**
50
+ * Log operations (e.g "getById returned 1 row"), but not data
51
+ */
49
52
  OPERATIONS = 10,
53
+ /**
54
+ * Log operations and data for single operations (e.g getById), but not batch operations.
55
+ */
50
56
  DATA_SINGLE = 20,
57
+ /**
58
+ * Log EVERYTHING - all data passing in and out (max 10 rows). Very verbose!
59
+ */
51
60
  DATA_FULL = 30,
52
61
  }
53
62
 
54
- export interface CommonDaoCfg<BM extends Partial<ObjectWithId>, DBM extends ObjectWithId, TM> {
63
+ export interface CommonDaoCfg<
64
+ BM extends Partial<ObjectWithId>,
65
+ DBM extends ObjectWithId = Saved<BM>,
66
+ TM = BM,
67
+ > {
55
68
  db: CommonDB
56
69
  table: string
57
70
 
@@ -71,10 +84,7 @@ export interface CommonDaoCfg<BM extends Partial<ObjectWithId>, DBM extends Obje
71
84
  readOnly?: boolean
72
85
 
73
86
  /**
74
- * Pass undefined (or noopLogger) to disable logging completely.
75
- *
76
- * Defaults to `console` in dev.
77
- * Default to noop in AppEngine.
87
+ * Defaults to `console`
78
88
  */
79
89
  logger?: CommonLogger
80
90
 
@@ -158,6 +168,14 @@ export interface CommonDaoOptions extends CommonDBOptions {
158
168
  * Useful e.g in AirtableDB where you can have one Dao to control multiple tables.
159
169
  */
160
170
  table?: string
171
+
172
+ /**
173
+ * If set - wraps the method in `pTimeout` with a timeout of given number of milliseconds.
174
+ * Currently, it is only used to debug an ongoing GCP infra issue.
175
+ *
176
+ * @experimental
177
+ */
178
+ timeout?: number
161
179
  }
162
180
 
163
181
  /**
@@ -1,20 +1,22 @@
1
1
  import {
2
+ _filterNullishValues,
3
+ _filterUndefinedValues,
4
+ _passthroughPredicate,
5
+ _since,
6
+ _truncate,
7
+ _uniqBy,
2
8
  AppError,
3
9
  AsyncMapper,
4
10
  ErrorMode,
5
11
  JsonSchemaObject,
6
- _passthroughPredicate,
7
- _since,
8
- _truncate,
9
- pMap,
10
12
  JsonSchemaRootObject,
11
- Saved,
12
- _uniqBy,
13
13
  ObjectWithId,
14
- _filterUndefinedValues,
15
- _filterNullishValues,
14
+ pMap,
15
+ pTimeout,
16
+ Saved,
16
17
  } from '@naturalcycles/js-lib'
17
18
  import {
19
+ _pipeline,
18
20
  AjvSchema,
19
21
  AjvValidationError,
20
22
  getValidationResult,
@@ -22,14 +24,13 @@ import {
22
24
  ObjectSchemaTyped,
23
25
  ReadableTyped,
24
26
  stringId,
27
+ transformBuffer,
25
28
  transformLogProgress,
26
29
  transformMap,
27
30
  transformMapSimple,
28
31
  transformMapSync,
29
32
  transformTap,
30
33
  writableVoid,
31
- _pipeline,
32
- transformBuffer,
33
34
  } from '@naturalcycles/nodejs-lib'
34
35
  import { DBLibError } from '../cnst'
35
36
  import { DBModelType, RunQueryResult } from '../db.model'
@@ -47,6 +48,7 @@ import {
47
48
  /* eslint-disable no-dupe-class-members */
48
49
 
49
50
  const isGAE = !!process.env['GAE_INSTANCE']
51
+ const isCI = !!process.env['CI']
50
52
 
51
53
  /**
52
54
  * Lowest common denominator API between supported Databases.
@@ -62,9 +64,12 @@ export class CommonDao<
62
64
  > {
63
65
  constructor(public cfg: CommonDaoCfg<BM, DBM, TM>) {
64
66
  this.cfg = {
65
- logLevel: CommonDaoLogLevel.OPERATIONS,
67
+ // Default is to NOT log in AppEngine and in CI,
68
+ // otherwise to log Operations
69
+ // e.g in Dev (local machine), Test - it will log operations (useful for debugging)
70
+ logLevel: isGAE || isCI ? CommonDaoLogLevel.NONE : CommonDaoLogLevel.OPERATIONS,
66
71
  createdUpdated: true,
67
- logger: isGAE ? undefined : console,
72
+ logger: console,
68
73
  ...cfg,
69
74
  hooks: {
70
75
  createId: () => stringId(),
@@ -99,7 +104,21 @@ export class CommonDao<
99
104
  const op = `getById(${id})`
100
105
  const table = opt.table || this.cfg.table
101
106
  const started = this.logStarted(op, table)
102
- const [dbm] = await this.cfg.db.getByIds<DBM>(table, [id])
107
+
108
+ let dbm: DBM | undefined
109
+
110
+ if (opt.timeout) {
111
+ // todo: possibly remove it after debugging is done
112
+ dbm = (
113
+ await pTimeout(this.cfg.db.getByIds<DBM>(table, [id]), {
114
+ timeout: opt.timeout,
115
+ name: `getById(${table})`,
116
+ })
117
+ )[0]
118
+ } else {
119
+ dbm = (await this.cfg.db.getByIds<DBM>(table, [id]))[0]
120
+ }
121
+
103
122
  const bm = opt.raw ? (dbm as any) : await this.dbmToBM(dbm, opt)
104
123
  this.logResult(started, op, bm, table)
105
124
  return bm || null
@@ -899,9 +918,9 @@ export class CommonDao<
899
918
  * Does NOT mutate the object.
900
919
  */
901
920
  validateAndConvert<IN, OUT = IN>(
902
- obj: IN,
903
- schema?: ObjectSchemaTyped<IN> | AjvSchema<IN>,
904
- modelType?: DBModelType,
921
+ obj: Partial<IN>,
922
+ schema: ObjectSchemaTyped<IN> | AjvSchema<IN> | undefined,
923
+ modelType: DBModelType,
905
924
  opt: CommonDaoOptions = {},
906
925
  ): OUT {
907
926
  // `raw` option completely bypasses any processing
@@ -924,12 +943,12 @@ export class CommonDao<
924
943
 
925
944
  // Pre-validation hooks
926
945
  if (modelType === DBModelType.DBM) {
927
- obj = this.cfg.hooks!.beforeDBMValidate!(obj as any) as any
946
+ obj = this.cfg.hooks!.beforeDBMValidate!(obj as any) as IN
928
947
  }
929
948
 
930
949
  // Return as is if no schema is passed or if `skipConversion` is set
931
950
  if (!schema || opt.skipConversion) {
932
- return obj as any
951
+ return obj as OUT
933
952
  }
934
953
 
935
954
  // This will Convert and Validate
@@ -943,12 +962,12 @@ export class CommonDao<
943
962
  // Ajv schema
944
963
  convertedValue = obj // because Ajv mutates original object
945
964
 
946
- error = schema.getValidationError(obj, {
965
+ error = schema.getValidationError(obj as IN, {
947
966
  objectName,
948
967
  })
949
968
  } else {
950
969
  // Joi
951
- const vr = getValidationResult<IN, OUT>(obj, schema, objectName)
970
+ const vr = getValidationResult<IN, OUT>(obj as IN, schema, objectName)
952
971
  error = vr.error
953
972
  convertedValue = vr.value
954
973
  }
@@ -979,8 +998,6 @@ export class CommonDao<
979
998
  await this.cfg.db.ping()
980
999
  }
981
1000
 
982
- // todo: logging
983
- // todo: bmToDBM, etc. How?
984
1001
  // transaction(): DBTransaction {
985
1002
  // return this.cfg.db.transaction()
986
1003
  // }
@@ -994,7 +1011,7 @@ export class CommonDao<
994
1011
  if (Array.isArray(res)) {
995
1012
  logRes = `${res.length} row(s)`
996
1013
  if (res.length && this.cfg.logLevel >= CommonDaoLogLevel.DATA_FULL) {
997
- args.push('\n', res.slice(0, 10)) // max 10 items
1014
+ args.push('\n', ...res.slice(0, 10)) // max 10 items
998
1015
  }
999
1016
  } else if (res) {
1000
1017
  logRes = `1 row`
@@ -1005,7 +1022,7 @@ export class CommonDao<
1005
1022
  logRes = `undefined`
1006
1023
  }
1007
1024
 
1008
- this.cfg.logger?.log(...[`<< ${table}.${op}: ${logRes} in ${_since(started)}`].concat(args))
1025
+ this.cfg.logger?.log(`<< ${table}.${op}: ${logRes} in ${_since(started)}`, ...args)
1009
1026
  }
1010
1027
 
1011
1028
  protected logSaveResult(started: number, op: string, table: string): void {
@@ -209,7 +209,7 @@ export async function dbPipelineRestore(opt: DBPipelineRestoreOptions): Promise<
209
209
  ...opt,
210
210
  metric: table,
211
211
  }),
212
- transformLimit(limit),
212
+ transformLimit({ limit }),
213
213
  ...(sinceUpdated
214
214
  ? [transformFilterSync<SavedDBEntity>(r => r.updated >= sinceUpdated)]
215
215
  : []),