@nmakarov/cli-toolkit 0.39.0 → 0.43.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.
@@ -3279,6 +3279,41 @@ var Db = class _Db {
3279
3279
  }
3280
3280
  return stack.pop();
3281
3281
  };
3282
+ const isTimeoutError = (error) => error?.name === "KnexTimeoutError" || /query timeout|timeout exceeded/i.test(String(error?.message ?? ""));
3283
+ const logQueryEntry = (query, start, { error } = {}) => {
3284
+ let executionTimeMs;
3285
+ if (start) {
3286
+ const [seconds, nanoseconds] = process.hrtime(start);
3287
+ executionTimeMs = (seconds * 1e3 + nanoseconds / 1e6).toFixed(2);
3288
+ } else if (error?.timeout != null) {
3289
+ executionTimeMs = Number(error.timeout).toFixed(2);
3290
+ } else {
3291
+ executionTimeMs = "?";
3292
+ }
3293
+ let status = "ok";
3294
+ if (error) {
3295
+ status = isTimeoutError(error) ? "timeout" : "error";
3296
+ }
3297
+ const logEntry = {
3298
+ sql: query?.sql,
3299
+ bindings: query?.bindings || [],
3300
+ executionTimeMs,
3301
+ status
3302
+ };
3303
+ if (error) {
3304
+ logEntry.error = error.message ?? String(error);
3305
+ }
3306
+ this.queriesLog.push(logEntry);
3307
+ const suffix = error ? ` | ${status}: ${logEntry.error}` : "";
3308
+ this.logger.debug?.(
3309
+ `[Db] Query: ${query?.sql} | Duration: ${executionTimeMs}ms${suffix}`
3310
+ );
3311
+ };
3312
+ const handleQueryError = (error, query) => {
3313
+ const start = popStart(query);
3314
+ logQueryEntry(query, start, { error });
3315
+ this.logger.error?.(`[Db] Query failed: ${query?.sql}`, error);
3316
+ };
3282
3317
  this.knexInstance.on("query", (query) => {
3283
3318
  pushStart(query);
3284
3319
  });
@@ -3287,20 +3322,31 @@ var Db = class _Db {
3287
3322
  if (!start) {
3288
3323
  return;
3289
3324
  }
3290
- const [seconds, nanoseconds] = process.hrtime(start);
3291
- const executionTimeMs = (seconds * 1e3 + nanoseconds / 1e6).toFixed(2);
3292
- const logEntry = {
3293
- sql: query.sql,
3294
- bindings: query.bindings || [],
3295
- executionTimeMs
3296
- };
3297
- this.queriesLog.push(logEntry);
3298
- this.logger.debug?.(`[Db] Query: ${query.sql} | Duration: ${executionTimeMs}ms`);
3325
+ logQueryEntry(query, start);
3299
3326
  });
3300
3327
  this.knexInstance.on("query-error", (error, query) => {
3301
- popStart(query);
3302
- this.logger.error?.(`[Db] Query failed: ${query.sql}`, error);
3328
+ handleQueryError(error, query);
3303
3329
  });
3330
+ const hookBuilder = (builder) => {
3331
+ if (!builder || builder.__dbProfilerHooked) {
3332
+ return;
3333
+ }
3334
+ builder.__dbProfilerHooked = true;
3335
+ builder.on("query", pushStart);
3336
+ builder.on("query-error", handleQueryError);
3337
+ };
3338
+ const client = this.knexInstance.client;
3339
+ if (client && !client.__dbProfilerPatched) {
3340
+ client.__dbProfilerPatched = true;
3341
+ if (typeof client.queryBuilder === "function") {
3342
+ const origQueryBuilder = client.queryBuilder.bind(client);
3343
+ client.queryBuilder = (...args) => {
3344
+ const builder = origQueryBuilder(...args);
3345
+ hookBuilder(builder);
3346
+ return builder;
3347
+ };
3348
+ }
3349
+ }
3304
3350
  }
3305
3351
  getQueryLog() {
3306
3352
  return [...this.queriesLog];
@@ -4036,6 +4082,9 @@ var FileDatabase = class _FileDatabase {
4036
4082
  currentRecord = 0;
4037
4083
  hasReadFirstPage = false;
4038
4084
  lastFileData = null;
4085
+ /** Cache of the last JSON file parsed during paginated reads (avoid re-parse per page). */
4086
+ readFileCache = null;
4087
+ // { filePath: string, data: any[] } | null
4039
4088
  metadata;
4040
4089
  // Synopsis calculation functions
4041
4090
  fileSynopsisFunction = null;
@@ -4802,7 +4851,6 @@ var FileDatabase = class _FileDatabase {
4802
4851
  let effectivePageSize;
4803
4852
  if (nextPage && this.hasReadFirstPage) {
4804
4853
  effectivePageSize = pageSize || this.pageSize;
4805
- this.currentRecord += effectivePageSize;
4806
4854
  } else if (!nextPage) {
4807
4855
  effectivePageSize = pageSize !== void 0 ? pageSize : this.metadata.totalRecords;
4808
4856
  this.currentRecord = 0;
@@ -4831,8 +4879,14 @@ var FileDatabase = class _FileDatabase {
4831
4879
  const file = this.metadata.files[i];
4832
4880
  const filePath = import_path4.default.join(this.getDestinationPath(this.currentVersion || void 0), file.fileName);
4833
4881
  try {
4834
- const rawData = await import_fs4.default.promises.readFile(filePath, "utf8");
4835
- const fileData = deserializeData(rawData, this.metadata.dataType);
4882
+ let fileData;
4883
+ if (this.readFileCache?.filePath === filePath && Array.isArray(this.readFileCache.data)) {
4884
+ fileData = this.readFileCache.data;
4885
+ } else {
4886
+ const rawData = await import_fs4.default.promises.readFile(filePath, "utf8");
4887
+ fileData = deserializeData(rawData, this.metadata.dataType);
4888
+ this.readFileCache = { filePath, data: fileData };
4889
+ }
4836
4890
  let startIndex = 0;
4837
4891
  if (i === currentFileIndex) {
4838
4892
  startIndex = this.currentRecord - cumulativeRecords;
@@ -4846,6 +4900,7 @@ var FileDatabase = class _FileDatabase {
4846
4900
  throw new FileDatabaseError(`Failed to read file ${file.fileName}: ${error.message}`);
4847
4901
  }
4848
4902
  }
4903
+ this.currentRecord += recordsRead;
4849
4904
  if (result.length > 0) {
4850
4905
  if (nextPage || pageSize !== void 0 && pageSize < this.metadata.totalRecords) {
4851
4906
  this.hasReadFirstPage = true;
@@ -4859,6 +4914,7 @@ var FileDatabase = class _FileDatabase {
4859
4914
  setStartRecord(startRecord) {
4860
4915
  this.currentRecord = startRecord - 1;
4861
4916
  this.hasReadFirstPage = false;
4917
+ this.readFileCache = null;
4862
4918
  }
4863
4919
  /**
4864
4920
  * Reset read pagination state
@@ -4866,6 +4922,7 @@ var FileDatabase = class _FileDatabase {
4866
4922
  resetPagination() {
4867
4923
  this.currentRecord = 0;
4868
4924
  this.hasReadFirstPage = false;
4925
+ this.readFileCache = null;
4869
4926
  }
4870
4927
  /**
4871
4928
  * List filenames in the table directory.