forge-sql-orm 2.1.0 → 2.1.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge-sql-orm",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
4
4
  "description": "Drizzle ORM integration for Atlassian @forge/sql. Provides a custom driver, schema migration, two levels of caching (local and global via @forge/kvs), optimistic locking, and query analysis.",
5
5
  "main": "dist/ForgeSQLORM.js",
6
6
  "module": "dist/ForgeSQLORM.mjs",
@@ -34,7 +34,7 @@
34
34
  "devDependencies": {
35
35
  "@eslint/js": "^9.35.0",
36
36
  "@types/luxon": "^3.7.1",
37
- "@types/node": "^24.3.3",
37
+ "@types/node": "^24.4.0",
38
38
  "@typescript-eslint/eslint-plugin": "^8.43.0",
39
39
  "@typescript-eslint/parser": "^8.43.0",
40
40
  "@vitest/coverage-v8": "^3.2.4",
@@ -36,6 +36,8 @@ import {
36
36
  } from "drizzle-orm/mysql-core/query-builders";
37
37
  import { cacheApplicationContext, localCacheApplicationContext } from "../utils/cacheContextUtils";
38
38
  import { clearTablesCache } from "../utils/cacheUtils";
39
+ import { SQLWrapper } from "drizzle-orm/sql/sql";
40
+ import { WithSubquery } from "drizzle-orm/subquery";
39
41
 
40
42
  /**
41
43
  * Implementation of ForgeSQLORM that uses Drizzle ORM for query building.
@@ -142,16 +144,19 @@ class ForgeSQLORMImpl implements ForgeSqlOperation {
142
144
  async executeWithCacheContextAndReturnValue<T>(cacheContext: () => Promise<T>): Promise<T> {
143
145
  return await this.executeWithLocalCacheContextAndReturnValue(
144
146
  async () =>
145
- await cacheApplicationContext.run({ tables: new Set<string>() }, async () => {
146
- try {
147
- return await cacheContext();
148
- } finally {
149
- await clearTablesCache(
150
- Array.from(cacheApplicationContext.getStore()?.tables ?? []),
151
- this.options,
152
- );
153
- }
154
- }),
147
+ await cacheApplicationContext.run(
148
+ cacheApplicationContext.getStore() ?? { tables: new Set<string>() },
149
+ async () => {
150
+ try {
151
+ return await cacheContext();
152
+ } finally {
153
+ await clearTablesCache(
154
+ Array.from(cacheApplicationContext.getStore()?.tables ?? []),
155
+ this.options,
156
+ );
157
+ }
158
+ },
159
+ ),
155
160
  );
156
161
  }
157
162
  /**
@@ -162,9 +167,12 @@ class ForgeSQLORMImpl implements ForgeSqlOperation {
162
167
  * @returns Promise that resolves to the return value of the cacheContext function
163
168
  */
164
169
  async executeWithLocalCacheContextAndReturnValue<T>(cacheContext: () => Promise<T>): Promise<T> {
165
- return await localCacheApplicationContext.run({ cache: {} }, async () => {
166
- return await cacheContext();
167
- });
170
+ return await localCacheApplicationContext.run(
171
+ localCacheApplicationContext.getStore() ?? { cache: {} },
172
+ async () => {
173
+ return await cacheContext();
174
+ },
175
+ );
168
176
  }
169
177
 
170
178
  /**
@@ -440,6 +448,155 @@ class ForgeSQLORMImpl implements ForgeSqlOperation {
440
448
  }
441
449
  return this.drizzle.selectAliasedDistinctCacheable(fields, cacheTTL);
442
450
  }
451
+
452
+ /**
453
+ * Creates a select query builder for all columns from a table with field aliasing support.
454
+ * This is a convenience method that automatically selects all columns from the specified table.
455
+ *
456
+ * @template T - The type of the table
457
+ * @param table - The table to select from
458
+ * @returns Select query builder with all table columns and field aliasing support
459
+ * @example
460
+ * ```typescript
461
+ * const users = await forgeSQL.selectFrom(userTable).where(eq(userTable.id, 1));
462
+ * ```
463
+ */
464
+ selectFrom<T extends MySqlTable>(table: T) {
465
+ return this.drizzle.selectFrom(table);
466
+ }
467
+
468
+ /**
469
+ * Creates a select distinct query builder for all columns from a table with field aliasing support.
470
+ * This is a convenience method that automatically selects all distinct columns from the specified table.
471
+ *
472
+ * @template T - The type of the table
473
+ * @param table - The table to select from
474
+ * @returns Select distinct query builder with all table columns and field aliasing support
475
+ * @example
476
+ * ```typescript
477
+ * const uniqueUsers = await forgeSQL.selectDistinctFrom(userTable).where(eq(userTable.status, 'active'));
478
+ * ```
479
+ */
480
+ selectDistinctFrom<T extends MySqlTable>(table: T) {
481
+ return this.drizzle.selectDistinctFrom(table);
482
+ }
483
+
484
+ /**
485
+ * Creates a cacheable select query builder for all columns from a table with field aliasing and caching support.
486
+ * This is a convenience method that automatically selects all columns from the specified table with caching enabled.
487
+ *
488
+ * @template T - The type of the table
489
+ * @param table - The table to select from
490
+ * @param cacheTTL - Optional cache TTL override (defaults to global cache TTL)
491
+ * @returns Select query builder with all table columns, field aliasing, and caching support
492
+ * @example
493
+ * ```typescript
494
+ * const users = await forgeSQL.selectCacheableFrom(userTable, 300).where(eq(userTable.id, 1));
495
+ * ```
496
+ */
497
+ selectCacheableFrom<T extends MySqlTable>(table: T, cacheTTL?: number) {
498
+ return this.drizzle.selectFromCacheable(table, cacheTTL);
499
+ }
500
+
501
+ /**
502
+ * Creates a cacheable select distinct query builder for all columns from a table with field aliasing and caching support.
503
+ * This is a convenience method that automatically selects all distinct columns from the specified table with caching enabled.
504
+ *
505
+ * @template T - The type of the table
506
+ * @param table - The table to select from
507
+ * @param cacheTTL - Optional cache TTL override (defaults to global cache TTL)
508
+ * @returns Select distinct query builder with all table columns, field aliasing, and caching support
509
+ * @example
510
+ * ```typescript
511
+ * const uniqueUsers = await forgeSQL.selectDistinctCacheableFrom(userTable, 300).where(eq(userTable.status, 'active'));
512
+ * ```
513
+ */
514
+ selectDistinctCacheableFrom<T extends MySqlTable>(table: T, cacheTTL?: number) {
515
+ return this.drizzle.selectDistinctFromCacheable(table, cacheTTL);
516
+ }
517
+
518
+ /**
519
+ * Executes a raw SQL query with local cache support.
520
+ * This method provides local caching for raw SQL queries within the current invocation context.
521
+ * Results are cached locally and will be returned from cache on subsequent identical queries.
522
+ *
523
+ * @param query - The SQL query to execute (SQLWrapper or string)
524
+ * @returns Promise with query results
525
+ * @example
526
+ * ```typescript
527
+ * // Using SQLWrapper
528
+ * const result = await forgeSQL.execute(sql`SELECT * FROM users WHERE id = ${userId}`);
529
+ *
530
+ * // Using string
531
+ * const result = await forgeSQL.execute("SELECT * FROM users WHERE status = 'active'");
532
+ * ```
533
+ */
534
+ execute(query: SQLWrapper | string) {
535
+ return this.drizzle.executeQuery(query);
536
+ }
537
+
538
+ /**
539
+ * Executes a raw SQL query with both local and global cache support.
540
+ * This method provides comprehensive caching for raw SQL queries:
541
+ * - Local cache: Within the current invocation context
542
+ * - Global cache: Cross-invocation caching using @forge/kvs
543
+ *
544
+ * @param query - The SQL query to execute (SQLWrapper or string)
545
+ * @param cacheTtl - Optional cache TTL override (defaults to global cache TTL)
546
+ * @returns Promise with query results
547
+ * @example
548
+ * ```typescript
549
+ * // Using SQLWrapper with custom TTL
550
+ * const result = await forgeSQL.executeCacheable(sql`SELECT * FROM users WHERE id = ${userId}`, 300);
551
+ *
552
+ * // Using string with default TTL
553
+ * const result = await forgeSQL.executeCacheable("SELECT * FROM users WHERE status = 'active'");
554
+ * ```
555
+ */
556
+ executeCacheable(query: SQLWrapper | string, cacheTtl?: number) {
557
+ return this.drizzle.executeQueryCacheable(query, cacheTtl);
558
+ }
559
+
560
+ /**
561
+ * Creates a Common Table Expression (CTE) builder for complex queries.
562
+ * CTEs allow you to define temporary named result sets that exist within the scope of a single query.
563
+ *
564
+ * @returns WithBuilder for creating CTEs
565
+ * @example
566
+ * ```typescript
567
+ * const withQuery = forgeSQL.$with('userStats').as(
568
+ * forgeSQL.select({ userId: users.id, count: sql<number>`count(*)` })
569
+ * .from(users)
570
+ * .groupBy(users.id)
571
+ * );
572
+ * ```
573
+ */
574
+ get $with() {
575
+ return this.drizzle.$with;
576
+ }
577
+
578
+ /**
579
+ * Creates a query builder that uses Common Table Expressions (CTEs).
580
+ * CTEs allow you to define temporary named result sets that exist within the scope of a single query.
581
+ *
582
+ * @param queries - Array of CTE queries created with $with()
583
+ * @returns Query builder with CTE support
584
+ * @example
585
+ * ```typescript
586
+ * const withQuery = forgeSQL.$with('userStats').as(
587
+ * forgeSQL.select({ userId: users.id, count: sql<number>`count(*)` })
588
+ * .from(users)
589
+ * .groupBy(users.id)
590
+ * );
591
+ *
592
+ * const result = await forgeSQL.with(withQuery)
593
+ * .select({ userId: withQuery.userId, count: withQuery.count })
594
+ * .from(withQuery);
595
+ * ```
596
+ */
597
+ with(...queries: WithSubquery[]) {
598
+ return this.drizzle.with(...queries);
599
+ }
443
600
  }
