forge-sql-orm 2.0.30 → 2.1.1

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 (46) hide show
  1. package/README.md +1410 -81
  2. package/dist/ForgeSQLORM.js +1456 -60
  3. package/dist/ForgeSQLORM.js.map +1 -1
  4. package/dist/ForgeSQLORM.mjs +1440 -61
  5. package/dist/ForgeSQLORM.mjs.map +1 -1
  6. package/dist/core/ForgeSQLAnalyseOperations.d.ts +1 -1
  7. package/dist/core/ForgeSQLAnalyseOperations.d.ts.map +1 -1
  8. package/dist/core/ForgeSQLCacheOperations.d.ts +119 -0
  9. package/dist/core/ForgeSQLCacheOperations.d.ts.map +1 -0
  10. package/dist/core/ForgeSQLCrudOperations.d.ts +38 -22
  11. package/dist/core/ForgeSQLCrudOperations.d.ts.map +1 -1
  12. package/dist/core/ForgeSQLORM.d.ts +248 -13
  13. package/dist/core/ForgeSQLORM.d.ts.map +1 -1
  14. package/dist/core/ForgeSQLQueryBuilder.d.ts +394 -19
  15. package/dist/core/ForgeSQLQueryBuilder.d.ts.map +1 -1
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/lib/drizzle/extensions/additionalActions.d.ts +90 -0
  19. package/dist/lib/drizzle/extensions/additionalActions.d.ts.map +1 -0
  20. package/dist/utils/cacheContextUtils.d.ts +123 -0
  21. package/dist/utils/cacheContextUtils.d.ts.map +1 -0
  22. package/dist/utils/cacheUtils.d.ts +56 -0
  23. package/dist/utils/cacheUtils.d.ts.map +1 -0
  24. package/dist/utils/sqlUtils.d.ts +8 -0
  25. package/dist/utils/sqlUtils.d.ts.map +1 -1
  26. package/dist/webtriggers/clearCacheSchedulerTrigger.d.ts +46 -0
  27. package/dist/webtriggers/clearCacheSchedulerTrigger.d.ts.map +1 -0
  28. package/dist/webtriggers/index.d.ts +1 -0
  29. package/dist/webtriggers/index.d.ts.map +1 -1
  30. package/package.json +15 -12
  31. package/src/core/ForgeSQLAnalyseOperations.ts +1 -1
  32. package/src/core/ForgeSQLCacheOperations.ts +195 -0
  33. package/src/core/ForgeSQLCrudOperations.ts +49 -40
  34. package/src/core/ForgeSQLORM.ts +743 -34
  35. package/src/core/ForgeSQLQueryBuilder.ts +456 -20
  36. package/src/index.ts +1 -1
  37. package/src/lib/drizzle/extensions/additionalActions.ts +852 -0
  38. package/src/lib/drizzle/extensions/types.d.ts +99 -10
  39. package/src/utils/cacheContextUtils.ts +212 -0
  40. package/src/utils/cacheUtils.ts +403 -0
  41. package/src/utils/sqlUtils.ts +42 -0
  42. package/src/webtriggers/clearCacheSchedulerTrigger.ts +79 -0
  43. package/src/webtriggers/index.ts +1 -0
  44. package/dist/lib/drizzle/extensions/selectAliased.d.ts +0 -9
  45. package/dist/lib/drizzle/extensions/selectAliased.d.ts.map +0 -1
  46. package/src/lib/drizzle/extensions/selectAliased.ts +0 -72
@@ -5,42 +5,84 @@ import {
5
5
  AnyMySqlTable,
6
6
  customType,
7
7
  MySqlSelectBuilder,
8
+ MySqlTable,
8
9
  } from "drizzle-orm/mysql-core";
9
10
  import {
10
11
  MySqlSelectDynamic,
11
12
  type SelectedFields,
12
13
  } from "drizzle-orm/mysql-core/query-builders/select.types";
13
14
  import { InferInsertModel, Query, SQL } from "drizzle-orm";
14
- import { DateTime } from "luxon";
15
- import { parseDateTime } from "../utils/sqlUtils";
16
- import { MySqlRemoteDatabase, MySqlRemotePreparedQueryHKT } from "drizzle-orm/mysql-proxy/index";
15
+ import { parseDateTime, formatDateTime } from "../utils/sqlUtils";
16
+ import { MySqlRemoteDatabase, MySqlRemotePreparedQueryHKT } from "drizzle-orm/mysql-proxy";
17
17
  import { SqlHints } from "../utils/sqlHints";
