forge-sql-orm 2.1.5 → 2.1.7

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.
Files changed (41) hide show
  1. package/README.md +135 -53
  2. package/dist/ForgeSQLORM.js +572 -231
  3. package/dist/ForgeSQLORM.js.map +1 -1
  4. package/dist/ForgeSQLORM.mjs +572 -231
  5. package/dist/ForgeSQLORM.mjs.map +1 -1
  6. package/dist/core/ForgeSQLORM.d.ts +91 -3
  7. package/dist/core/ForgeSQLORM.d.ts.map +1 -1
  8. package/dist/core/ForgeSQLQueryBuilder.d.ts +89 -2
  9. package/dist/core/ForgeSQLQueryBuilder.d.ts.map +1 -1
  10. package/dist/core/SystemTables.d.ts +3654 -0
  11. package/dist/core/SystemTables.d.ts.map +1 -1
  12. package/dist/lib/drizzle/extensions/additionalActions.d.ts +2 -2
  13. package/dist/lib/drizzle/extensions/additionalActions.d.ts.map +1 -1
  14. package/dist/utils/forgeDriver.d.ts +61 -14
  15. package/dist/utils/forgeDriver.d.ts.map +1 -1
  16. package/dist/utils/metadataContextUtils.d.ts +1 -1
  17. package/dist/utils/metadataContextUtils.d.ts.map +1 -1
  18. package/dist/utils/requestTypeContextUtils.d.ts +8 -0
  19. package/dist/utils/requestTypeContextUtils.d.ts.map +1 -0
  20. package/dist/webtriggers/topSlowestStatementLastHourTrigger.d.ts +90 -65
  21. package/dist/webtriggers/topSlowestStatementLastHourTrigger.d.ts.map +1 -1
  22. package/package.json +9 -9
  23. package/src/core/ForgeSQLCrudOperations.ts +3 -3
  24. package/src/core/ForgeSQLORM.ts +334 -124
  25. package/src/core/ForgeSQLQueryBuilder.ts +116 -20
  26. package/src/core/ForgeSQLSelectOperations.ts +2 -2
  27. package/src/core/SystemTables.ts +16 -0
  28. package/src/lib/drizzle/extensions/additionalActions.ts +24 -22
  29. package/src/utils/cacheContextUtils.ts +2 -2
  30. package/src/utils/cacheUtils.ts +12 -12
  31. package/src/utils/forgeDriver.ts +219 -40
  32. package/src/utils/forgeDriverProxy.ts +2 -2
  33. package/src/utils/metadataContextUtils.ts +11 -13
  34. package/src/utils/requestTypeContextUtils.ts +11 -0
  35. package/src/utils/sqlUtils.ts +1 -1
  36. package/src/webtriggers/applyMigrationsWebTrigger.ts +9 -9
  37. package/src/webtriggers/clearCacheSchedulerTrigger.ts +1 -1
  38. package/src/webtriggers/dropMigrationWebTrigger.ts +2 -2
  39. package/src/webtriggers/dropTablesMigrationWebTrigger.ts +2 -2
  40. package/src/webtriggers/fetchSchemaWebTrigger.ts +1 -1
  41. package/src/webtriggers/topSlowestStatementLastHourTrigger.ts +511 -308
@@ -26,19 +26,20 @@ import {
26
26
  } from "./SystemTables";
27
27
  import { ForgeSQLCacheOperations } from "./ForgeSQLCacheOperations";
28
28
  import {
29
- DeleteAndEvictCacheType,
30
- ExecuteQuery,
31
- ExecuteQueryCacheable, ForgeSQLMetadata,
32
- InsertAndEvictCacheType,
33
- SelectAliasedCacheableType,
34
- SelectAliasedDistinctCacheableType,
35
- SelectAliasedDistinctType,
36
- SelectAliasedType,
37
- SelectAllDistinctFromAliasedType,
38
- SelectAllDistinctFromCacheableAliasedType,
39
- SelectAllFromAliasedType,
40
- SelectAllFromCacheableAliasedType,
41
- UpdateAndEvictCacheType,
29
+ DeleteAndEvictCacheType,
30
+ ExecuteQuery,
31
+ ExecuteQueryCacheable,
32
+ ForgeSQLMetadata,
33
+ InsertAndEvictCacheType,
34
+ SelectAliasedCacheableType,
35
+ SelectAliasedDistinctCacheableType,
36
+ SelectAliasedDistinctType,
37
+ SelectAliasedType,
38
+ SelectAllDistinctFromAliasedType,
39
+ SelectAllDistinctFromCacheableAliasedType,
40
+ SelectAllFromAliasedType,
41
+ SelectAllFromCacheableAliasedType,
42
+ UpdateAndEvictCacheType,
42
43
  } from "..";