444
601
 
445
602
  /**
@@ -467,6 +624,72 @@ class ForgeSQLORM implements ForgeSqlOperation {
467
624
  return this.ormInstance.selectDistinctCacheable(fields, cacheTTL);
468
625
  }
469
626
 
627
+ /**
628
+ * Creates a select query builder for all columns from a table with field aliasing support.
629
+ * This is a convenience method that automatically selects all columns from the specified table.
630
+ *
631
+ * @template T - The type of the table
632
+ * @param table - The table to select from
633
+ * @returns Select query builder with all table columns and field aliasing support
634
+ * @example
635
+ * ```typescript
636
+ * const users = await forgeSQL.selectFrom(userTable).where(eq(userTable.id, 1));
637
+ * ```
638
+ */
639
+ selectFrom<T extends MySqlTable>(table: T) {
640
+ return this.ormInstance.getDrizzleQueryBuilder().selectFrom(table);
641
+ }
642
+
643
+ /**
644
+ * Creates a select distinct query builder for all columns from a table with field aliasing support.
645
+ * This is a convenience method that automatically selects all distinct columns from the specified table.
646
+ *
647
+ * @template T - The type of the table
648
+ * @param table - The table to select from
649
+ * @returns Select distinct query builder with all table columns and field aliasing support
650
+ * @example
651
+ * ```typescript
652
+ * const uniqueUsers = await forgeSQL.selectDistinctFrom(userTable).where(eq(userTable.status, 'active'));
653
+ * ```
654
+ */
655
+ selectDistinctFrom<T extends MySqlTable>(table: T) {
656
+ return this.ormInstance.getDrizzleQueryBuilder().selectDistinctFrom(table);
657
+ }
658
+
659
+ /**
660
+ * Creates a cacheable select query builder for all columns from a table with field aliasing and caching support.
661
+ * This is a convenience method that automatically selects all columns from the specified table with caching enabled.
662
+ *
663
+ * @template T - The type of the table
664
+ * @param table - The table to select from
665
+ * @param cacheTTL - Optional cache TTL override (defaults to global cache TTL)
666
+ * @returns Select query builder with all table columns, field aliasing, and caching support
667
+ * @example
668
+ * ```typescript
669
+ * const users = await forgeSQL.selectCacheableFrom(userTable, 300).where(eq(userTable.id, 1));
670
+ * ```
671
+ */
672
+ selectCacheableFrom<T extends MySqlTable>(table: T, cacheTTL?: number) {
673
+ return this.ormInstance.getDrizzleQueryBuilder().selectFromCacheable(table, cacheTTL);
674
+ }
675
+
676
+ /**
677
+ * Creates a cacheable select distinct query builder for all columns from a table with field aliasing and caching support.
678
+ * This is a convenience method that automatically selects all distinct columns from the specified table with caching enabled.
679
+ *
680
+ * @template T - The type of the table
681
+ * @param table - The table to select from
682
+ * @param cacheTTL - Optional cache TTL override (defaults to global cache TTL)
683
+ * @returns Select distinct query builder with all table columns, field aliasing, and caching support
684
+ * @example
685
+ * ```typescript
686
+ * const uniqueUsers = await forgeSQL.selectDistinctCacheableFrom(userTable, 300).where(eq(userTable.status, 'active'));
687
+ * ```
688
+ */
689
+ selectDistinctCacheableFrom<T extends MySqlTable>(table: T, cacheTTL?: number) {
690
+ return this.ormInstance.getDrizzleQueryBuilder().selectDistinctFromCacheable(table, cacheTTL);
691
+ }
692
+
470
693
  executeWithCacheContext(cacheContext: () => Promise<void>): Promise<void> {
471
694
  return this.ormInstance.executeWithCacheContext(cacheContext);
472
695
  }