18
18
  import {
19
19
  ClusterStatementRowCamelCase,
20
20
  ExplainAnalyzeRow,
21
21
  SlowQueryNormalized,
22
22
  } from "./SystemTables";
23
+ import { ForgeSQLCacheOperations } from "./ForgeSQLCacheOperations";
24
+ import {
25
+ DeleteAndEvictCacheType, ExecuteQuery, ExecuteQueryCacheable,
26
+ InsertAndEvictCacheType,
27
+ SelectAliasedCacheableType,
28
+ SelectAliasedDistinctCacheableType,
29
+ SelectAliasedDistinctType,
30
+ SelectAliasedType, SelectAllDistinctFromAliasedType,
31
+ SelectAllDistinctFromCacheableAliasedType, SelectAllFromAliasedType, SelectAllFromCacheableAliasedType,
32
+ UpdateAndEvictCacheType,
33
+ } from "..";
34
+ import {
35
+ MySqlDeleteBase,
36
+ MySqlInsertBuilder,
37
+ MySqlSelectBase,
38
+ MySqlUpdateBuilder,
39
+ } from "drizzle-orm/mysql-core/query-builders";
40
+ import { MySqlRemoteQueryResultHKT } from "drizzle-orm/mysql-proxy";
41
+ import {GetSelectTableName, GetSelectTableSelection} from "drizzle-orm/query-builders/select.types";
42
+ import {SQLWrapper} from "drizzle-orm/sql/sql";
43
+ import type {MySqlQueryResultKind} from "drizzle-orm/mysql-core/session";
44
+ import type {WithBuilder} from "drizzle-orm/mysql-core/subquery";
45
+ import {WithSubquery} from "drizzle-orm/subquery";
23
46
 
24
47
  /**
25
48
  * Core interface for ForgeSQL operations.
26
49
  * Provides access to CRUD operations, schema-level SQL operations, and query analysis capabilities.
27
50
  *
51
+ * This is the main interface that developers interact with when using ForgeSQL ORM.
52
+ * It combines query building capabilities with database operations and caching.
53
+ *
28
54
  * @interface ForgeSqlOperation
29
55
  * @extends {QueryBuilderForgeSql}
30
56
  */
31
57
  export interface ForgeSqlOperation extends QueryBuilderForgeSql {
32
58
  /**
33
- * Provides CRUD (Create, Update, Delete) operations.
34
- * @deprecated Use modify() instead for better type safety and consistency
35
- * @returns {CRUDForgeSQL} Interface for performing CRUD operations
59
+ * Creates a new query builder for the given entity.
60
+ * @returns {MySqlRemoteDatabase<Record<string, unknown>>} The Drizzle database instance for building queries
36
61
  */
37
- crud(): CRUDForgeSQL;
62
+ getDrizzleQueryBuilder(): MySqlRemoteDatabase<Record<string, unknown>> & {
63
+ selectAliased: SelectAliasedType;
64
+ selectAliasedDistinct: SelectAliasedDistinctType;
65
+ executeQuery: ExecuteQuery;
66
+ selectAliasedCacheable: SelectAliasedCacheableType;
67
+ selectAliasedDistinctCacheable: SelectAliasedDistinctCacheableType;
68
+ executeQueryCacheable: ExecuteQueryCacheable;
69
+ insertWithCacheContext: InsertAndEvictCacheType;
70
+ insertAndEvictCache: InsertAndEvictCacheType;
71
+ updateAndEvictCache: UpdateAndEvictCacheType;
72
+ updateWithCacheContext: UpdateAndEvictCacheType;
73
+ deleteAndEvictCache: DeleteAndEvictCacheType;
74
+ deleteWithCacheContext: DeleteAndEvictCacheType;
75
+ selectFrom: SelectAllFromAliasedType;
76
+ selectDistinctFrom: SelectAllDistinctFromAliasedType;
77
+ selectFromCacheable: SelectAllFromCacheableAliasedType;
78
+ selectDistinctFromCacheable: SelectAllDistinctFromCacheableAliasedType;
79
+ };
38
80
 
39
81
  /**
40
82
  * Provides modify (Create, Update, Delete) operations with optimistic locking support.
41
- * @returns {CRUDForgeSQL} Interface for performing CRUD operations
83
+ * @returns {VerioningModificationForgeSQL} Interface for performing CRUD operations
42
84
  */
43
- modify(): CRUDForgeSQL;
85
+ modifyWithVersioning(): VerioningModificationForgeSQL;
44
86
 
45
87
  /**
46
88
  * Provides schema-level SQL fetch operations with type safety.
@@ -53,12 +95,29 @@ export interface ForgeSqlOperation extends QueryBuilderForgeSql {
53
95
  * @returns {SchemaAnalyzeForgeSql} Interface for analyzing query performance
54
96
  */
55
97
  analyze(): SchemaAnalyzeForgeSql;
98
+
99
+ /**
100
+ * Provides schema-level SQL operations with optimistic locking/versioning and automatic cache eviction.
101
+ *
102
+ * This method returns operations that use `modifyWithVersioning()` internally, providing:
103
+ * - Optimistic locking support
104
+ * - Automatic version field management
105
+ * - Cache eviction after successful operations
106
+ *
107
+ * @returns {ForgeSQLCacheOperations} Interface for executing versioned SQL operations with cache management
108
+ */
109
+ modifyWithVersioningAndEvictCache(): ForgeSQLCacheOperations;
56
110
  }
