forge-sql-orm 2.1.0 → 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.
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.1",
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,7 +144,7 @@ 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 () => {
147
+ await cacheApplicationContext.run(cacheApplicationContext.getStore() ?? { tables: new Set<string>() }, async () => {
146
148
  try {
147
149
  return await cacheContext();
148
150
  } finally {
@@ -157,12 +159,12 @@ class ForgeSQLORMImpl implements ForgeSqlOperation {
157
159
  /**
158
160
  * Executes operations within a local cache context and returns a value.
159
161
  * This provides in-memory caching for select queries within a single request scope.
160
- *
162
+ *
161
163
  * @param cacheContext - Function containing operations that will benefit from local caching
162
164
  * @returns Promise that resolves to the return value of the cacheContext function
163
165
  */
164
166
  async executeWithLocalCacheContextAndReturnValue<T>(cacheContext: () => Promise<T>): Promise<T> {
165
- return await localCacheApplicationContext.run({ cache: {} }, async () => {
167
+ return await localCacheApplicationContext.run(localCacheApplicationContext.getStore() ?? { cache: {} }, async () => {
166
168
  return await cacheContext();
167
169
  });
168
170
  }
@@ -170,7 +172,7 @@ class ForgeSQLORMImpl implements ForgeSqlOperation {
170
172
  /**
171
173
  * Executes operations within a local cache context.
172
174
  * This provides in-memory caching for select queries within a single request scope.
173
- *
175
+ *
174
176
  * @param cacheContext - Function containing operations that will benefit from local caching
175
177
  * @returns Promise that resolves when all operations are complete
176
178
  */
@@ -440,6 +442,155 @@ class ForgeSQLORMImpl implements ForgeSqlOperation {
440
442
  }
441
443
  return this.drizzle.selectAliasedDistinctCacheable(fields, cacheTTL);
442
444
  }
445
+
446
+ /**
447
+ * Creates a select query builder for all columns from a table with field aliasing support.
448
+ * This is a convenience method that automatically selects all columns from the specified table.
449
+ *
450
+ * @template T - The type of the table
451
+ * @param table - The table to select from
452
+ * @returns Select query builder with all table columns and field aliasing support
453
+ * @example
454
+ * ```typescript
455
+ * const users = await forgeSQL.selectFrom(userTable).where(eq(userTable.id, 1));
456
+ * ```
457
+ */
458
+ selectFrom<T extends MySqlTable>(table: T) {
459
+ return this.drizzle.selectFrom(table);
460
+ }
461
+
462
+ /**
463
+ * Creates a select distinct query builder for all columns from a table with field aliasing support.
464
+ * This is a convenience method that automatically selects all distinct columns from the specified table.
465
+ *
466
+ * @template T - The type of the table
467
+ * @param table - The table to select from
468
+ * @returns Select distinct query builder with all table columns and field aliasing support
469
+ * @example
470
+ * ```typescript
471
+ * const uniqueUsers = await forgeSQL.selectDistinctFrom(userTable).where(eq(userTable.status, 'active'));
472
+ * ```
473
+ */
474
+ selectDistinctFrom<T extends MySqlTable>(table: T) {
475
+ return this.drizzle.selectDistinctFrom(table);
476
+ }
477
+
478
+ /**
479
+ * Creates a cacheable select query builder for all columns from a table with field aliasing and caching support.
480
+ * This is a convenience method that automatically selects all columns from the specified table with caching enabled.
481
+ *
482
+ * @template T - The type of the table
483
+ * @param table - The table to select from
484
+ * @param cacheTTL - Optional cache TTL override (defaults to global cache TTL)
485
+ * @returns Select query builder with all table columns, field aliasing, and caching support
486
+ * @example
487
+ * ```typescript
488
+ * const users = await forgeSQL.selectCacheableFrom(userTable, 300).where(eq(userTable.id, 1));
489
+ * ```
490
+ */
491
+ selectCacheableFrom<T extends MySqlTable>(table: T, cacheTTL?: number) {
492
+ return this.drizzle.selectFromCacheable(table, cacheTTL);
493
+ }
494
+
495
+ /**
496
+ * Creates a cacheable select distinct query builder for all columns from a table with field aliasing and caching support.
497
+ * This is a convenience method that automatically selects all distinct columns from the specified table with caching enabled.
498
+ *
499
+ * @template T - The type of the table
500
+ * @param table - The table to select from
501
+ * @param cacheTTL - Optional cache TTL override (defaults to global cache TTL)
502
+ * @returns Select distinct query builder with all table columns, field aliasing, and caching support
503
+ * @example
504
+ * ```typescript
505
+ * const uniqueUsers = await forgeSQL.selectDistinctCacheableFrom(userTable, 300).where(eq(userTable.status, 'active'));
506
+ * ```
507
+ */
508
+ selectDistinctCacheableFrom<T extends MySqlTable>(table: T, cacheTTL?: number) {
509
+ return this.drizzle.selectDistinctFromCacheable(table, cacheTTL);
510
+ }
511
+
512
+ /**
513
+ * Executes a raw SQL query with local cache support.
514
+ * This method provides local caching for raw SQL queries within the current invocation context.
515
+ * Results are cached locally and will be returned from cache on subsequent identical queries.
516
+ *
517
+ * @param query - The SQL query to execute (SQLWrapper or string)
518
+ * @returns Promise with query results
519
+ * @example
520
+ * ```typescript
521
+ * // Using SQLWrapper
522
+ * const result = await forgeSQL.execute(sql`SELECT * FROM users WHERE id = ${userId}`);
523
+ *
524
+ * // Using string
525
+ * const result = await forgeSQL.execute("SELECT * FROM users WHERE status = 'active'");
526
+ * ```
527
+ */
528
+ execute(query: SQLWrapper | string) {
529
+ return this.drizzle.executeQuery(query);
530
+ }
531
+
532
+ /**
533
+ * Executes a raw SQL query with both local and global cache support.
534
+ * This method provides comprehensive caching for raw SQL queries:
535
+ * - Local cache: Within the current invocation context
536
+ * - Global cache: Cross-invocation caching using @forge/kvs
537
+ *
538
+ * @param query - The SQL query to execute (SQLWrapper or string)
539
+ * @param cacheTtl - Optional cache TTL override (defaults to global cache TTL)
540
+ * @returns Promise with query results
541
+ * @example
542
+ * ```typescript
543
+ * // Using SQLWrapper with custom TTL
544
+ * const result = await forgeSQL.executeCacheable(sql`SELECT * FROM users WHERE id = ${userId}`, 300);
545
+ *
546
+ * // Using string with default TTL
547
+ * const result = await forgeSQL.executeCacheable("SELECT * FROM users WHERE status = 'active'");
548
+ * ```
549
+ */
550
+ executeCacheable(query: SQLWrapper | string, cacheTtl?: number) {
551
+ return this.drizzle.executeQueryCacheable(query, cacheTtl);
552
+ }
553
+
554
+ /**
555
+ * Creates a Common Table Expression (CTE) builder for complex queries.
556
+ * CTEs allow you to define temporary named result sets that exist within the scope of a single query.
557
+ *
558
+ * @returns WithBuilder for creating CTEs
559
+ * @example
560
+ * ```typescript
561
+ * const withQuery = forgeSQL.$with('userStats').as(
562
+ * forgeSQL.select({ userId: users.id, count: sql<number>`count(*)` })
563
+ * .from(users)
564
+ * .groupBy(users.id)
565
+ * );
566
+ * ```
567
+ */
568
+ get $with() {
569
+ return this.drizzle.$with;
570
+ }
571
+
572
+ /**
573
+ * Creates a query builder that uses Common Table Expressions (CTEs).
574
+ * CTEs allow you to define temporary named result sets that exist within the scope of a single query.
575
+ *
576
+ * @param queries - Array of CTE queries created with $with()
577
+ * @returns Query builder with CTE support
578
+ * @example
579
+ * ```typescript
580
+ * const withQuery = forgeSQL.$with('userStats').as(
581
+ * forgeSQL.select({ userId: users.id, count: sql<number>`count(*)` })
582
+ * .from(users)
583
+ * .groupBy(users.id)
584
+ * );
585
+ *
586
+ * const result = await forgeSQL.with(withQuery)
587
+ * .select({ userId: withQuery.userId, count: withQuery.count })
588
+ * .from(withQuery);
589
+ * ```
590
+ */
591
+ with(...queries: WithSubquery[]) {
592
+ return this.drizzle.with(...queries);
593
+ }
443
594
  }
444
595
 
445
596
  /**
@@ -467,6 +618,72 @@ class ForgeSQLORM implements ForgeSqlOperation {
467
618
  return this.ormInstance.selectDistinctCacheable(fields, cacheTTL);
468
619
  }
469
620
 
621
+ /**
622
+ * Creates a select query builder for all columns from a table with field aliasing support.
623
+ * This is a convenience method that automatically selects all columns from the specified table.
624
+ *
625
+ * @template T - The type of the table
626
+ * @param table - The table to select from
627
+ * @returns Select query builder with all table columns and field aliasing support
628
+ * @example
629
+ * ```typescript
630
+ * const users = await forgeSQL.selectFrom(userTable).where(eq(userTable.id, 1));
631
+ * ```
632
+ */
633
+ selectFrom<T extends MySqlTable>(table: T) {
634
+ return this.ormInstance.getDrizzleQueryBuilder().selectFrom(table);
635
+ }
636
+
637
+ /**
638
+ * Creates a select distinct query builder for all columns from a table with field aliasing support.
639
+ * This is a convenience method that automatically selects all distinct columns from the specified table.
640
+ *
641
+ * @template T - The type of the table
642
+ * @param table - The table to select from
643
+ * @returns Select distinct query builder with all table columns and field aliasing support
644
+ * @example
645
+ * ```typescript
646
+ * const uniqueUsers = await forgeSQL.selectDistinctFrom(userTable).where(eq(userTable.status, 'active'));
647
+ * ```
648
+ */
649
+ selectDistinctFrom<T extends MySqlTable>(table: T) {
650
+ return this.ormInstance.getDrizzleQueryBuilder().selectDistinctFrom(table);
651
+ }
652
+
653
+ /**
654
+ * Creates a cacheable select query builder for all columns from a table with field aliasing and caching support.
655
+ * This is a convenience method that automatically selects all columns from the specified table with caching enabled.
656
+ *
657
+ * @template T - The type of the table
658
+ * @param table - The table to select from
659
+ * @param cacheTTL - Optional cache TTL override (defaults to global cache TTL)
660
+ * @returns Select query builder with all table columns, field aliasing, and caching support
661
+ * @example
662
+ * ```typescript
663
+ * const users = await forgeSQL.selectCacheableFrom(userTable, 300).where(eq(userTable.id, 1));
664
+ * ```
665
+ */
666
+ selectCacheableFrom<T extends MySqlTable>(table: T, cacheTTL?: number) {
667
+ return this.ormInstance.getDrizzleQueryBuilder().selectFromCacheable(table, cacheTTL);
668
+ }
669
+
670
+ /**
671
+ * Creates a cacheable select distinct query builder for all columns from a table with field aliasing and caching support.
672
+ * This is a convenience method that automatically selects all distinct columns from the specified table with caching enabled.
673
+ *
674
+ * @template T - The type of the table
675
+ * @param table - The table to select from
676
+ * @param cacheTTL - Optional cache TTL override (defaults to global cache TTL)
677
+ * @returns Select distinct query builder with all table columns, field aliasing, and caching support
678
+ * @example
679
+ * ```typescript
680
+ * const uniqueUsers = await forgeSQL.selectDistinctCacheableFrom(userTable, 300).where(eq(userTable.status, 'active'));
681
+ * ```
682
+ */
683
+ selectDistinctCacheableFrom<T extends MySqlTable>(table: T, cacheTTL?: number) {
684
+ return this.ormInstance.getDrizzleQueryBuilder().selectDistinctFromCacheable(table, cacheTTL);
685
+ }
686
+
470
687
  executeWithCacheContext(cacheContext: () => Promise<void>): Promise<void> {
471
688
  return this.ormInstance.executeWithCacheContext(cacheContext);
472
689
  }
@@ -476,7 +693,7 @@ class ForgeSQLORM implements ForgeSqlOperation {
476
693
  /**
477
694
  * Executes operations within a local cache context.
478
695
  * This provides in-memory caching for select queries within a single request scope.
479
- *
696
+ *
480
697
  * @param cacheContext - Function containing operations that will benefit from local caching
481
698
  * @returns Promise that resolves when all operations are complete
482
699
  */
@@ -487,7 +704,7 @@ class ForgeSQLORM implements ForgeSqlOperation {
487
704
  /**
488
705
  * Executes operations within a local cache context and returns a value.
489
706
  * This provides in-memory caching for select queries within a single request scope.
490
- *
707
+ *
491
708
  * @param cacheContext - Function containing operations that will benefit from local caching
492
709
  * @returns Promise that resolves to the return value of the cacheContext function
493
710
  */
@@ -669,6 +886,89 @@ class ForgeSQLORM implements ForgeSqlOperation {
669
886
  getDrizzleQueryBuilder() {
670
887
  return this.ormInstance.getDrizzleQueryBuilder();
671
888
  }
889
+
890
+ /**
891
+ * Executes a raw SQL query with local cache support.
892
+ * This method provides local caching for raw SQL queries within the current invocation context.
893
+ * Results are cached locally and will be returned from cache on subsequent identical queries.
894
+ *
895
+ * @param query - The SQL query to execute (SQLWrapper or string)
896
+ * @returns Promise with query results
897
+ * @example
898
+ * ```typescript
899
+ * // Using SQLWrapper
900
+ * const result = await forgeSQL.execute(sql`SELECT * FROM users WHERE id = ${userId}`);
901
+ *
902
+ * // Using string
903
+ * const result = await forgeSQL.execute("SELECT * FROM users WHERE status = 'active'");
904
+ * ```
905
+ */
906
+ execute(query: SQLWrapper | string) {
907
+ return this.ormInstance.getDrizzleQueryBuilder().executeQuery(query);
908
+ }
909
+
910
+ /**
911
+ * Executes a raw SQL query with both local and global cache support.
912
+ * This method provides comprehensive caching for raw SQL queries:
913
+ * - Local cache: Within the current invocation context
914
+ * - Global cache: Cross-invocation caching using @forge/kvs
915
+ *
916
+ * @param query - The SQL query to execute (SQLWrapper or string)
917
+ * @param cacheTtl - Optional cache TTL override (defaults to global cache TTL)
918
+ * @returns Promise with query results
919
+ * @example
920
+ * ```typescript
921
+ * // Using SQLWrapper with custom TTL
922
+ * const result = await forgeSQL.executeCacheable(sql`SELECT * FROM users WHERE id = ${userId}`, 300);
923
+ *
924
+ * // Using string with default TTL
925
+ * const result = await forgeSQL.executeCacheable("SELECT * FROM users WHERE status = 'active'");
926
+ * ```
927
+ */
928
+ executeCacheable(query: SQLWrapper | string, cacheTtl?: number) {
929
+ return this.ormInstance.getDrizzleQueryBuilder().executeQueryCacheable(query, cacheTtl);
930
+ }
931
+
932
+ /**
933
+ * Creates a Common Table Expression (CTE) builder for complex queries.
934
+ * CTEs allow you to define temporary named result sets that exist within the scope of a single query.
935
+ *
936
+ * @returns WithBuilder for creating CTEs
937
+ * @example
938
+ * ```typescript
939
+ * const withQuery = forgeSQL.$with('userStats').as(
940
+ * forgeSQL.select({ userId: users.id, count: sql<number>`count(*)` })
941
+ * .from(users)
942
+ * .groupBy(users.id)
943
+ * );
944
+ * ```
945
+ */
946
+ get $with() {
947
+ return this.ormInstance.getDrizzleQueryBuilder().$with;
948
+ }
949
+
950
+ /**
951
+ * Creates a query builder that uses Common Table Expressions (CTEs).
952
+ * CTEs allow you to define temporary named result sets that exist within the scope of a single query.
953
+ *
954
+ * @param queries - Array of CTE queries created with $with()
955
+ * @returns Query builder with CTE support
956
+ * @example
957
+ * ```typescript
958
+ * const withQuery = forgeSQL.$with('userStats').as(
959
+ * forgeSQL.select({ userId: users.id, count: sql<number>`count(*)` })
960
+ * .from(users)
961
+ * .groupBy(users.id)
962
+ * );
963
+ *
964
+ * const result = await forgeSQL.with(withQuery)
965
+ * .select({ userId: withQuery.userId, count: withQuery.count })
966
+ * .from(withQuery);
967
+ * ```
968
+ */
969
+ with(...queries: WithSubquery[]) {
970
+ return this.ormInstance.getDrizzleQueryBuilder().with(...queries);
971
+ }
672
972
  }
673
973
 
674
974
  export default ForgeSQLORM;
@@ -22,20 +22,27 @@ import {
22
22
  } from "./SystemTables";
23
23
  import { ForgeSQLCacheOperations } from "./ForgeSQLCacheOperations";
24
24
  import {
25
- DeleteAndEvictCacheType,
26
- InsertAndEvictCacheType,
27
- SelectAliasedCacheableType,
28
- SelectAliasedDistinctCacheableType,
29
- SelectAliasedDistinctType,
30
- SelectAliasedType,
31
- UpdateAndEvictCacheType,
25
+ DeleteAndEvictCacheType, ExecuteQuery, ExecuteQueryCacheable,
26
+ InsertAndEvictCacheType,
27
+ SelectAliasedCacheableType,
28
+ SelectAliasedDistinctCacheableType,
29
+ SelectAliasedDistinctType,
30
+ SelectAliasedType, SelectAllDistinctFromAliasedType,
31
+ SelectAllDistinctFromCacheableAliasedType, SelectAllFromAliasedType, SelectAllFromCacheableAliasedType,
32
+ UpdateAndEvictCacheType,
32
33
  } from "..";
33
34
  import {
34
35
  MySqlDeleteBase,
35
36
  MySqlInsertBuilder,
37
+ MySqlSelectBase,
36
38
  MySqlUpdateBuilder,
37
39
  } from "drizzle-orm/mysql-core/query-builders";
38
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";
39
46
 
40
47
  /**
41
48
  * Core interface for ForgeSQL operations.
@@ -55,14 +62,20 @@ export interface ForgeSqlOperation extends QueryBuilderForgeSql {
55
62
  getDrizzleQueryBuilder(): MySqlRemoteDatabase<Record<string, unknown>> & {
56
63
  selectAliased: SelectAliasedType;
57
64
  selectAliasedDistinct: SelectAliasedDistinctType;
58
- selectAliasedCacheable: SelectAliasedCacheableType;
59
- selectAliasedDistinctCacheable: SelectAliasedDistinctCacheableType;
60
- insertWithCacheContext: InsertAndEvictCacheType;
61
- insertAndEvictCache: InsertAndEvictCacheType;
62
- updateAndEvictCache: UpdateAndEvictCacheType;
63
- updateWithCacheContext: UpdateAndEvictCacheType;
64
- deleteAndEvictCache: DeleteAndEvictCacheType;
65
- deleteWithCacheContext: DeleteAndEvictCacheType;
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;
66
79
  };
67
80
 
68
81
  /**
@@ -115,8 +128,10 @@ export interface QueryBuilderForgeSql {
115
128
  getDrizzleQueryBuilder(): MySqlRemoteDatabase<Record<string, unknown>> & {
116
129
  selectAliased: SelectAliasedType;
117
130
  selectAliasedDistinct: SelectAliasedDistinctType;
131
+ executeQuery: ExecuteQuery;
118
132
  selectAliasedCacheable: SelectAliasedCacheableType;
119
133
  selectAliasedDistinctCacheable: SelectAliasedDistinctCacheableType;
134
+ executeQueryCacheable: ExecuteQueryCacheable;
120
135
  insertWithCacheContext: InsertAndEvictCacheType;
121
136
  insertAndEvictCache: InsertAndEvictCacheType;
122
137
  updateAndEvictCache: UpdateAndEvictCacheType;
@@ -146,6 +161,22 @@ export interface QueryBuilderForgeSql {
146
161
  ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
147
162
 
148
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
+ /**
149
180
  * Creates a distinct select query with unique field aliases to prevent field name collisions in joins.
150
181
  * This is particularly useful when working with Atlassian Forge SQL, which collapses fields with the same name in joined tables.
151
182
  *
@@ -164,6 +195,21 @@ export interface QueryBuilderForgeSql {
164
195
  selectDistinct<TSelection extends SelectedFields>(
165
196
  fields: TSelection,
166
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>;
167
213
 
168
214
  /**
169
215
  * Creates a cacheable select query with unique field aliases to prevent field name collisions in joins.
@@ -187,6 +233,24 @@ export interface QueryBuilderForgeSql {
187
233
  cacheTTL?: number,
188
234
  ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
189
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
+
190
254
  /**
191
255
  * Creates a cacheable distinct select query with unique field aliases to prevent field name collisions in joins.
192
256
  * This is particularly useful when working with Atlassian Forge SQL, which collapses fields with the same name in joined tables.
@@ -209,7 +273,25 @@ export interface QueryBuilderForgeSql {
209
273
  cacheTTL?: number,
210
274
  ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
211
275
 
212
- /**
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
+ /**
213
295
  * Creates an insert query builder.
214
296
  *
215
297
  * ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
@@ -366,6 +448,89 @@ export interface QueryBuilderForgeSql {
366
448
  * ```
367
449
  */
368
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
+ }
369
534
  }
370
535
 
371
536
  /**