@@ -669,6 +892,89 @@ class ForgeSQLORM implements ForgeSqlOperation {
669
892
  getDrizzleQueryBuilder() {
670
893
  return this.ormInstance.getDrizzleQueryBuilder();
671
894
  }
895
+
896
+ /**
897
+ * Executes a raw SQL query with local cache support.
898
+ * This method provides local caching for raw SQL queries within the current invocation context.
899
+ * Results are cached locally and will be returned from cache on subsequent identical queries.
900
+ *
901
+ * @param query - The SQL query to execute (SQLWrapper or string)
902
+ * @returns Promise with query results
903
+ * @example
904
+ * ```typescript
905
+ * // Using SQLWrapper
906
+ * const result = await forgeSQL.execute(sql`SELECT * FROM users WHERE id = ${userId}`);
907
+ *
908
+ * // Using string
909
+ * const result = await forgeSQL.execute("SELECT * FROM users WHERE status = 'active'");
910
+ * ```
911
+ */
912
+ execute(query: SQLWrapper | string) {
913
+ return this.ormInstance.getDrizzleQueryBuilder().executeQuery(query);
914
+ }
915
+
916
+ /**
917
+ * Executes a raw SQL query with both local and global cache support.
918
+ * This method provides comprehensive caching for raw SQL queries:
919
+ * - Local cache: Within the current invocation context
920
+ * - Global cache: Cross-invocation caching using @forge/kvs
921
+ *
922
+ * @param query - The SQL query to execute (SQLWrapper or string)
923
+ * @param cacheTtl - Optional cache TTL override (defaults to global cache TTL)
924
+ * @returns Promise with query results
925
+ * @example
926
+ * ```typescript
927
+ * // Using SQLWrapper with custom TTL
928
+ * const result = await forgeSQL.executeCacheable(sql`SELECT * FROM users WHERE id = ${userId}`, 300);
929
+ *
930
+ * // Using string with default TTL
931
+ * const result = await forgeSQL.executeCacheable("SELECT * FROM users WHERE status = 'active'");
932
+ * ```
933
+ */
934
+ executeCacheable(query: SQLWrapper | string, cacheTtl?: number) {
935
+ return this.ormInstance.getDrizzleQueryBuilder().executeQueryCacheable(query, cacheTtl);
936
+ }
937
+
938
+ /**
939
+ * Creates a Common Table Expression (CTE) builder for complex queries.
940
+ * CTEs allow you to define temporary named result sets that exist within the scope of a single query.
941
+ *
942
+ * @returns WithBuilder for creating CTEs
943
+ * @example
944
+ * ```typescript
945
+ * const withQuery = forgeSQL.$with('userStats').as(
946
+ * forgeSQL.select({ userId: users.id, count: sql<number>`count(*)` })
947
+ * .from(users)
948
+ * .groupBy(users.id)
949
+ * );
950
+ * ```
951
+ */
952
+ get $with() {
953
+ return this.ormInstance.getDrizzleQueryBuilder().$with;
954
+ }
955
+
956
+ /**
957
+ * Creates a query builder that uses Common Table Expressions (CTEs).
958
+ * CTEs allow you to define temporary named result sets that exist within the scope of a single query.
959
+ *
960
+ * @param queries - Array of CTE queries created with $with()
961
+ * @returns Query builder with CTE support
962
+ * @example
963
+ * ```typescript
964
+ * const withQuery = forgeSQL.$with('userStats').as(
965
+ * forgeSQL.select({ userId: users.id, count: sql<number>`count(*)` })
966
+ * .from(users)
967
+ * .groupBy(users.id)
968
+ * );
969
+ *
970
+ * const result = await forgeSQL.with(withQuery)
971
+ * .select({ userId: withQuery.userId, count: withQuery.count })
972
+ * .from(withQuery);
973
+ * ```
974
+ */
975
+ with(...queries: WithSubquery[]) {
976
+ return this.ormInstance.getDrizzleQueryBuilder().with(...queries);
977
+ }
672
978
  }