57
111
 
58
112
  /**
59
113
  * Interface for Query Builder operations.
60
114
  * Provides access to the underlying Drizzle ORM query builder with enhanced functionality.
61
115
  *
116
+ * This interface extends Drizzle's query building capabilities with:
117
+ * - Field aliasing to prevent name collisions in joins
118
+ * - Caching support for select operations
119
+ * - Automatic cache eviction for modify operations
120
+ *
62
121
  * @interface QueryBuilderForgeSql
63
122
  */
64
123
  export interface QueryBuilderForgeSql {
@@ -66,7 +125,20 @@ export interface QueryBuilderForgeSql {
66
125
  * Creates a new query builder for the given entity.
67
126
  * @returns {MySqlRemoteDatabase<Record<string, unknown>>} The Drizzle database instance for building queries
68
127
  */
69
- getDrizzleQueryBuilder(): MySqlRemoteDatabase<Record<string, unknown>>;
128
+ getDrizzleQueryBuilder(): MySqlRemoteDatabase<Record<string, unknown>> & {
129
+ selectAliased: SelectAliasedType;
130
+ selectAliasedDistinct: SelectAliasedDistinctType;
131
+ executeQuery: ExecuteQuery;
132
+ selectAliasedCacheable: SelectAliasedCacheableType;
133
+ selectAliasedDistinctCacheable: SelectAliasedDistinctCacheableType;
134
+ executeQueryCacheable: ExecuteQueryCacheable;
135
+ insertWithCacheContext: InsertAndEvictCacheType;
136
+ insertAndEvictCache: InsertAndEvictCacheType;
137
+ updateAndEvictCache: UpdateAndEvictCacheType;
138
+ updateWithCacheContext: UpdateAndEvictCacheType;
139
+ deleteAndEvictCache: DeleteAndEvictCacheType;
140
+ deleteWithCacheContext: DeleteAndEvictCacheType;
141
+ };
70
142
 
71
143
  /**
72
144
  * Creates a select query with unique field aliases to prevent field name collisions in joins.
@@ -89,6 +161,22 @@ export interface QueryBuilderForgeSql {
89
161
  ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
90
162
 
91
163
  /**
164
+ * Creates a select query builder for all columns from a table with field aliasing support.
165
+ * This is a convenience method that automatically selects all columns from the specified table.
166
+ *
167
+ * @template T - The type of the table
168
+ * @param table - The table to select from
169
+ * @returns Select query builder with all table columns and field aliasing support
170
+ * @example
171
+ * ```typescript
172
+ * const users = await forgeSQL.selectFrom(userTable).where(eq(userTable.id, 1));
173
+ * ```
174
+ */
175
+ selectFrom<T extends MySqlTable>(
176
+ table: T,
177
+ ): MySqlSelectBase<GetSelectTableName<T>, T["_"]["columns"] extends undefined ? GetSelectTableSelection<T> : T["_"]["columns"], T["_"]["columns"] extends undefined ? "single" : "partial", MySqlRemotePreparedQueryHKT, GetSelectTableName<T> extends string ? Record<string & GetSelectTableName<T>, "not-null"> : {}, false, never, any>;
178
+
179
+ /**
92
180
  * Creates a distinct select query with unique field aliases to prevent field name collisions in joins.
93
181
  * This is particularly useful when working with Atlassian Forge SQL, which collapses fields with the same name in joined tables.
94
182
  *
@@ -107,15 +195,351 @@ export interface QueryBuilderForgeSql {
107
195
  selectDistinct<TSelection extends SelectedFields>(
108
196
  fields: TSelection,
109
197
  ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
198
+ /**
199
+ * Creates a select distinct query builder for all columns from a table with field aliasing support.
200
+ * This is a convenience method that automatically selects all distinct columns from the specified table.
201
+ *
202
+ * @template T - The type of the table
203
+ * @param table - The table to select from
204
+ * @returns Select distinct query builder with all table columns and field aliasing support
205
+ * @example
206
+ * ```typescript
207
+ * const uniqueUsers = await forgeSQL.selectDistinctFrom(userTable).where(eq(userTable.status, 'active'));
208
+ * ```
209
+ */
210
+ selectDistinctFrom<T extends MySqlTable>(
211
+ table: T,
212
+ ): MySqlSelectBase<GetSelectTableName<T>, T["_"]["columns"] extends undefined ? GetSelectTableSelection<T> : T["_"]["columns"], T["_"]["columns"] extends undefined ? "single" : "partial", MySqlRemotePreparedQueryHKT, GetSelectTableName<T> extends string ? Record<string & GetSelectTableName<T>, "not-null"> : {}, false, never, any>;
213
+
214
+ /**
215
+ * Creates a cacheable select query with unique field aliases to prevent field name collisions in joins.
216
+ * This is particularly useful when working with Atlassian Forge SQL, which collapses fields with the same name in joined tables.
217
+ *
218
+ * @template TSelection - The type of the selected fields
219
+ * @param {TSelection} fields - Object containing the fields to select, with table schemas as values
220
+ * @param {number} cacheTTL - cache ttl optional default is 60 sec.
221
+ * @returns {MySqlSelectBuilder<TSelection, MySql2PreparedQueryHKT>} A select query builder with unique field aliases
222
+ * @throws {Error} If fields parameter is empty
223
+ * @example
224
+ * ```typescript
225
+ * await forgeSQL
226
+ * .selectCacheable({user: users, order: orders},60)
227
+ * .from(orders)
228
+ * .innerJoin(users, eq(orders.userId, users.id));
229
+ * ```
230
+ */
231
+ selectCacheable<TSelection extends SelectedFields>(
232
+ fields: TSelection,
233
+ cacheTTL?: number,
234
+ ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
235
+
236
+ /**
237
+ * Creates a cacheable select query builder for all columns from a table with field aliasing and caching support.
238
+ * This is a convenience method that automatically selects all columns from the specified table with caching enabled.
239
+ *
240
+ * @template T - The type of the table
241
+ * @param table - The table to select from
242
+ * @param cacheTTL - Optional cache TTL override (defaults to global cache TTL)
243
+ * @returns Select query builder with all table columns, field aliasing, and caching support
244
+ * @example
245
+ * ```typescript
246
+ * const users = await forgeSQL.selectCacheableFrom(userTable, 300).where(eq(userTable.id, 1));
247
+ * ```
248
+ */
249
+ selectCacheableFrom<T extends MySqlTable>(
250
+ table: T,
251
+ cacheTTL?: number,
252
+ ): MySqlSelectBase<GetSelectTableName<T>, T["_"]["columns"] extends undefined ? GetSelectTableSelection<T> : T["_"]["columns"], T["_"]["columns"] extends undefined ? "single" : "partial", MySqlRemotePreparedQueryHKT, GetSelectTableName<T> extends string ? Record<string & GetSelectTableName<T>, "not-null"> : {}, false, never, any>;
253
+
254
+ /**
255
+ * Creates a cacheable distinct select query with unique field aliases to prevent field name collisions in joins.
256
+ * This is particularly useful when working with Atlassian Forge SQL, which collapses fields with the same name in joined tables.
257
+ *
258
+ * @template TSelection - The type of the selected fields
259
+ * @param {TSelection} fields - Object containing the fields to select, with table schemas as values
260
+ * @param {number} cacheTTL - cache ttl optional default is 60 sec.
261
+ * @returns {MySqlSelectBuilder<TSelection, MySql2PreparedQueryHKT>} A distinct select query builder with unique field aliases
262
+ * @throws {Error} If fields parameter is empty
263
+ * @example
264
+ * ```typescript
265
+ * await forgeSQL
266
+ * .selectDistinctCacheable({user: users, order: orders}, 60)
267
+ * .from(orders)
268
+ * .innerJoin(users, eq(orders.userId, users.id));
269
+ * ```
270
+ */
271
+ selectDistinctCacheable<TSelection extends SelectedFields>(
272
+ fields: TSelection,
273
+ cacheTTL?: number,
274
+ ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
275
+
276
+ /**
277
+ * Creates a cacheable select distinct query builder for all columns from a table with field aliasing and caching support.
278
+ * This is a convenience method that automatically selects all distinct columns from the specified table with caching enabled.
279
+ *
280
+ * @template T - The type of the table
281
+ * @param table - The table to select from
282
+ * @param cacheTTL - Optional cache TTL override (defaults to global cache TTL)
283
+ * @returns Select distinct query builder with all table columns, field aliasing, and caching support
284
+ * @example
285
+ * ```typescript
286
+ * const uniqueUsers = await forgeSQL.selectDistinctCacheableFrom(userTable, 300).where(eq(userTable.status, 'active'));
287
+ * ```
288
+ */
289
+ selectDistinctCacheableFrom<T extends MySqlTable>(
290
+ table: T,
291
+ cacheTTL?: number,
292
+ ): MySqlSelectBase<GetSelectTableName<T>, T["_"]["columns"] extends undefined ? GetSelectTableSelection<T> : T["_"]["columns"], T["_"]["columns"] extends undefined ? "single" : "partial", MySqlRemotePreparedQueryHKT, GetSelectTableName<T> extends string ? Record<string & GetSelectTableName<T>, "not-null"> : {}, false, never, any>;
293
+
294
+ /**
295
+ * Creates an insert query builder.
296
+ *
297
+ * ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
298
+ * For versioned inserts, use `modifyWithVersioning().insert()` or `modifyWithVersioningAndEvictCache().insert()` instead.
299
+ *
300
+ * @param table - The table to insert into
301
+ * @returns Insert query builder (no versioning, no cache management)
302
+ */
303
+ insert<TTable extends MySqlTable>(
304
+ table: TTable,
305
+ ): MySqlInsertBuilder<TTable, MySqlRemoteQueryResultHKT, MySqlRemotePreparedQueryHKT>;
306
+
307
+ /**
308
+ * Creates an insert query builder that automatically evicts cache after execution.
309
+ *
310
+ * ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
311
+ * For versioned inserts, use `modifyWithVersioning().insert()` or `modifyWithVersioningAndEvictCache().insert()` instead.
312
+ *
313
+ * @param table - The table to insert into
314
+ * @returns Insert query builder with automatic cache eviction (no versioning)
315
+ */
316
+ insertAndEvictCache<TTable extends MySqlTable>(
317
+ table: TTable,
318
+ ): MySqlInsertBuilder<TTable, MySqlRemoteQueryResultHKT, MySqlRemotePreparedQueryHKT>;
319
+
320
+ /**
321
+ * Creates an update query builder.
322
+ *
323
+ * ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
324
+ * For versioned updates, use `modifyWithVersioning().updateById()` or `modifyWithVersioningAndEvictCache().updateById()` instead.
325
+ *
326
+ * @param table - The table to update
327
+ * @returns Update query builder (no versioning, no cache management)
328
+ */
329
+ update<TTable extends MySqlTable>(
330
+ table: TTable,
331
+ ): MySqlUpdateBuilder<TTable, MySqlRemoteQueryResultHKT, MySqlRemotePreparedQueryHKT>;
332
+
333
+ /**
334
+ * Creates an update query builder that automatically evicts cache after execution.
335
+ *
336
+ * ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
337
+ * For versioned updates, use `modifyWithVersioning().updateById()` or `modifyWithVersioningAndEvictCache().updateById()` instead.
338
+ *
339
+ * @param table - The table to update
340
+ * @returns Update query builder with automatic cache eviction (no versioning)
341
+ */
342
+ updateAndEvictCache<TTable extends MySqlTable>(
343
+ table: TTable,
344
+ ): MySqlUpdateBuilder<TTable, MySqlRemoteQueryResultHKT, MySqlRemotePreparedQueryHKT>;
345
+
346
+ /**
347
+ * Creates a delete query builder.
348
+ *
349
+ * ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
350
+ * For versioned deletes, use `modifyWithVersioning().deleteById()` or `modifyWithVersioningAndEvictCache().deleteById()` instead.
351
+ *
352
+ * @param table - The table to delete from
353
+ * @returns Delete query builder (no versioning, no cache management)
354
+ */
355
+ delete<TTable extends MySqlTable>(
356
+ table: TTable,
357
+ ): MySqlDeleteBase<TTable, MySqlRemoteQueryResultHKT, MySqlRemotePreparedQueryHKT>;
358
+ /**
359
+ * Creates a delete query builder that automatically evicts cache after execution.
360
+ *
361
+ * ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
362
+ * For versioned deletes, use `modifyWithVersioning().deleteById()` or `modifyWithVersioningAndEvictCache().deleteById()` instead.
363
+ *
364
+ * @param table - The table to delete from
365
+ * @returns Delete query builder with automatic cache eviction (no versioning)
366
+ */
367
+ deleteAndEvictCache<TTable extends MySqlTable>(
368
+ table: TTable,
369
+ ): MySqlDeleteBase<TTable, MySqlRemoteQueryResultHKT, MySqlRemotePreparedQueryHKT>;
370
+
371
+ /**
372
+ * Executes operations within a cache context that collects cache eviction events.
373
+ * All clearCache calls within the context are collected and executed in batch at the end.
374
+ * Queries executed within this context will bypass cache for tables that were marked for clearing.
375
+ *
376
+ * @param cacheContext - Function containing operations that may trigger cache evictions
377
+ * @returns Promise that resolves when all operations and cache clearing are complete
378
+ */
379
+ executeWithCacheContext(cacheContext: () => Promise<void>): Promise<void>;
380
+
381
+ /**
382
+ * Executes operations within a cache context and returns a value.
383
+ * All clearCache calls within the context are collected and executed in batch at the end.
384
+ * Queries executed within this context will bypass cache for tables that were marked for clearing.
385
+ *
386
+ * @param cacheContext - Function containing operations that may trigger cache evictions
387
+ * @returns Promise that resolves to the return value of the cacheContext function
388
+ */
389
+ executeWithCacheContextAndReturnValue<T>(cacheContext: () => Promise<T>): Promise<T>;
390
+
391
+ /**
392
+ * Executes operations within a local cache context that provides in-memory caching for select queries.
393
+ * This is useful for optimizing queries within a single resolver or request scope.
394
+ *
395
+ * Local cache features:
396
+ * - Caches select query results in memory for the duration of the context
397
+ * - Automatically evicts cache when insert/update/delete operations are performed
398
+ * - Provides faster access to repeated queries within the same context
399
+ * - Does not persist across different requests or contexts
400
+ *
401
+ * @param cacheContext - Function containing operations that will benefit from local caching
402
+ * @returns Promise that resolves when all operations are complete
403
+ *
404
+ * @example
405
+ * ```typescript
406
+ * await forgeSQL.executeWithLocalContext(async () => {
407
+ * // First call - executes query and caches result
408
+ * const users = await forgeSQL.select({ id: users.id, name: users.name })
409
+ * .from(users).where(eq(users.active, true));
410
+ *
411
+ * // Second call - gets result from local cache (no database query)
412
+ * const cachedUsers = await forgeSQL.select({ id: users.id, name: users.name })
413
+ * .from(users).where(eq(users.active, true));
414
+ *
415
+ * // Insert operation - evicts local cache
416
+ * await forgeSQL.insert(users).values({ name: 'New User', active: true });
417
+ * });
418
+ * ```
419
+ */
420
+ executeWithLocalContext(cacheContext: () => Promise<void>): Promise<void>;
421
+
422
+ /**
423
+ * Executes operations within a local cache context and returns a value.
424
+ * This is useful for optimizing queries within a single resolver or request scope.
425
+ *
426
+ * Local cache features:
427
+ * - Caches select query results in memory for the duration of the context
428
+ * - Automatically evicts cache when insert/update/delete operations are performed
429
+ * - Provides faster access to repeated queries within the same context
430
+ * - Does not persist across different requests or contexts
431
+ *
432
+ * @param cacheContext - Function containing operations that will benefit from local caching
433
+ * @returns Promise that resolves to the return value of the cacheContext function
434
+ *
435
+ * @example
436
+ * ```typescript
437
+ * const result = await forgeSQL.executeWithLocalCacheContextAndReturnValue(async () => {
438
+ * // First call - executes query and caches result
439
+ * const users = await forgeSQL.select({ id: users.id, name: users.name })
440
+ * .from(users).where(eq(users.active, true));
441
+ *
442
+ * // Second call - gets result from local cache (no database query)
443
+ * const cachedUsers = await forgeSQL.select({ id: users.id, name: users.name })
444
+ * .from(users).where(eq(users.active, true));
445
+ *
446
+ * return { users, cachedUsers };
447
+ * });
448
+ * ```
449
+ */
450
+ executeWithLocalCacheContextAndReturnValue<T>(cacheContext: () => Promise<T>): Promise<T>;
451
+
452
+ /**
453
+ * Executes a raw SQL query with local cache support.
454
+ * This method provides local caching for raw SQL queries within the current invocation context.
455
+ * Results are cached locally and will be returned from cache on subsequent identical queries.
456
+ *
457
+ * @param query - The SQL query to execute (SQLWrapper or string)
458
+ * @returns Promise with query results
459
+ * @example
460
+ * ```typescript
461
+ * // Using SQLWrapper
462
+ * const result = await forgeSQL.execute(sql`SELECT * FROM users WHERE id = ${userId}`);
463
+ *
464
+ * // Using string
465
+ * const result = await forgeSQL.execute("SELECT * FROM users WHERE status = 'active'");
466
+ * ```
467
+ */
468
+ execute(query: SQLWrapper | string): Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, unknown>>;
469
+
470
+ /**
471
+ * Executes a raw SQL query with both local and global cache support.
472
+ * This method provides comprehensive caching for raw SQL queries:
473
+ * - Local cache: Within the current invocation context
474
+ * - Global cache: Cross-invocation caching using @forge/kvs
475
+ *
476
+ * @param query - The SQL query to execute (SQLWrapper or string)
477
+ * @param cacheTtl - Optional cache TTL override (defaults to global cache TTL)
478
+ * @returns Promise with query results
479
+ * @example
480
+ * ```typescript
481
+ * // Using SQLWrapper with custom TTL
482
+ * const result = await forgeSQL.executeCacheable(sql`SELECT * FROM users WHERE id = ${userId}`, 300);
483
+ *
484
+ * // Using string with default TTL
485
+ * const result = await forgeSQL.executeCacheable("SELECT * FROM users WHERE status = 'active'");
486
+ * ```
487
+ */
488
+ executeCacheable(query: SQLWrapper | string, cacheTtl?: number): Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, unknown>>;
489
+ /**
490
+ * Creates a Common Table Expression (CTE) builder for complex queries.
491
+ * CTEs allow you to define temporary named result sets that exist within the scope of a single query.
492
+ *
493
+ * @returns WithBuilder for creating CTEs
494
+ * @example
495
+ * ```typescript
496
+ * const withQuery = forgeSQL.$with('userStats').as(
497
+ * forgeSQL.select({ userId: users.id, count: sql<number>`count(*)` })
498
+ * .from(users)
499
+ * .groupBy(users.id)
500
+ * );
501
+ * ```
502
+ */
503
+ $with: WithBuilder;
504
+
505
+ /**
506
+ * Creates a query builder that uses Common Table Expressions (CTEs).
507
+ * CTEs allow you to define temporary named result sets that exist within the scope of a single query.
508
+ *
509
+ * @param queries - Array of CTE queries created with $with()
510
+ * @returns Query builder with CTE support
511
+ * @example
512
+ * ```typescript
513
+ * const withQuery = forgeSQL.$with('userStats').as(
514
+ * forgeSQL.select({ userId: users.id, count: sql<number>`count(*)` })
515
+ * .from(users)
516
+ * .groupBy(users.id)
517
+ * );
518
+ *
519
+ * const result = await forgeSQL.with(withQuery)
520
+ * .select({ userId: withQuery.userId, count: withQuery.count })
521
+ * .from(withQuery);
522
+ * ```
523
+ */
524
+ with(...queries: WithSubquery[]): {
525
+ select: {
526
+ (): MySqlSelectBuilder<undefined, MySqlRemotePreparedQueryHKT>;
527
+ <TSelection extends SelectedFields>(fields: TSelection): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
528
+ };
529
+ selectDistinct: {
530
+ (): MySqlSelectBuilder<undefined, MySqlRemotePreparedQueryHKT>;
531
+ <TSelection extends SelectedFields>(fields: TSelection): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
532
+ };
533
+ }
110
534
  }
111
535
 
112
536
  /**
113
537
  * Interface for Modify (Create, Update, Delete) operations.
114
538
  * Provides methods for basic database operations with support for optimistic locking.
115
539
  *
116
- * @interface CRUDForgeSQL
540
+ * @interface VerioningModificationForgeSQL
117
541
  */
118
- export interface CRUDForgeSQL {
542
+ export interface VerioningModificationForgeSQL {
119
543
  /**
120
544
  * Inserts multiple records into the database.
121
545
  * @template T - The type of the table schema
@@ -180,6 +604,11 @@ export interface CRUDForgeSQL {
180
604
  ): Promise<number>;
181
605
  }
182
606
 
607
+ export interface CacheForgeSQL extends VerioningModificationForgeSQL {
608
+ evictCache(tables: string[]): Promise<void>;
609
+ evictCacheEntities(tables: AnyMySqlTable[]): Promise<void>;
610
+ }
611
+
183
612
  /**
184
613
  * Interface for schema analysis operations.
185
614
  * Provides methods for analyzing query performance and execution plans.
@@ -283,10 +712,11 @@ export interface SchemaSqlForgeSql {
283
712
 
284
713
  /**
285
714
  * Executes a raw SQL update query.
286
- * @param {string} query - The raw SQL update query
287
- * @param {SqlParameters[]} [params] - Optional SQL parameters
288
- * @returns {Promise<UpdateQueryResponse>} The update response containing affected rows
289
- * @throws {Error} If the update operation fails
715
+ *
716
+ * @param query - The raw SQL update query
717
+ * @param params - Optional SQL parameters
718
+ * @returns Promise that resolves to the update response containing affected rows
719
+ * @throws Error if the update operation fails
290
720
  */
291
721
  executeRawUpdateSQL(query: string, params?: unknown[]): Promise<UpdateQueryResponse>;
292
722
  }
@@ -335,6 +765,12 @@ export interface ForgeSqlOrmOptions {
335
765
  disableOptimisticLocking?: boolean;
336
766
  /** SQL hints to be applied to queries */
337
767
  hints?: SqlHints;
768
+ cacheTTL?: number;
769
+ cacheEntityName?: string;
770
+ cacheEntityQueryName?: string;
771
+ cacheWrapTable?: boolean;
772
+ cacheEntityExpirationName?: string;
773
+ cacheEntityDataName?: string;
338
774
 
339
775
  /**
340
776
  * Additional metadata for table configuration.
@@ -371,7 +807,7 @@ export const forgeDateTimeString = customType<{
371
807
  return "datetime";
372
808
  },
373
809
  toDriver(value: Date) {
374
- return DateTime.fromJSDate(new Date(value)).toFormat("yyyy-LL-dd'T'HH:mm:ss.SSS");
810
+ return formatDateTime(value, "yyyy-LL-dd' 'HH:mm:ss.SSS");
375
811
  },
376
812
  fromDriver(value: unknown) {
377
813
  const format = "yyyy-LL-dd'T'HH:mm:ss.SSS";
@@ -394,7 +830,7 @@ export const forgeTimestampString = customType<{
394
830
  return "timestamp";
395
831
  },
396
832
  toDriver(value: Date) {
397
- return DateTime.fromJSDate(value).toFormat("yyyy-LL-dd'T'HH:mm:ss.SSS");
833
+ return formatDateTime(value, "yyyy-LL-dd' 'HH:mm:ss.SSS");
398
834
  },
399
835
  fromDriver(value: unknown) {
400
836
  const format = "yyyy-LL-dd'T'HH:mm:ss.SSS";
@@ -417,7 +853,7 @@ export const forgeDateString = customType<{
417
853
  return "date";
418
854
  },
419
855
  toDriver(value: Date) {
420
- return DateTime.fromJSDate(value).toFormat("yyyy-LL-dd");
856
+ return formatDateTime(value, "yyyy-LL-dd");
421
857
  },
422
858
  fromDriver(value: unknown) {
423
859
  const format = "yyyy-LL-dd";
@@ -440,7 +876,7 @@ export const forgeTimeString = customType<{
440
876
  return "time";
441
877
  },
442
878
  toDriver(value: Date) {
443
- return DateTime.fromJSDate(value).toFormat("HH:mm:ss.SSS");
879
+ return formatDateTime(value, "HH:mm:ss.SSS");
444
880
  },
445
881
  fromDriver(value: unknown) {
446
882
  return parseDateTime(value as string, "HH:mm:ss.SSS");
package/src/index.ts CHANGED
@@ -6,7 +6,7 @@ export * from "./core/ForgeSQLSelectOperations";
6
6
  export * from "./utils/sqlUtils";
7
7
  export * from "./utils/forgeDriver";
8
8
  export * from "./webtriggers";
9
- export * from "./lib/drizzle/extensions/selectAliased";
9
+ export * from "./lib/drizzle/extensions/additionalActions";
10
10
  export * from "./core/SystemTables";
11
11
 
12
12
  export default ForgeSQLORM;