43
44
  import {
44
45
  MySqlDeleteBase,
@@ -519,8 +520,12 @@ export interface QueryBuilderForgeSql {
519
520
  * ```
520
521
  */
521
522
  executeWithMetadata<T>(
522
- query: () => Promise<T>,
523
- onMetadata: (totalDbExecutionTime: number, totalResponseSize: number, forgeMetadata: ForgeSQLMetadata) => Promise<void> | void
523
+ query: () => Promise<T>,
524
+ onMetadata: (
525
+ totalDbExecutionTime: number,
526
+ totalResponseSize: number,
527
+ forgeMetadata: ForgeSQLMetadata,
528
+ ) => Promise<void> | void,
524
529
  ): Promise<T>;
525
530
  /**
526
531
  * Executes a raw SQL query with local cache support.
@@ -538,9 +543,100 @@ export interface QueryBuilderForgeSql {
538
543
  * const result = await forgeSQL.execute("SELECT * FROM users WHERE status = 'active'");
539
544
  * ```
540
545
  */
541
- execute(
546
+ execute<T>(
542
547
  query: SQLWrapper | string,
543
- ): Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, unknown>>;
548
+ ): Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, T>>;
549
+
550
+ /**
551
+ * Executes a Data Definition Language (DDL) SQL query.
552
+ * DDL operations include CREATE, ALTER, DROP, TRUNCATE, and other schema modification statements.
553
+ *
554
+ * This method is specifically designed for DDL operations and provides:
555
+ * - Proper operation type context for DDL queries
556
+ * - No caching (DDL operations should not be cached)
557
+ * - Direct execution without query optimization
558
+ *
559
+ * @template T - The expected return type of the query result
560
+ * @param query - The DDL SQL query to execute (SQLWrapper or string)
561
+ * @returns Promise with query results
562
+ * @throws {Error} If the DDL operation fails
563
+ *
564
+ * @example
565
+ * ```typescript
566
+ * // Create a new table
567
+ * await forgeSQL.executeDDL(`
568
+ * CREATE TABLE users (
569
+ * id INT PRIMARY KEY AUTO_INCREMENT,
570
+ * name VARCHAR(255) NOT NULL,
571
+ * email VARCHAR(255) UNIQUE
572
+ * )
573
+ * `);
574
+ *
575
+ * // Alter table structure
576
+ * await forgeSQL.executeDDL(sql`
577
+ * ALTER TABLE users
578
+ * ADD COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
579
+ * `);
580
+ *
581
+ * // Drop a table
582
+ * await forgeSQL.executeDDL("DROP TABLE IF EXISTS old_users");
583
+ * ```
584
+ */
585
+ executeDDL<T>(
586
+ query: SQLWrapper | string,
587
+ ): Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, T>>;
588
+
589
+ /**
590
+ * Executes a series of actions within a DDL operation context.
591
+ * This method provides a way to execute regular SQL queries that should be treated
592
+ * as DDL operations, ensuring proper operation type context for performance monitoring.
593
+ *
594
+ * This method is useful for:
595
+ * - Executing regular SQL queries in DDL context for monitoring purposes
596
+ * - Wrapping non-DDL operations that should be treated as DDL for analysis
597
+ * - Ensuring proper operation type context for complex workflows
598
+ * - Maintaining DDL operation context across multiple function calls
599
+ *
600
+ * @template T - The return type of the actions function
601
+ * @param actions - Function containing SQL operations to execute in DDL context
602
+ * @returns Promise that resolves to the return value of the actions function
603
+ *
604
+ * @example
605
+ * ```typescript
606
+ * // Execute regular SQL queries in DDL context for monitoring
607
+ * await forgeSQL.executeDDLActions(async () => {
608
+ * const slowQueries = await forgeSQL.execute(`
609
+ * SELECT * FROM INFORMATION_SCHEMA.STATEMENTS_SUMMARY
610
+ * WHERE AVG_LATENCY > 1000000
611
+ * `);
612
+ * return slowQueries;
613
+ * });
614
+ *
615
+ * // Execute complex analysis queries in DDL context
616
+ * const result = await forgeSQL.executeDDLActions(async () => {
617
+ * const tableInfo = await forgeSQL.execute("SHOW TABLES");
618
+ * const performanceData = await forgeSQL.execute(`
619
+ * SELECT * FROM INFORMATION_SCHEMA.CLUSTER_STATEMENTS_SUMMARY_HISTORY
620
+ * WHERE SUMMARY_END_TIME > DATE_SUB(NOW(), INTERVAL 1 HOUR)
621
+ * `);
622
+ * return { tableInfo, performanceData };
623
+ * });
624
+ *
625
+ * // Execute monitoring queries with error handling
626
+ * try {
627
+ * await forgeSQL.executeDDLActions(async () => {
628
+ * const metrics = await forgeSQL.execute(`
629
+ * SELECT COUNT(*) as query_count
630
+ * FROM INFORMATION_SCHEMA.STATEMENTS_SUMMARY
631
+ * `);
632
+ * console.log(`Total queries: ${metrics[0].query_count}`);
633
+ * });
634
+ * } catch (error) {
635
+ * console.error("Monitoring query failed:", error);
636
+ * }
637
+ * ```
638
+ */
639
+ executeDDLActions<T>(actions: () => Promise<T>): Promise<T>;
544
640
 
545
641
  /**
546
642
  * Executes a raw SQL query with both local and global cache support.
@@ -560,10 +656,10 @@ export interface QueryBuilderForgeSql {
560
656
  * const result = await forgeSQL.executeCacheable("SELECT * FROM users WHERE status = 'active'");
561
657
  * ```
562
658
  */
563
- executeCacheable(
659
+ executeCacheable<T>(
564
660
  query: SQLWrapper | string,
565
661
  cacheTtl?: number,
566
- ): Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, unknown>>;
662
+ ): Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, T>>;
567
663
  /**
568
664
  * Creates a Common Table Expression (CTE) builder for complex queries.
569
665
  * CTEs allow you to define temporary named result sets that exist within the scope of a single query.
@@ -865,7 +961,7 @@ export interface ForgeSqlOrmOptions {
865
961
  /**
866
962
  * Additional metadata for table configuration.
867
963
  * Allows specifying table-specific settings and behaviors such as version fields for optimistic locking.
868
- *
964
+ *
869
965
  * @example
870
966
  * ```typescript
871
967
  * {
@@ -58,7 +58,7 @@ export class ForgeSQLSelectOperations implements SchemaSqlForgeSql {
58
58
  async executeRawSQL<T extends object | unknown>(query: string, params?: unknown[]): Promise<T[]> {
59
59
  if (this.options.logRawSqlQuery) {
60
60
  const paramsStr = params ? `, with params: ${JSON.stringify(params)}` : "";
61
- // eslint-disable-next-line no-console
61
+ // eslint-disable-next-line no-console
62
62
  console.debug(`Executing with SQL ${query}${paramsStr}`);
63
63
  }
64
64
  const sqlStatement = sql.prepare<T>(query);
@@ -81,7 +81,7 @@ export class ForgeSQLSelectOperations implements SchemaSqlForgeSql {
81
81
  sqlStatement.bindParams(...params);
82
82
  }
83
83
  if (this.options.logRawSqlQuery) {
84
- // eslint-disable-next-line no-console
84
+ // eslint-disable-next-line no-console
85
85
  console.debug(
86
86
  `Executing Update with SQL ${query}` +
87
87
  (params ? `, with params: ${JSON.stringify(params)}` : ""),
@@ -312,6 +312,22 @@ export const clusterStatementsSummaryHistory = informationSchema.table(
312
312
  // Types
313
313
  export type ClusterStatementsSummaryHistory = typeof clusterStatementsSummaryHistory.$inferSelect;
314
314
 
315
+ export const statementsSummaryHistory = informationSchema.table(
316
+ "STATEMENTS_SUMMARY_HISTORY",
317
+ createClusterStatementsSummarySchema(),
318
+ );
319
+
320
+ // Types
321
+ export type StatementsSummaryHistory = typeof statementsSummaryHistory.$inferSelect;
322
+
323
+ export const statementsSummary = informationSchema.table(
324
+ "STATEMENTS_SUMMARY",
325
+ createClusterStatementsSummarySchema(),
326
+ );
327
+
328
+ // Types
329
+ export type StatementsSummary = typeof statementsSummary.$inferSelect;
330
+
315
331
  export const clusterStatementsSummary = informationSchema.table(
316
332
  "CLUSTER_STATEMENTS_SUMMARY",
317
333
  createClusterStatementsSummarySchema(),
@@ -22,9 +22,9 @@ import {
22
22
  saveQueryLocalCacheQuery,
23
23
  saveTableIfInsideCacheContext,
24
24
  } from "../../../utils/cacheContextUtils";
25
- import { BuildQueryConfig, isSQLWrapper, SQLWrapper } from "drizzle-orm/sql/sql";
25
+ import { isSQLWrapper, SQLWrapper } from "drizzle-orm/sql/sql";
26
26
  import type { MySqlQueryResultKind } from "drizzle-orm/mysql-core/session";
27
- import { getTableColumns, Query } from "drizzle-orm";
27
+ import { getTableColumns, Query, SQL } from "drizzle-orm";
28
28
  import { MySqlDialect } from "drizzle-orm/mysql-core/dialect";
29
29
  import type {
30
30
  GetSelectTableName,
@@ -204,17 +204,17 @@ export type SelectAllDistinctFromCacheableAliasedType = <T extends MySqlTable>(
204
204
  /**
205
205
  * Type for executing raw SQL queries with local cache
206
206
  */
207
- export type ExecuteQuery = (
207
+ export type ExecuteQuery = <T>(
208
208
  query: SQLWrapper | string,
209
- ) => Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, unknown>>;
209
+ ) => Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, T>>;
210
210
 
211
211
  /**
212
212
  * Type for executing raw SQL queries with local and global cache
213
213
  */
214
- export type ExecuteQueryCacheable = (
214
+ export type ExecuteQueryCacheable = <T>(
215
215
  query: SQLWrapper | string,
216
216
  cacheTtl?: number,
217
- ) => Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, unknown>>;
217
+ ) => Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, T>>;
218
218
 
219
219
  /**
220
220
  * Type for insert operations with cache eviction
@@ -260,7 +260,7 @@ async function handleSuccessfulExecution(
260
260
  if (isCached && !cacheApplicationContext.getStore()) {
261
261
  await clearCache(table, options);
262
262
  }
263
- const result = onfulfilled?.(rows);
263
+ const result = onfulfilled ? onfulfilled(rows) : rows;
264
264
  return result;
265
265
  } catch (error) {
266
266
  // Only clear cache for certain types of errors
@@ -268,7 +268,7 @@ async function handleSuccessfulExecution(
268
268
  await evictLocalCacheQuery(table, options);
269
269
  if (isCached) {
270
270
  await clearCache(table, options).catch((e) => {
271
- // eslint-disable-next-line no-console
271
+ // eslint-disable-next-line no-console
272
272
  console.warn("Ignore cache clear errors", e);
273
273
  });
274
274
  } else {
@@ -447,24 +447,27 @@ async function handleCachedQuery(
447
447
  try {
448
448
  const localCached = await getQueryLocalCacheQuery(target, options);
449
449
  if (localCached) {
450
- return onfulfilled?.(localCached);
450
+ return onfulfilled ? onfulfilled(localCached) : localCached;
451
451
  }
452
452
  const cacheResult = await getFromCache(target, options);
453
453
  if (cacheResult) {
454
- return onfulfilled?.(cacheResult);
454
+ return onfulfilled ? onfulfilled(cacheResult) : cacheResult;
455
455
  }
456
456
  const rows = await target.execute();
457
457
  const transformed = applyFromDriverTransform(rows, selections, aliasMap);
458
458
  await saveQueryLocalCacheQuery(target, transformed, options);
459
459
  await setCacheResult(target, options, transformed, cacheTtl).catch((cacheError) => {
460
460
  // Log cache error but don't fail the query
461
- // eslint-disable-next-line no-console
461
+ // eslint-disable-next-line no-console
462
462
  console.warn("Cache set error:", cacheError);
463
463
  });
464
464
 
465
- return onfulfilled?.(transformed);
465
+ return onfulfilled ? onfulfilled(transformed) : transformed;
466
466
  } catch (error) {
467
- return onrejected?.(error);
467
+ if (onrejected) {
468
+ return onrejected(error);
469
+ }
470
+ throw error;
468
471
  }
469
472
  }
470
473
 
@@ -490,14 +493,17 @@ async function handleNonCachedQuery(
490
493
  try {
491
494
  const localCached = await getQueryLocalCacheQuery(target, options);
492
495
  if (localCached) {
493
- return onfulfilled?.(localCached);
496
+ return onfulfilled ? onfulfilled(localCached) : localCached;
494
497
  }
495
498
  const rows = await target.execute();
496
499
  const transformed = applyFromDriverTransform(rows, selections, aliasMap);
497
500
  await saveQueryLocalCacheQuery(target, transformed, options);
498
- return onfulfilled?.(transformed);
501
+ return onfulfilled ? onfulfilled(transformed) : transformed;
499
502
  } catch (error) {
500
- return onrejected?.(error);
503
+ if (onrejected) {
504
+ return onrejected(error);
505
+ }
506
+ throw error;
501
507
  }
502
508
  }
503
509
 
@@ -617,12 +623,8 @@ function createRawQueryExecutor(
617
623
  let sql: Query;
618
624
 
619
625
  if (isSQLWrapper(query)) {
620
- const sqlWrapper = query as SQLWrapper;
621
- sql = sqlWrapper
622
- .getSQL()
623
- .toQuery(
624
- (db as unknown as { dialect: MySqlDialect }).dialect as unknown as BuildQueryConfig,
625
- );
626
+ const dialect = (db as unknown as { dialect: MySqlDialect }).dialect;
627
+ sql = dialect.sqlToQuery(query as SQL);
626
628
  } else {
627
629
  sql = {
628
630
  sql: query,
@@ -104,7 +104,7 @@ export async function saveQueryLocalCacheQuery<
104
104
  };
105
105
  if (options.logCache) {
106
106
  const q = sql.toSQL();
107
- // eslint-disable-next-line no-console
107
+ // eslint-disable-next-line no-console
108
108
  console.debug(
109
109
  `[forge-sql-orm][local-cache][SAVE] Stored result in cache. sql="${q.sql}", params=${JSON.stringify(q.params)}`,
110
110
  );
@@ -143,7 +143,7 @@ export async function getQueryLocalCacheQuery<
143
143
  if (context.cache[key] && context.cache[key].sql === sql.toSQL().sql.toLowerCase()) {
144
144
  if (options.logCache) {
145
145
  const q = sql.toSQL();
146
- // eslint-disable-next-line no-console
146
+ // eslint-disable-next-line no-console
147
147
  console.debug(
148
148
  `[forge-sql-orm][local-cache][HIT] Returned cached result. sql="${q.sql}", params=${JSON.stringify(q.params)}`,
149
149
  );
@@ -124,7 +124,7 @@ async function clearCursorCache(
124
124
  const listResult = await entityQueryBuilder.limit(100).getMany();
125
125
 
126
126
  if (options.logCache) {
127
- // eslint-disable-next-line no-console
127
+ // eslint-disable-next-line no-console
128
128
  console.warn(`clear cache Records: ${JSON.stringify(listResult.results.map((r) => r.key))}`);
129
129
  }
130
130
 
@@ -172,7 +172,7 @@ async function clearExpirationCursorCache(
172
172
  const listResult = await entityQueryBuilder.limit(100).getMany();
173
173
 
174
174
  if (options.logCache) {
175
- // eslint-disable-next-line no-console
175
+ // eslint-disable-next-line no-console
176
176
  console.warn(`clear expired Records: ${JSON.stringify(listResult.results.map((r) => r.key))}`);
177
177
  }
178
178
 
@@ -203,12 +203,12 @@ async function executeWithRetry<T>(operation: () => Promise<T>, operationName: s
203
203
  try {
204
204
  return await operation();
205
205
  } catch (err: any) {
206
- // eslint-disable-next-line no-console
206
+ // eslint-disable-next-line no-console
207
207
  console.warn(`Error during ${operationName}: ${err.message}, retry ${attempt}`, err);
208
208
  attempt++;
209
209
 
210
210
  if (attempt >= CACHE_CONSTANTS.MAX_RETRY_ATTEMPTS) {
211
- // eslint-disable-next-line no-console
211
+ // eslint-disable-next-line no-console
212
212
  console.error(`Error during ${operationName}: ${err.message}`, err);
213
213
  throw err;
214
214
  }
@@ -266,7 +266,7 @@ export async function clearTablesCache(
266
266
  } finally {
267
267
  if (options.logCache) {
268
268
  const duration = DateTime.now().toSeconds() - startTime.toSeconds();
269
- // eslint-disable-next-line no-console
269
+ // eslint-disable-next-line no-console
270
270
  console.info(`Cleared ${totalRecords} cache records in ${duration} seconds`);
271
271
  }
272
272
  }
@@ -293,7 +293,7 @@ export async function clearExpiredCache(options: ForgeSqlOrmOptions): Promise<vo
293
293
  } finally {
294
294
  const duration = DateTime.now().toSeconds() - startTime.toSeconds();
295
295
  if (options?.logCache) {
296
- // eslint-disable-next-line no-console
296
+ // eslint-disable-next-line no-console
297
297
  console.debug(`Cleared ${totalRecords} expired cache records in ${duration} seconds`);
298
298
  }
299
299
  }
@@ -325,7 +325,7 @@ export async function getFromCache<T>(
325
325
  // Skip cache if table is in cache context (will be cleared)
326
326
  if (await isTableContainsTableInCacheContext(sqlQuery.sql, options)) {
327
327
  if (options.logCache) {
328
- // eslint-disable-next-line no-console
328
+ // eslint-disable-next-line no-console
329
329
  console.warn(`Context contains value to clear. Skip getting from cache`);
330
330
  }
331
331
  return undefined;
@@ -340,14 +340,14 @@ export async function getFromCache<T>(
340
340
  sqlQuery.sql.toLowerCase() === cacheResult[entityQueryName]
341
341
  ) {
342
342
  if (options.logCache) {
343
- // eslint-disable-next-line no-console
343
+ // eslint-disable-next-line no-console
344
344
  console.warn(`Get value from cache, cacheKey: ${key}`);
345
345
  }
346
346
  const results = cacheResult[dataName];
347
347
  return JSON.parse(results as string);
348
348
  }
349
349
  } catch (error: any) {
350
- // eslint-disable-next-line no-console
350
+ // eslint-disable-next-line no-console
351
351
  console.error(`Error getting from cache: ${error.message}`, error);
352
352
  }
353
353
 
@@ -385,7 +385,7 @@ export async function setCacheResult(
385
385
  // Skip cache if table is in cache context (will be cleared)
386
386
  if (await isTableContainsTableInCacheContext(sqlQuery.sql, options)) {
387
387
  if (options.logCache) {
388
- // eslint-disable-next-line no-console
388
+ // eslint-disable-next-line no-console
389
389
  console.warn(`Context contains value to clear. Skip setting from cache`);
390
390
  }
391
391
  return;
@@ -407,11 +407,11 @@ export async function setCacheResult(
407
407
  .execute();
408
408
 
409
409
  if (options.logCache) {
410
- // eslint-disable-next-line no-console
410
+ // eslint-disable-next-line no-console
411
411
  console.warn(`Store value to cache, cacheKey: ${key}`);
412
412
  }
413
413
  } catch (error: any) {
414
- // eslint-disable-next-line no-console
414
+ // eslint-disable-next-line no-console
415
415
  console.error(`Error setting cache: ${error.message}`, error);
416
416
  }
417
417
  }