673
979
 
674
980
  export default ForgeSQLORM;
@@ -23,19 +23,34 @@ import {
23
23
  import { ForgeSQLCacheOperations } from "./ForgeSQLCacheOperations";
24
24
  import {
25
25
  DeleteAndEvictCacheType,
26
+ ExecuteQuery,
27
+ ExecuteQueryCacheable,
26
28
  InsertAndEvictCacheType,
27
29
  SelectAliasedCacheableType,
28
30
  SelectAliasedDistinctCacheableType,
29
31
  SelectAliasedDistinctType,
30
32
  SelectAliasedType,
33
+ SelectAllDistinctFromAliasedType,
34
+ SelectAllDistinctFromCacheableAliasedType,
35
+ SelectAllFromAliasedType,
36
+ SelectAllFromCacheableAliasedType,
31
37
  UpdateAndEvictCacheType,
32
38
  } from "..";
33
39
  import {
34
40
  MySqlDeleteBase,
35
41
  MySqlInsertBuilder,
42
+ MySqlSelectBase,
36
43
  MySqlUpdateBuilder,
37
44
  } from "drizzle-orm/mysql-core/query-builders";
38
45
  import { MySqlRemoteQueryResultHKT } from "drizzle-orm/mysql-proxy";
46
+ import {
47
+ GetSelectTableName,
48
+ GetSelectTableSelection,
49
+ } from "drizzle-orm/query-builders/select.types";
50
+ import { SQLWrapper } from "drizzle-orm/sql/sql";
51
+ import type { MySqlQueryResultKind } from "drizzle-orm/mysql-core/session";
52
+ import type { WithBuilder } from "drizzle-orm/mysql-core/subquery";
53
+ import { WithSubquery } from "drizzle-orm/subquery";
39
54
 
40
55
  /**
41
56
  * Core interface for ForgeSQL operations.
@@ -55,14 +70,20 @@ export interface ForgeSqlOperation extends QueryBuilderForgeSql {
55
70
  getDrizzleQueryBuilder(): MySqlRemoteDatabase<Record<string, unknown>> & {
56
71
  selectAliased: SelectAliasedType;
57
72
  selectAliasedDistinct: SelectAliasedDistinctType;
73
+ executeQuery: ExecuteQuery;
58
74
  selectAliasedCacheable: SelectAliasedCacheableType;
59
75
  selectAliasedDistinctCacheable: SelectAliasedDistinctCacheableType;
76
+ executeQueryCacheable: ExecuteQueryCacheable;
60
77
  insertWithCacheContext: InsertAndEvictCacheType;
61
78
  insertAndEvictCache: InsertAndEvictCacheType;
62
79
  updateAndEvictCache: UpdateAndEvictCacheType;
63
80
  updateWithCacheContext: UpdateAndEvictCacheType;
64
81
  deleteAndEvictCache: DeleteAndEvictCacheType;
65
82
  deleteWithCacheContext: DeleteAndEvictCacheType;
83
+ selectFrom: SelectAllFromAliasedType;
84
+ selectDistinctFrom: SelectAllDistinctFromAliasedType;
85
+ selectFromCacheable: SelectAllFromCacheableAliasedType;
86
+ selectDistinctFromCacheable: SelectAllDistinctFromCacheableAliasedType;
66
87
  };
67
88
 
68
89
  /**
@@ -115,8 +136,10 @@ export interface QueryBuilderForgeSql {
115
136
  getDrizzleQueryBuilder(): MySqlRemoteDatabase<Record<string, unknown>> & {
116
137
  selectAliased: SelectAliasedType;
117
138
  selectAliasedDistinct: SelectAliasedDistinctType;
139
+ executeQuery: ExecuteQuery;
118
140
  selectAliasedCacheable: SelectAliasedCacheableType;
119
141
  selectAliasedDistinctCacheable: SelectAliasedDistinctCacheableType;
142
+ executeQueryCacheable: ExecuteQueryCacheable;
120
143
  insertWithCacheContext: InsertAndEvictCacheType;
121
144
  insertAndEvictCache: InsertAndEvictCacheType;
122
145
  updateAndEvictCache: UpdateAndEvictCacheType;
@@ -145,6 +168,31 @@ export interface QueryBuilderForgeSql {
145
168
  fields: TSelection,
146
169
  ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
147
170
 
171
+ /**
172
+ * Creates a select query builder for all columns from a table with field aliasing support.
173
+ * This is a convenience method that automatically selects all columns from the specified table.
174
+ *
175
+ * @template T - The type of the table
176
+ * @param table - The table to select from
177
+ * @returns Select query builder with all table columns and field aliasing support
178
+ * @example
179
+ * ```typescript
180
+ * const users = await forgeSQL.selectFrom(userTable).where(eq(userTable.id, 1));
181
+ * ```
182
+ */
183
+ selectFrom<T extends MySqlTable>(
184
+ table: T,
185
+ ): MySqlSelectBase<
186
+ GetSelectTableName<T>,
187
+ T["_"]["columns"] extends undefined ? GetSelectTableSelection<T> : T["_"]["columns"],
188
+ T["_"]["columns"] extends undefined ? "single" : "partial",
189
+ MySqlRemotePreparedQueryHKT,
190
+ GetSelectTableName<T> extends string ? Record<string & GetSelectTableName<T>, "not-null"> : {},
191
+ false,
192
+ never,
193
+ any
194
+ >;
195
+
148
196
  /**
149
197
  * Creates a distinct select query with unique field aliases to prevent field name collisions in joins.
150
198
  * This is particularly useful when working with Atlassian Forge SQL, which collapses fields with the same name in joined tables.
@@ -164,6 +212,30 @@ export interface QueryBuilderForgeSql {
164
212
  selectDistinct<TSelection extends SelectedFields>(
165
213
  fields: TSelection,
166
214
  ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
215
+ /**
216
+ * Creates a select distinct query builder for all columns from a table with field aliasing support.
217
+ * This is a convenience method that automatically selects all distinct columns from the specified table.
218
+ *
219
+ * @template T - The type of the table
220
+ * @param table - The table to select from
221
+ * @returns Select distinct query builder with all table columns and field aliasing support
222
+ * @example
223
+ * ```typescript
224
+ * const uniqueUsers = await forgeSQL.selectDistinctFrom(userTable).where(eq(userTable.status, 'active'));
225
+ * ```
226
+ */
227
+ selectDistinctFrom<T extends MySqlTable>(
228
+ table: T,
229
+ ): MySqlSelectBase<
230
+ GetSelectTableName<T>,
231
+ T["_"]["columns"] extends undefined ? GetSelectTableSelection<T> : T["_"]["columns"],
232
+ T["_"]["columns"] extends undefined ? "single" : "partial",
233
+ MySqlRemotePreparedQueryHKT,
234
+ GetSelectTableName<T> extends string ? Record<string & GetSelectTableName<T>, "not-null"> : {},
235
+ false,
236
+ never,
237
+ any
238
+ >;
167
239
 
168
240
  /**
169
241
  * Creates a cacheable select query with unique field aliases to prevent field name collisions in joins.
@@ -187,6 +259,33 @@ export interface QueryBuilderForgeSql {
187
259
  cacheTTL?: number,
188
260
  ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
189
261
 
262
+ /**
263
+ * Creates a cacheable select query builder for all columns from a table with field aliasing and caching support.
264
+ * This is a convenience method that automatically selects all columns from the specified table with caching enabled.
265
+ *
266
+ * @template T - The type of the table
267
+ * @param table - The table to select from
268
+ * @param cacheTTL - Optional cache TTL override (defaults to global cache TTL)
269
+ * @returns Select query builder with all table columns, field aliasing, and caching support
270
+ * @example
271
+ * ```typescript
272
+ * const users = await forgeSQL.selectCacheableFrom(userTable, 300).where(eq(userTable.id, 1));
273
+ * ```
274
+ */
275
+ selectCacheableFrom<T extends MySqlTable>(
276
+ table: T,
277
+ cacheTTL?: number,
278
+ ): MySqlSelectBase<
279
+ GetSelectTableName<T>,
280
+ T["_"]["columns"] extends undefined ? GetSelectTableSelection<T> : T["_"]["columns"],
281
+ T["_"]["columns"] extends undefined ? "single" : "partial",
282
+ MySqlRemotePreparedQueryHKT,
283
+ GetSelectTableName<T> extends string ? Record<string & GetSelectTableName<T>, "not-null"> : {},
284
+ false,
285
+ never,
286
+ any
287
+ >;
288
+
190
289
  /**
191
290
  * Creates a cacheable distinct select query with unique field aliases to prevent field name collisions in joins.
192
291
  * This is particularly useful when working with Atlassian Forge SQL, which collapses fields with the same name in joined tables.
@@ -209,6 +308,33 @@ export interface QueryBuilderForgeSql {
209
308
  cacheTTL?: number,
210
309
  ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
211
310
 
311
+ /**
312
+ * Creates a cacheable select distinct query builder for all columns from a table with field aliasing and caching support.
313
+ * This is a convenience method that automatically selects all distinct columns from the specified table with caching enabled.
314
+ *
315
+ * @template T - The type of the table
316
+ * @param table - The table to select from
317
+ * @param cacheTTL - Optional cache TTL override (defaults to global cache TTL)
318
+ * @returns Select distinct query builder with all table columns, field aliasing, and caching support
319
+ * @example
320
+ * ```typescript
321
+ * const uniqueUsers = await forgeSQL.selectDistinctCacheableFrom(userTable, 300).where(eq(userTable.status, 'active'));
322
+ * ```
323
+ */
324
+ selectDistinctCacheableFrom<T extends MySqlTable>(
325
+ table: T,
326
+ cacheTTL?: number,
327
+ ): MySqlSelectBase<
328
+ GetSelectTableName<T>,
329
+ T["_"]["columns"] extends undefined ? GetSelectTableSelection<T> : T["_"]["columns"],
330
+ T["_"]["columns"] extends undefined ? "single" : "partial",
331
+ MySqlRemotePreparedQueryHKT,
332
+ GetSelectTableName<T> extends string ? Record<string & GetSelectTableName<T>, "not-null"> : {},
333
+ false,
334
+ never,
335
+ any
336
+ >;
337
+
212
338
  /**
213
339
  * Creates an insert query builder.
214
340
  *
@@ -366,6 +492,98 @@ export interface QueryBuilderForgeSql {
366
492
  * ```
367
493
  */
368
494
  executeWithLocalCacheContextAndReturnValue<T>(cacheContext: () => Promise<T>): Promise<T>;
495
+
496
+ /**
497
+ * Executes a raw SQL query with local cache support.
498
+ * This method provides local caching for raw SQL queries within the current invocation context.
499
+ * Results are cached locally and will be returned from cache on subsequent identical queries.
500
+ *
501
+ * @param query - The SQL query to execute (SQLWrapper or string)
502
+ * @returns Promise with query results
503
+ * @example
504
+ * ```typescript
505
+ * // Using SQLWrapper
506
+ * const result = await forgeSQL.execute(sql`SELECT * FROM users WHERE id = ${userId}`);
507
+ *
508
+ * // Using string
509
+ * const result = await forgeSQL.execute("SELECT * FROM users WHERE status = 'active'");
510
+ * ```
511
+ */
512
+ execute(
513
+ query: SQLWrapper | string,
514
+ ): Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, unknown>>;
515
+
516
+ /**
517
+ * Executes a raw SQL query with both local and global cache support.
518
+ * This method provides comprehensive caching for raw SQL queries:
519
+ * - Local cache: Within the current invocation context
520
+ * - Global cache: Cross-invocation caching using @forge/kvs
521
+ *
522
+ * @param query - The SQL query to execute (SQLWrapper or string)
523
+ * @param cacheTtl - Optional cache TTL override (defaults to global cache TTL)
524
+ * @returns Promise with query results
525
+ * @example
526
+ * ```typescript
527
+ * // Using SQLWrapper with custom TTL
528
+ * const result = await forgeSQL.executeCacheable(sql`SELECT * FROM users WHERE id = ${userId}`, 300);
529
+ *
530
+ * // Using string with default TTL
531
+ * const result = await forgeSQL.executeCacheable("SELECT * FROM users WHERE status = 'active'");
532
+ * ```
533
+ */
534
+ executeCacheable(
535
+ query: SQLWrapper | string,
536
+ cacheTtl?: number,
537
+ ): Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, unknown>>;
538
+ /**
539
+ * Creates a Common Table Expression (CTE) builder for complex queries.
540
+ * CTEs allow you to define temporary named result sets that exist within the scope of a single query.
541
+ *
542
+ * @returns WithBuilder for creating CTEs
543
+ * @example
544
+ * ```typescript
545
+ * const withQuery = forgeSQL.$with('userStats').as(
546
+ * forgeSQL.select({ userId: users.id, count: sql<number>`count(*)` })
547
+ * .from(users)
548
+ * .groupBy(users.id)
549
+ * );
550
+ * ```
551
+ */
552
+ $with: WithBuilder;
553
+
554
+ /**
555
+ * Creates a query builder that uses Common Table Expressions (CTEs).
556
+ * CTEs allow you to define temporary named result sets that exist within the scope of a single query.
557
+ *
558
+ * @param queries - Array of CTE queries created with $with()
559
+ * @returns Query builder with CTE support
560
+ * @example
561
+ * ```typescript
562
+ * const withQuery = forgeSQL.$with('userStats').as(
563
+ * forgeSQL.select({ userId: users.id, count: sql<number>`count(*)` })
564
+ * .from(users)
565
+ * .groupBy(users.id)
566
+ * );
567
+ *
568
+ * const result = await forgeSQL.with(withQuery)
569
+ * .select({ userId: withQuery.userId, count: withQuery.count })
570
+ * .from(withQuery);
571
+ * ```
572
+ */
573
+ with(...queries: WithSubquery[]): {
574
+ select: {
575
+ (): MySqlSelectBuilder<undefined, MySqlRemotePreparedQueryHKT>;
576
+ <TSelection extends SelectedFields>(
577
+ fields: TSelection,
578
+ ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
579
+ };
580
+ selectDistinct: {
581
+ (): MySqlSelectBuilder<undefined, MySqlRemotePreparedQueryHKT>;
582
+ <TSelection extends SelectedFields>(
583
+ fields: TSelection,
584
+ ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
585
+ };
586
+ };
369
587
  }
370
588
 
371
589
  /**