forge-sql-orm 2.1.12 → 2.1.13
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/README.md +662 -548
- package/dist/core/ForgeSQLAnalyseOperations.d.ts.map +1 -1
- package/dist/core/ForgeSQLAnalyseOperations.js +257 -0
- package/dist/core/ForgeSQLAnalyseOperations.js.map +1 -0
- package/dist/core/ForgeSQLCacheOperations.js +172 -0
- package/dist/core/ForgeSQLCacheOperations.js.map +1 -0
- package/dist/core/ForgeSQLCrudOperations.js +349 -0
- package/dist/core/ForgeSQLCrudOperations.js.map +1 -0
- package/dist/core/ForgeSQLORM.js +1191 -0
- package/dist/core/ForgeSQLORM.js.map +1 -0
- package/dist/core/ForgeSQLQueryBuilder.js +77 -0
- package/dist/core/ForgeSQLQueryBuilder.js.map +1 -0
- package/dist/core/ForgeSQLSelectOperations.js +81 -0
- package/dist/core/ForgeSQLSelectOperations.js.map +1 -0
- package/dist/core/SystemTables.js +258 -0
- package/dist/core/SystemTables.js.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/drizzle/extensions/additionalActions.d.ts.map +1 -1
- package/dist/lib/drizzle/extensions/additionalActions.js +527 -0
- package/dist/lib/drizzle/extensions/additionalActions.js.map +1 -0
- package/dist/utils/cacheContextUtils.d.ts.map +1 -1
- package/dist/utils/cacheContextUtils.js +198 -0
- package/dist/utils/cacheContextUtils.js.map +1 -0
- package/dist/utils/cacheUtils.d.ts.map +1 -1
- package/dist/utils/cacheUtils.js +383 -0
- package/dist/utils/cacheUtils.js.map +1 -0
- package/dist/utils/forgeDriver.d.ts.map +1 -1
- package/dist/utils/forgeDriver.js +139 -0
- package/dist/utils/forgeDriver.js.map +1 -0
- package/dist/utils/forgeDriverProxy.js +68 -0
- package/dist/utils/forgeDriverProxy.js.map +1 -0
- package/dist/utils/metadataContextUtils.js +28 -0
- package/dist/utils/metadataContextUtils.js.map +1 -0
- package/dist/utils/requestTypeContextUtils.js +10 -0
- package/dist/utils/requestTypeContextUtils.js.map +1 -0
- package/dist/utils/sqlHints.js +52 -0
- package/dist/utils/sqlHints.js.map +1 -0
- package/dist/utils/sqlUtils.d.ts.map +1 -1
- package/dist/utils/sqlUtils.js +590 -0
- package/dist/utils/sqlUtils.js.map +1 -0
- package/dist/webtriggers/applyMigrationsWebTrigger.js +77 -0
- package/dist/webtriggers/applyMigrationsWebTrigger.js.map +1 -0
- package/dist/webtriggers/clearCacheSchedulerTrigger.js +83 -0
- package/dist/webtriggers/clearCacheSchedulerTrigger.js.map +1 -0
- package/dist/webtriggers/dropMigrationWebTrigger.js +54 -0
- package/dist/webtriggers/dropMigrationWebTrigger.js.map +1 -0
- package/dist/webtriggers/dropTablesMigrationWebTrigger.js +54 -0
- package/dist/webtriggers/dropTablesMigrationWebTrigger.js.map +1 -0
- package/dist/webtriggers/fetchSchemaWebTrigger.js +82 -0
- package/dist/webtriggers/fetchSchemaWebTrigger.js.map +1 -0
- package/dist/webtriggers/index.js +40 -0
- package/dist/webtriggers/index.js.map +1 -0
- package/dist/webtriggers/slowQuerySchedulerTrigger.js +80 -0
- package/dist/webtriggers/slowQuerySchedulerTrigger.js.map +1 -0
- package/package.json +28 -23
- package/src/core/ForgeSQLAnalyseOperations.ts +3 -2
- package/src/lib/drizzle/extensions/additionalActions.ts +11 -0
- package/src/utils/cacheContextUtils.ts +9 -6
- package/src/utils/cacheUtils.ts +6 -4
- package/src/utils/forgeDriver.ts +3 -7
- package/src/utils/sqlUtils.ts +33 -34
- package/dist/ForgeSQLORM.js +0 -3922
- package/dist/ForgeSQLORM.js.map +0 -1
- package/dist/ForgeSQLORM.mjs +0 -3905
- package/dist/ForgeSQLORM.mjs.map +0 -1
|
@@ -0,0 +1,1191 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const ForgeSQLCrudOperations_1 = require("./ForgeSQLCrudOperations");
|
|
4
|
+
const ForgeSQLSelectOperations_1 = require("./ForgeSQLSelectOperations");
|
|
5
|
+
const mysql_proxy_1 = require("drizzle-orm/mysql-proxy");
|
|
6
|
+
const forgeDriverProxy_1 = require("../utils/forgeDriverProxy");
|
|
7
|
+
const additionalActions_1 = require("../lib/drizzle/extensions/additionalActions");
|
|
8
|
+
const ForgeSQLAnalyseOperations_1 = require("./ForgeSQLAnalyseOperations");
|
|
9
|
+
const ForgeSQLCacheOperations_1 = require("./ForgeSQLCacheOperations");
|
|
10
|
+
const cacheContextUtils_1 = require("../utils/cacheContextUtils");
|
|
11
|
+
const cacheUtils_1 = require("../utils/cacheUtils");
|
|
12
|
+
const metadataContextUtils_1 = require("../utils/metadataContextUtils");
|
|
13
|
+
const requestTypeContextUtils_1 = require("../utils/requestTypeContextUtils");
|
|
14
|
+
/**
|
|
15
|
+
* Implementation of ForgeSQLORM that uses Drizzle ORM for query building.
|
|
16
|
+
* This class provides a bridge between Forge SQL and Drizzle ORM, allowing
|
|
17
|
+
* to use Drizzle's query builder while executing queries through Forge SQL.
|
|
18
|
+
*/
|
|
19
|
+
class ForgeSQLORMImpl {
|
|
20
|
+
static instance = null;
|
|
21
|
+
drizzle;
|
|
22
|
+
crudOperations;
|
|
23
|
+
fetchOperations;
|
|
24
|
+
analyzeOperations;
|
|
25
|
+
cacheOperations;
|
|
26
|
+
options;
|
|
27
|
+
/**
|
|
28
|
+
* Private constructor to enforce singleton behavior.
|
|
29
|
+
* @param options - Options for configuring ForgeSQL ORM behavior.
|
|
30
|
+
*/
|
|
31
|
+
constructor(options) {
|
|
32
|
+
try {
|
|
33
|
+
const newOptions = options ?? {
|
|
34
|
+
logRawSqlQuery: false,
|
|
35
|
+
logCache: false,
|
|
36
|
+
disableOptimisticLocking: false,
|
|
37
|
+
cacheWrapTable: true,
|
|
38
|
+
cacheTTL: 120,
|
|
39
|
+
cacheEntityQueryName: "sql",
|
|
40
|
+
cacheEntityExpirationName: "expiration",
|
|
41
|
+
cacheEntityDataName: "data",
|
|
42
|
+
};
|
|
43
|
+
this.options = newOptions;
|
|
44
|
+
if (newOptions.logRawSqlQuery) {
|
|
45
|
+
// eslint-disable-next-line no-console
|
|
46
|
+
console.debug("Initializing ForgeSQLORM...");
|
|
47
|
+
}
|
|
48
|
+
// Initialize Drizzle instance with our custom driver
|
|
49
|
+
const proxiedDriver = (0, forgeDriverProxy_1.createForgeDriverProxy)(this, newOptions.hints, newOptions.logRawSqlQuery);
|
|
50
|
+
this.drizzle = (0, additionalActions_1.patchDbWithSelectAliased)((0, mysql_proxy_1.drizzle)(proxiedDriver, { logger: newOptions.logRawSqlQuery }), newOptions);
|
|
51
|
+
this.crudOperations = new ForgeSQLCrudOperations_1.ForgeSQLCrudOperations(this, newOptions);
|
|
52
|
+
this.fetchOperations = new ForgeSQLSelectOperations_1.ForgeSQLSelectOperations(newOptions);
|
|
53
|
+
this.analyzeOperations = new ForgeSQLAnalyseOperations_1.ForgeSQLAnalyseOperation(this);
|
|
54
|
+
this.cacheOperations = new ForgeSQLCacheOperations_1.ForgeSQLCacheOperations(newOptions, this);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
// eslint-disable-next-line no-console
|
|
58
|
+
console.error("ForgeSQLORM initialization failed:", error);
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Executes a query and provides access to execution metadata with performance monitoring.
|
|
64
|
+
* This method allows you to capture detailed information about query execution
|
|
65
|
+
* including database execution time, response size, and query analysis capabilities.
|
|
66
|
+
*
|
|
67
|
+
* The method aggregates metrics across all database operations within the query function,
|
|
68
|
+
* making it ideal for monitoring resolver performance and detecting performance issues.
|
|
69
|
+
*
|
|
70
|
+
* @template T - The return type of the query
|
|
71
|
+
* @param query - A function that returns a Promise with the query result. Can contain multiple database operations.
|
|
72
|
+
* @param onMetadata - Callback function that receives aggregated execution metadata
|
|
73
|
+
* @param onMetadata.totalDbExecutionTime - Total database execution time across all operations in the query function (in milliseconds)
|
|
74
|
+
* @param onMetadata.totalResponseSize - Total response size across all operations (in bytes)
|
|
75
|
+
* @param onMetadata.printQueries - Function to analyze and print query execution plans from CLUSTER_STATEMENTS_SUMMARY
|
|
76
|
+
* @returns Promise with the query result
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* // Basic usage with performance monitoring
|
|
81
|
+
* const result = await forgeSQL.executeWithMetadata(
|
|
82
|
+
* async () => {
|
|
83
|
+
* const users = await forgeSQL.selectFrom(usersTable);
|
|
84
|
+
* const orders = await forgeSQL.selectFrom(ordersTable).where(eq(ordersTable.userId, usersTable.id));
|
|
85
|
+
* return { users, orders };
|
|
86
|
+
* },
|
|
87
|
+
* (totalDbExecutionTime, totalResponseSize, printQueries) => {
|
|
88
|
+
* const threshold = 500; // ms baseline for this resolver
|
|
89
|
+
*
|
|
90
|
+
* if (totalDbExecutionTime > threshold * 1.5) {
|
|
91
|
+
* console.warn(`[Performance Warning] Resolver exceeded DB time: ${totalDbExecutionTime} ms`);
|
|
92
|
+
* await printQueries(); // Analyze and print query execution plans
|
|
93
|
+
* } else if (totalDbExecutionTime > threshold) {
|
|
94
|
+
* console.debug(`[Performance Debug] High DB time: ${totalDbExecutionTime} ms`);
|
|
95
|
+
* }
|
|
96
|
+
*
|
|
97
|
+
* console.log(`DB response size: ${totalResponseSize} bytes`);
|
|
98
|
+
* }
|
|
99
|
+
* );
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```typescript
|
|
104
|
+
* // Resolver with performance monitoring
|
|
105
|
+
* resolver.define("fetch", async (req: Request) => {
|
|
106
|
+
* try {
|
|
107
|
+
* return await forgeSQL.executeWithMetadata(
|
|
108
|
+
* async () => {
|
|
109
|
+
* // Resolver logic with multiple queries
|
|
110
|
+
* const users = await forgeSQL.selectFrom(demoUsers);
|
|
111
|
+
* const orders = await forgeSQL.selectFrom(demoOrders)
|
|
112
|
+
* .where(eq(demoOrders.userId, demoUsers.id));
|
|
113
|
+
* return { users, orders };
|
|
114
|
+
* },
|
|
115
|
+
* async (totalDbExecutionTime, totalResponseSize, printQueries) => {
|
|
116
|
+
* const threshold = 500; // ms baseline for this resolver
|
|
117
|
+
*
|
|
118
|
+
* if (totalDbExecutionTime > threshold * 1.5) {
|
|
119
|
+
* console.warn(`[Performance Warning fetch] Resolver exceeded DB time: ${totalDbExecutionTime} ms`);
|
|
120
|
+
* await printQueries(); // Optionally log or capture diagnostics for further analysis
|
|
121
|
+
* } else if (totalDbExecutionTime > threshold) {
|
|
122
|
+
* console.debug(`[Performance Debug] High DB time: ${totalDbExecutionTime} ms`);
|
|
123
|
+
* }
|
|
124
|
+
*
|
|
125
|
+
* console.log(`DB response size: ${totalResponseSize} bytes`);
|
|
126
|
+
* }
|
|
127
|
+
* );
|
|
128
|
+
* } catch (e) {
|
|
129
|
+
* const error = e?.cause?.debug?.sqlMessage ?? e?.cause;
|
|
130
|
+
* console.error(error, e);
|
|
131
|
+
* throw error;
|
|
132
|
+
* }
|
|
133
|
+
* });
|
|
134
|
+
* ```
|
|
135
|
+
*
|
|
136
|
+
* @note **Important**: When multiple resolvers are running concurrently, their query data may also appear in `printQueries()` analysis, as it queries the global `CLUSTER_STATEMENTS_SUMMARY` table.
|
|
137
|
+
*/
|
|
138
|
+
async executeWithMetadata(query, onMetadata) {
|
|
139
|
+
return metadataContextUtils_1.metadataQueryContext.run({
|
|
140
|
+
totalDbExecutionTime: 0,
|
|
141
|
+
totalResponseSize: 0,
|
|
142
|
+
beginTime: new Date(),
|
|
143
|
+
forgeSQLORM: this,
|
|
144
|
+
printQueriesWithPlan: async () => {
|
|
145
|
+
return;
|
|
146
|
+
},
|
|
147
|
+
}, async () => {
|
|
148
|
+
const result = await query();
|
|
149
|
+
const metadata = await (0, metadataContextUtils_1.getLastestMetadata)();
|
|
150
|
+
try {
|
|
151
|
+
if (metadata) {
|
|
152
|
+
await onMetadata(metadata.totalDbExecutionTime, metadata.totalResponseSize, metadata.printQueriesWithPlan);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch (e) {
|
|
156
|
+
// eslint-disable-next-line no-console
|
|
157
|
+
console.error("[ForgeSQLORM][executeWithMetadata] Failed to run onMetadata callback", {
|
|
158
|
+
errorMessage: e?.message,
|
|
159
|
+
errorStack: e?.stack,
|
|
160
|
+
totalDbExecutionTime: metadata?.totalDbExecutionTime,
|
|
161
|
+
totalResponseSize: metadata?.totalResponseSize,
|
|
162
|
+
beginTime: metadata?.beginTime,
|
|
163
|
+
}, e);
|
|
164
|
+
}
|
|
165
|
+
return result;
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Executes operations within a cache context that collects cache eviction events.
|
|
170
|
+
* All clearCache calls within the context are collected and executed in batch at the end.
|
|
171
|
+
* Queries executed within this context will bypass cache for tables that were marked for clearing.
|
|
172
|
+
*
|
|
173
|
+
* This is useful for:
|
|
174
|
+
* - Batch operations that affect multiple tables
|
|
175
|
+
* - Transaction-like operations where you want to clear cache only at the end
|
|
176
|
+
* - Performance optimization by reducing cache clear operations
|
|
177
|
+
*
|
|
178
|
+
* @param cacheContext - Function containing operations that may trigger cache evictions
|
|
179
|
+
* @returns Promise that resolves when all operations and cache clearing are complete
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```typescript
|
|
183
|
+
* await forgeSQL.executeWithCacheContext(async () => {
|
|
184
|
+
* await forgeSQL.modifyWithVersioning().insert(users, userData);
|
|
185
|
+
* await forgeSQL.modifyWithVersioning().insert(orders, orderData);
|
|
186
|
+
* // Cache for both users and orders tables will be cleared at the end
|
|
187
|
+
* });
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
executeWithCacheContext(cacheContext) {
|
|
191
|
+
return this.executeWithCacheContextAndReturnValue(cacheContext);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Executes operations within a cache context and returns a value.
|
|
195
|
+
* All clearCache calls within the context are collected and executed in batch at the end.
|
|
196
|
+
* Queries executed within this context will bypass cache for tables that were marked for clearing.
|
|
197
|
+
*
|
|
198
|
+
* @param cacheContext - Function containing operations that may trigger cache evictions
|
|
199
|
+
* @returns Promise that resolves to the return value of the cacheContext function
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```typescript
|
|
203
|
+
* const result = await forgeSQL.executeWithCacheContextAndReturnValue(async () => {
|
|
204
|
+
* await forgeSQL.modifyWithVersioning().insert(users, userData);
|
|
205
|
+
* return await forgeSQL.fetch().executeQueryOnlyOne(selectUserQuery);
|
|
206
|
+
* });
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
async executeWithCacheContextAndReturnValue(cacheContext) {
|
|
210
|
+
return await this.executeWithLocalCacheContextAndReturnValue(async () => await cacheContextUtils_1.cacheApplicationContext.run(cacheContextUtils_1.cacheApplicationContext.getStore() ?? { tables: new Set() }, async () => {
|
|
211
|
+
try {
|
|
212
|
+
return await cacheContext();
|
|
213
|
+
}
|
|
214
|
+
finally {
|
|
215
|
+
await (0, cacheUtils_1.clearTablesCache)(Array.from(cacheContextUtils_1.cacheApplicationContext.getStore()?.tables ?? []), this.options);
|
|
216
|
+
}
|
|
217
|
+
}));
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Executes operations within a local cache context and returns a value.
|
|
221
|
+
* This provides in-memory caching for select queries within a single request scope.
|
|
222
|
+
*
|
|
223
|
+
* @param cacheContext - Function containing operations that will benefit from local caching
|
|
224
|
+
* @returns Promise that resolves to the return value of the cacheContext function
|
|
225
|
+
*/
|
|
226
|
+
async executeWithLocalCacheContextAndReturnValue(cacheContext) {
|
|
227
|
+
return await cacheContextUtils_1.localCacheApplicationContext.run(cacheContextUtils_1.localCacheApplicationContext.getStore() ?? { cache: {} }, async () => {
|
|
228
|
+
return await cacheContext();
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Executes operations within a local cache context.
|
|
233
|
+
* This provides in-memory caching for select queries within a single request scope.
|
|
234
|
+
*
|
|
235
|
+
* @param cacheContext - Function containing operations that will benefit from local caching
|
|
236
|
+
* @returns Promise that resolves when all operations are complete
|
|
237
|
+
*/
|
|
238
|
+
executeWithLocalContext(cacheContext) {
|
|
239
|
+
return this.executeWithLocalCacheContextAndReturnValue(cacheContext);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Creates an insert query builder.
|
|
243
|
+
*
|
|
244
|
+
* ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
|
|
245
|
+
* For versioned inserts, use `modifyWithVersioning().insert()` or `modifyWithVersioningAndEvictCache().insert()` instead.
|
|
246
|
+
*
|
|
247
|
+
* @param table - The table to insert into
|
|
248
|
+
* @returns Insert query builder (no versioning, no cache management)
|
|
249
|
+
*/
|
|
250
|
+
insert(table) {
|
|
251
|
+
return this.drizzle.insertWithCacheContext(table);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Creates an insert query builder that automatically evicts cache after execution.
|
|
255
|
+
*
|
|
256
|
+
* ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
|
|
257
|
+
* For versioned inserts, use `modifyWithVersioning().insert()` or `modifyWithVersioningAndEvictCache().insert()` instead.
|
|
258
|
+
*
|
|
259
|
+
* @param table - The table to insert into
|
|
260
|
+
* @returns Insert query builder with automatic cache eviction (no versioning)
|
|
261
|
+
*/
|
|
262
|
+
insertAndEvictCache(table) {
|
|
263
|
+
return this.drizzle.insertAndEvictCache(table);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Creates an update query builder that automatically evicts cache after execution.
|
|
267
|
+
*
|
|
268
|
+
* ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
|
|
269
|
+
* For versioned updates, use `modifyWithVersioning().updateById()` or `modifyWithVersioningAndEvictCache().updateById()` instead.
|
|
270
|
+
*
|
|
271
|
+
* @param table - The table to update
|
|
272
|
+
* @returns Update query builder with automatic cache eviction (no versioning)
|
|
273
|
+
*/
|
|
274
|
+
updateAndEvictCache(table) {
|
|
275
|
+
return this.drizzle.updateAndEvictCache(table);
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Creates an update query builder.
|
|
279
|
+
*
|
|
280
|
+
* ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
|
|
281
|
+
* For versioned updates, use `modifyWithVersioning().updateById()` or `modifyWithVersioningAndEvictCache().updateById()` instead.
|
|
282
|
+
*
|
|
283
|
+
* @param table - The table to update
|
|
284
|
+
* @returns Update query builder (no versioning, no cache management)
|
|
285
|
+
*/
|
|
286
|
+
update(table) {
|
|
287
|
+
return this.drizzle.updateWithCacheContext(table);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Creates a delete query builder.
|
|
291
|
+
*
|
|
292
|
+
* ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
|
|
293
|
+
* For versioned deletes, use `modifyWithVersioning().deleteById()` or `modifyWithVersioningAndEvictCache().deleteById()` instead.
|
|
294
|
+
*
|
|
295
|
+
* @param table - The table to delete from
|
|
296
|
+
* @returns Delete query builder (no versioning, no cache management)
|
|
297
|
+
*/
|
|
298
|
+
delete(table) {
|
|
299
|
+
return this.drizzle.deleteWithCacheContext(table);
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Creates a delete query builder that automatically evicts cache after execution.
|
|
303
|
+
*
|
|
304
|
+
* ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
|
|
305
|
+
* For versioned deletes, use `modifyWithVersioning().deleteById()` or `modifyWithVersioningAndEvictCache().deleteById()` instead.
|
|
306
|
+
*
|
|
307
|
+
* @param table - The table to delete from
|
|
308
|
+
* @returns Delete query builder with automatic cache eviction (no versioning)
|
|
309
|
+
*/
|
|
310
|
+
deleteAndEvictCache(table) {
|
|
311
|
+
return this.drizzle.deleteAndEvictCache(table);
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Create the modify operations instance.
|
|
315
|
+
* @returns modify operations.
|
|
316
|
+
*/
|
|
317
|
+
modifyWithVersioning() {
|
|
318
|
+
return this.crudOperations;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Returns the singleton instance of ForgeSQLORMImpl.
|
|
322
|
+
* @param options - Options for configuring ForgeSQL ORM behavior.
|
|
323
|
+
* @returns The singleton instance of ForgeSQLORMImpl.
|
|
324
|
+
*/
|
|
325
|
+
static getInstance(options) {
|
|
326
|
+
ForgeSQLORMImpl.instance ??= new ForgeSQLORMImpl(options);
|
|
327
|
+
return ForgeSQLORMImpl.instance;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Retrieves the fetch operations instance.
|
|
331
|
+
* @returns Fetch operations.
|
|
332
|
+
*/
|
|
333
|
+
fetch() {
|
|
334
|
+
return this.fetchOperations;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Provides query analysis capabilities including EXPLAIN ANALYZE and slow query analysis.
|
|
338
|
+
* @returns {SchemaAnalyzeForgeSql} Interface for analyzing query performance
|
|
339
|
+
*/
|
|
340
|
+
analyze() {
|
|
341
|
+
return this.analyzeOperations;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Provides schema-level SQL operations with optimistic locking/versioning and automatic cache eviction.
|
|
345
|
+
*
|
|
346
|
+
* This method returns operations that use `modifyWithVersioning()` internally, providing:
|
|
347
|
+
* - Optimistic locking support
|
|
348
|
+
* - Automatic version field management
|
|
349
|
+
* - Cache eviction after successful operations
|
|
350
|
+
*
|
|
351
|
+
* @returns {ForgeSQLCacheOperations} Interface for executing versioned SQL operations with cache management
|
|
352
|
+
*/
|
|
353
|
+
modifyWithVersioningAndEvictCache() {
|
|
354
|
+
return this.cacheOperations;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Returns a Drizzle query builder instance.
|
|
358
|
+
*
|
|
359
|
+
* ⚠️ IMPORTANT: This method should be used ONLY for query building purposes.
|
|
360
|
+
* The returned instance should NOT be used for direct database connections or query execution.
|
|
361
|
+
* All database operations should be performed through Forge SQL's executeRawSQL or executeRawUpdateSQL methods.
|
|
362
|
+
*
|
|
363
|
+
* @returns A Drizzle query builder instance for query construction only.
|
|
364
|
+
*/
|
|
365
|
+
getDrizzleQueryBuilder() {
|
|
366
|
+
return this.drizzle;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Creates a select query with unique field aliases to prevent field name collisions in joins.
|
|
370
|
+
* This is particularly useful when working with Atlassian Forge SQL, which collapses fields with the same name in joined tables.
|
|
371
|
+
*
|
|
372
|
+
* @template TSelection - The type of the selected fields
|
|
373
|
+
* @param {TSelection} fields - Object containing the fields to select, with table schemas as values
|
|
374
|
+
* @returns {MySqlSelectBuilder<TSelection, MySql2PreparedQueryHKT>} A select query builder with unique field aliases
|
|
375
|
+
* @throws {Error} If fields parameter is empty
|
|
376
|
+
* @example
|
|
377
|
+
* ```typescript
|
|
378
|
+
* await forgeSQL
|
|
379
|
+
* .select({user: users, order: orders})
|
|
380
|
+
* .from(orders)
|
|
381
|
+
* .innerJoin(users, eq(orders.userId, users.id));
|
|
382
|
+
* ```
|
|
383
|
+
*/
|
|
384
|
+
select(fields) {
|
|
385
|
+
if (!fields) {
|
|
386
|
+
throw new Error("fields is empty");
|
|
387
|
+
}
|
|
388
|
+
return this.drizzle.selectAliased(fields);
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Creates a distinct select query with unique field aliases to prevent field name collisions in joins.
|
|
392
|
+
* This is particularly useful when working with Atlassian Forge SQL, which collapses fields with the same name in joined tables.
|
|
393
|
+
*
|
|
394
|
+
* @template TSelection - The type of the selected fields
|
|
395
|
+
* @param {TSelection} fields - Object containing the fields to select, with table schemas as values
|
|
396
|
+
* @returns {MySqlSelectBuilder<TSelection, MySql2PreparedQueryHKT>} A distinct select query builder with unique field aliases
|
|
397
|
+
* @throws {Error} If fields parameter is empty
|
|
398
|
+
* @example
|
|
399
|
+
* ```typescript
|
|
400
|
+
* await forgeSQL
|
|
401
|
+
* .selectDistinct({user: users, order: orders})
|
|
402
|
+
* .from(orders)
|
|
403
|
+
* .innerJoin(users, eq(orders.userId, users.id));
|
|
404
|
+
* ```
|
|
405
|
+
*/
|
|
406
|
+
selectDistinct(fields) {
|
|
407
|
+
if (!fields) {
|
|
408
|
+
throw new Error("fields is empty");
|
|
409
|
+
}
|
|
410
|
+
return this.drizzle.selectAliasedDistinct(fields);
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Creates a cacheable select query with unique field aliases to prevent field name collisions in joins.
|
|
414
|
+
* This is particularly useful when working with Atlassian Forge SQL, which collapses fields with the same name in joined tables.
|
|
415
|
+
*
|
|
416
|
+
* @template TSelection - The type of the selected fields
|
|
417
|
+
* @param {TSelection} fields - Object containing the fields to select, with table schemas as values
|
|
418
|
+
* @param {number} cacheTTL - cache ttl optional default is 60 sec.
|
|
419
|
+
* @returns {MySqlSelectBuilder<TSelection, MySql2PreparedQueryHKT>} A select query builder with unique field aliases
|
|
420
|
+
* @throws {Error} If fields parameter is empty
|
|
421
|
+
* @example
|
|
422
|
+
* ```typescript
|
|
423
|
+
* await forgeSQL
|
|
424
|
+
* .selectCacheable({user: users, order: orders},60)
|
|
425
|
+
* .from(orders)
|
|
426
|
+
* .innerJoin(users, eq(orders.userId, users.id));
|
|
427
|
+
* ```
|
|
428
|
+
*/
|
|
429
|
+
selectCacheable(fields, cacheTTL) {
|
|
430
|
+
if (!fields) {
|
|
431
|
+
throw new Error("fields is empty");
|
|
432
|
+
}
|
|
433
|
+
return this.drizzle.selectAliasedCacheable(fields, cacheTTL);
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Creates a cacheable distinct select query with unique field aliases to prevent field name collisions in joins.
|
|
437
|
+
* This is particularly useful when working with Atlassian Forge SQL, which collapses fields with the same name in joined tables.
|
|
438
|
+
*
|
|
439
|
+
* @template TSelection - The type of the selected fields
|
|
440
|
+
* @param {TSelection} fields - Object containing the fields to select, with table schemas as values
|
|
441
|
+
* @param {number} cacheTTL - cache ttl optional default is 60 sec.
|
|
442
|
+
* @returns {MySqlSelectBuilder<TSelection, MySql2PreparedQueryHKT>} A distinct select query builder with unique field aliases
|
|
443
|
+
* @throws {Error} If fields parameter is empty
|
|
444
|
+
* @example
|
|
445
|
+
* ```typescript
|
|
446
|
+
* await forgeSQL
|
|
447
|
+
* .selectDistinctCacheable({user: users, order: orders}, 60)
|
|
448
|
+
* .from(orders)
|
|
449
|
+
* .innerJoin(users, eq(orders.userId, users.id));
|
|
450
|
+
* ```
|
|
451
|
+
*/
|
|
452
|
+
selectDistinctCacheable(fields, cacheTTL) {
|
|
453
|
+
if (!fields) {
|
|
454
|
+
throw new Error("fields is empty");
|
|
455
|
+
}
|
|
456
|
+
return this.drizzle.selectAliasedDistinctCacheable(fields, cacheTTL);
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Creates a select query builder for all columns from a table with field aliasing support.
|
|
460
|
+
* This is a convenience method that automatically selects all columns from the specified table.
|
|
461
|
+
*
|
|
462
|
+
* @template T - The type of the table
|
|
463
|
+
* @param table - The table to select from
|
|
464
|
+
* @returns Select query builder with all table columns and field aliasing support
|
|
465
|
+
* @example
|
|
466
|
+
* ```typescript
|
|
467
|
+
* const users = await forgeSQL.selectFrom(userTable).where(eq(userTable.id, 1));
|
|
468
|
+
* ```
|
|
469
|
+
*/
|
|
470
|
+
selectFrom(table) {
|
|
471
|
+
return this.drizzle.selectFrom(table);
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Creates a select distinct query builder for all columns from a table with field aliasing support.
|
|
475
|
+
* This is a convenience method that automatically selects all distinct columns from the specified table.
|
|
476
|
+
*
|
|
477
|
+
* @template T - The type of the table
|
|
478
|
+
* @param table - The table to select from
|
|
479
|
+
* @returns Select distinct query builder with all table columns and field aliasing support
|
|
480
|
+
* @example
|
|
481
|
+
* ```typescript
|
|
482
|
+
* const uniqueUsers = await forgeSQL.selectDistinctFrom(userTable).where(eq(userTable.status, 'active'));
|
|
483
|
+
* ```
|
|
484
|
+
*/
|
|
485
|
+
selectDistinctFrom(table) {
|
|
486
|
+
return this.drizzle.selectDistinctFrom(table);
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Creates a cacheable select query builder for all columns from a table with field aliasing and caching support.
|
|
490
|
+
* This is a convenience method that automatically selects all columns from the specified table with caching enabled.
|
|
491
|
+
*
|
|
492
|
+
* @template T - The type of the table
|
|
493
|
+
* @param table - The table to select from
|
|
494
|
+
* @param cacheTTL - Optional cache TTL override (defaults to global cache TTL)
|
|
495
|
+
* @returns Select query builder with all table columns, field aliasing, and caching support
|
|
496
|
+
* @example
|
|
497
|
+
* ```typescript
|
|
498
|
+
* const users = await forgeSQL.selectCacheableFrom(userTable, 300).where(eq(userTable.id, 1));
|
|
499
|
+
* ```
|
|
500
|
+
*/
|
|
501
|
+
selectCacheableFrom(table, cacheTTL) {
|
|
502
|
+
return this.drizzle.selectFromCacheable(table, cacheTTL);
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Creates a cacheable select distinct query builder for all columns from a table with field aliasing and caching support.
|
|
506
|
+
* This is a convenience method that automatically selects all distinct columns from the specified table with caching enabled.
|
|
507
|
+
*
|
|
508
|
+
* @template T - The type of the table
|
|
509
|
+
* @param table - The table to select from
|
|
510
|
+
* @param cacheTTL - Optional cache TTL override (defaults to global cache TTL)
|
|
511
|
+
* @returns Select distinct query builder with all table columns, field aliasing, and caching support
|
|
512
|
+
* @example
|
|
513
|
+
* ```typescript
|
|
514
|
+
* const uniqueUsers = await forgeSQL.selectDistinctCacheableFrom(userTable, 300).where(eq(userTable.status, 'active'));
|
|
515
|
+
* ```
|
|
516
|
+
*/
|
|
517
|
+
selectDistinctCacheableFrom(table, cacheTTL) {
|
|
518
|
+
return this.drizzle.selectDistinctFromCacheable(table, cacheTTL);
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Executes a raw SQL query with local cache support.
|
|
522
|
+
* This method provides local caching for raw SQL queries within the current invocation context.
|
|
523
|
+
* Results are cached locally and will be returned from cache on subsequent identical queries.
|
|
524
|
+
*
|
|
525
|
+
* @param query - The SQL query to execute (SQLWrapper or string)
|
|
526
|
+
* @returns Promise with query results
|
|
527
|
+
* @example
|
|
528
|
+
* ```typescript
|
|
529
|
+
* // Using SQLWrapper
|
|
530
|
+
* const result = await forgeSQL.execute(sql`SELECT * FROM users WHERE id = ${userId}`);
|
|
531
|
+
*
|
|
532
|
+
* // Using string
|
|
533
|
+
* const result = await forgeSQL.execute("SELECT * FROM users WHERE status = 'active'");
|
|
534
|
+
* ```
|
|
535
|
+
*/
|
|
536
|
+
execute(query) {
|
|
537
|
+
return this.drizzle.executeQuery(query);
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Executes a Data Definition Language (DDL) SQL query.
|
|
541
|
+
* DDL operations include CREATE, ALTER, DROP, TRUNCATE, and other schema modification statements.
|
|
542
|
+
*
|
|
543
|
+
* This method is specifically designed for DDL operations and provides:
|
|
544
|
+
* - Proper operation type context for DDL queries
|
|
545
|
+
* - No caching (DDL operations should not be cached)
|
|
546
|
+
* - Direct execution without query optimization
|
|
547
|
+
*
|
|
548
|
+
* @template T - The expected return type of the query result
|
|
549
|
+
* @param query - The DDL SQL query to execute (SQLWrapper or string)
|
|
550
|
+
* @returns Promise with query results
|
|
551
|
+
* @throws {Error} If the DDL operation fails
|
|
552
|
+
*
|
|
553
|
+
* @example
|
|
554
|
+
* ```typescript
|
|
555
|
+
* // Create a new table
|
|
556
|
+
* await forgeSQL.executeDDL(`
|
|
557
|
+
* CREATE TABLE users (
|
|
558
|
+
* id INT PRIMARY KEY AUTO_INCREMENT,
|
|
559
|
+
* name VARCHAR(255) NOT NULL,
|
|
560
|
+
* email VARCHAR(255) UNIQUE
|
|
561
|
+
* )
|
|
562
|
+
* `);
|
|
563
|
+
*
|
|
564
|
+
* // Alter table structure
|
|
565
|
+
* await forgeSQL.executeDDL(sql`
|
|
566
|
+
* ALTER TABLE users
|
|
567
|
+
* ADD COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
568
|
+
* `);
|
|
569
|
+
*
|
|
570
|
+
* // Drop a table
|
|
571
|
+
* await forgeSQL.executeDDL("DROP TABLE IF EXISTS old_users");
|
|
572
|
+
* ```
|
|
573
|
+
*/
|
|
574
|
+
async executeDDL(query) {
|
|
575
|
+
return this.executeDDLActions(async () => this.drizzle.executeQuery(query));
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Executes a series of actions within a DDL operation context.
|
|
579
|
+
* This method provides a way to execute regular SQL queries that should be treated
|
|
580
|
+
* as DDL operations, ensuring proper operation type context for performance monitoring.
|
|
581
|
+
*
|
|
582
|
+
* This method is useful for:
|
|
583
|
+
* - Executing regular SQL queries in DDL context for monitoring purposes
|
|
584
|
+
* - Wrapping non-DDL operations that should be treated as DDL for analysis
|
|
585
|
+
* - Ensuring proper operation type context for complex workflows
|
|
586
|
+
* - Maintaining DDL operation context across multiple function calls
|
|
587
|
+
*
|
|
588
|
+
* @template T - The return type of the actions function
|
|
589
|
+
* @param actions - Function containing SQL operations to execute in DDL context
|
|
590
|
+
* @returns Promise that resolves to the return value of the actions function
|
|
591
|
+
*
|
|
592
|
+
* @example
|
|
593
|
+
* ```typescript
|
|
594
|
+
* // Execute regular SQL queries in DDL context for monitoring
|
|
595
|
+
* await forgeSQL.executeDDLActions(async () => {
|
|
596
|
+
* const slowQueries = await forgeSQL.execute(`
|
|
597
|
+
* SELECT * FROM INFORMATION_SCHEMA.STATEMENTS_SUMMARY
|
|
598
|
+
* WHERE AVG_LATENCY > 1000000
|
|
599
|
+
* `);
|
|
600
|
+
* return slowQueries;
|
|
601
|
+
* });
|
|
602
|
+
*
|
|
603
|
+
* // Execute complex analysis queries in DDL context
|
|
604
|
+
* const result = await forgeSQL.executeDDLActions(async () => {
|
|
605
|
+
* const tableInfo = await forgeSQL.execute("SHOW TABLES");
|
|
606
|
+
* const performanceData = await forgeSQL.execute(`
|
|
607
|
+
* SELECT * FROM INFORMATION_SCHEMA.CLUSTER_STATEMENTS_SUMMARY_HISTORY
|
|
608
|
+
* WHERE SUMMARY_END_TIME > DATE_SUB(NOW(), INTERVAL 1 HOUR)
|
|
609
|
+
* `);
|
|
610
|
+
* return { tableInfo, performanceData };
|
|
611
|
+
* });
|
|
612
|
+
*
|
|
613
|
+
* // Execute monitoring queries with error handling
|
|
614
|
+
* try {
|
|
615
|
+
* await forgeSQL.executeDDLActions(async () => {
|
|
616
|
+
* const metrics = await forgeSQL.execute(`
|
|
617
|
+
* SELECT COUNT(*) as query_count
|
|
618
|
+
* FROM INFORMATION_SCHEMA.STATEMENTS_SUMMARY
|
|
619
|
+
* `);
|
|
620
|
+
* console.log(`Total queries: ${metrics[0].query_count}`);
|
|
621
|
+
* });
|
|
622
|
+
* } catch (error) {
|
|
623
|
+
* console.error("Monitoring query failed:", error);
|
|
624
|
+
* }
|
|
625
|
+
* ```
|
|
626
|
+
*/
|
|
627
|
+
async executeDDLActions(actions) {
|
|
628
|
+
return requestTypeContextUtils_1.operationTypeQueryContext.run({ operationType: "DDL" }, async () => actions());
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Executes a raw SQL query with both local and global cache support.
|
|
632
|
+
* This method provides comprehensive caching for raw SQL queries:
|
|
633
|
+
* - Local cache: Within the current invocation context
|
|
634
|
+
* - Global cache: Cross-invocation caching using @forge/kvs
|
|
635
|
+
*
|
|
636
|
+
* @param query - The SQL query to execute (SQLWrapper or string)
|
|
637
|
+
* @param cacheTtl - Optional cache TTL override (defaults to global cache TTL)
|
|
638
|
+
* @returns Promise with query results
|
|
639
|
+
* @example
|
|
640
|
+
* ```typescript
|
|
641
|
+
* // Using SQLWrapper with custom TTL
|
|
642
|
+
* const result = await forgeSQL.executeCacheable(sql`SELECT * FROM users WHERE id = ${userId}`, 300);
|
|
643
|
+
*
|
|
644
|
+
* // Using string with default TTL
|
|
645
|
+
* const result = await forgeSQL.executeCacheable("SELECT * FROM users WHERE status = 'active'");
|
|
646
|
+
* ```
|
|
647
|
+
*/
|
|
648
|
+
executeCacheable(query, cacheTtl) {
|
|
649
|
+
return this.drizzle.executeQueryCacheable(query, cacheTtl);
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Creates a Common Table Expression (CTE) builder for complex queries.
|
|
653
|
+
* CTEs allow you to define temporary named result sets that exist within the scope of a single query.
|
|
654
|
+
*
|
|
655
|
+
* @returns WithBuilder for creating CTEs
|
|
656
|
+
* @example
|
|
657
|
+
* ```typescript
|
|
658
|
+
* const withQuery = forgeSQL.$with('userStats').as(
|
|
659
|
+
* forgeSQL.select({ userId: users.id, count: sql<number>`count(*)` })
|
|
660
|
+
* .from(users)
|
|
661
|
+
* .groupBy(users.id)
|
|
662
|
+
* );
|
|
663
|
+
* ```
|
|
664
|
+
*/
|
|
665
|
+
get $with() {
|
|
666
|
+
return this.drizzle.$with;
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Creates a query builder that uses Common Table Expressions (CTEs).
|
|
670
|
+
* CTEs allow you to define temporary named result sets that exist within the scope of a single query.
|
|
671
|
+
*
|
|
672
|
+
* @param queries - Array of CTE queries created with $with()
|
|
673
|
+
* @returns Query builder with CTE support
|
|
674
|
+
* @example
|
|
675
|
+
* ```typescript
|
|
676
|
+
* const withQuery = forgeSQL.$with('userStats').as(
|
|
677
|
+
* forgeSQL.select({ userId: users.id, count: sql<number>`count(*)` })
|
|
678
|
+
* .from(users)
|
|
679
|
+
* .groupBy(users.id)
|
|
680
|
+
* );
|
|
681
|
+
*
|
|
682
|
+
* const result = await forgeSQL.with(withQuery)
|
|
683
|
+
* .select({ userId: withQuery.userId, count: withQuery.count })
|
|
684
|
+
* .from(withQuery);
|
|
685
|
+
* ```
|
|
686
|
+
*/
|
|
687
|
+
with(...queries) {
|
|
688
|
+
return this.drizzle.with(...queries);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
/**
|
|
692
|
+
* Public class that acts as a wrapper around the private ForgeSQLORMImpl.
|
|
693
|
+
* Provides a clean interface for working with Forge SQL and Drizzle ORM.
|
|
694
|
+
*/
|
|
695
|
+
class ForgeSQLORM {
|
|
696
|
+
ormInstance;
|
|
697
|
+
constructor(options) {
|
|
698
|
+
this.ormInstance = ForgeSQLORMImpl.getInstance(options);
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* Executes a query and provides access to execution metadata with performance monitoring.
|
|
702
|
+
* This method allows you to capture detailed information about query execution
|
|
703
|
+
* including database execution time, response size, and query analysis capabilities.
|
|
704
|
+
*
|
|
705
|
+
* The method aggregates metrics across all database operations within the query function,
|
|
706
|
+
* making it ideal for monitoring resolver performance and detecting performance issues.
|
|
707
|
+
*
|
|
708
|
+
* @template T - The return type of the query
|
|
709
|
+
* @param query - A function that returns a Promise with the query result. Can contain multiple database operations.
|
|
710
|
+
* @param onMetadata - Callback function that receives aggregated execution metadata
|
|
711
|
+
* @param onMetadata.totalDbExecutionTime - Total database execution time across all operations in the query function (in milliseconds)
|
|
712
|
+
* @param onMetadata.totalResponseSize - Total response size across all operations (in bytes)
|
|
713
|
+
* @param onMetadata.printQueries - Function to analyze and print query execution plans from CLUSTER_STATEMENTS_SUMMARY
|
|
714
|
+
* @returns Promise with the query result
|
|
715
|
+
*
|
|
716
|
+
* @example
|
|
717
|
+
* ```typescript
|
|
718
|
+
* // Basic usage with performance monitoring
|
|
719
|
+
* const result = await forgeSQL.executeWithMetadata(
|
|
720
|
+
* async () => {
|
|
721
|
+
* const users = await forgeSQL.selectFrom(usersTable);
|
|
722
|
+
* const orders = await forgeSQL.selectFrom(ordersTable).where(eq(ordersTable.userId, usersTable.id));
|
|
723
|
+
* return { users, orders };
|
|
724
|
+
* },
|
|
725
|
+
* (totalDbExecutionTime, totalResponseSize, printQueries) => {
|
|
726
|
+
* const threshold = 500; // ms baseline for this resolver
|
|
727
|
+
*
|
|
728
|
+
* if (totalDbExecutionTime > threshold * 1.5) {
|
|
729
|
+
* console.warn(`[Performance Warning] Resolver exceeded DB time: ${totalDbExecutionTime} ms`);
|
|
730
|
+
* await printQueries(); // Analyze and print query execution plans
|
|
731
|
+
* } else if (totalDbExecutionTime > threshold) {
|
|
732
|
+
* console.debug(`[Performance Debug] High DB time: ${totalDbExecutionTime} ms`);
|
|
733
|
+
* }
|
|
734
|
+
*
|
|
735
|
+
* console.log(`DB response size: ${totalResponseSize} bytes`);
|
|
736
|
+
* }
|
|
737
|
+
* );
|
|
738
|
+
* ```
|
|
739
|
+
*
|
|
740
|
+
* @example
|
|
741
|
+
* ```typescript
|
|
742
|
+
* // Resolver with performance monitoring
|
|
743
|
+
* resolver.define("fetch", async (req: Request) => {
|
|
744
|
+
* try {
|
|
745
|
+
* return await forgeSQL.executeWithMetadata(
|
|
746
|
+
* async () => {
|
|
747
|
+
* // Resolver logic with multiple queries
|
|
748
|
+
* const users = await forgeSQL.selectFrom(demoUsers);
|
|
749
|
+
* const orders = await forgeSQL.selectFrom(demoOrders)
|
|
750
|
+
* .where(eq(demoOrders.userId, demoUsers.id));
|
|
751
|
+
* return { users, orders };
|
|
752
|
+
* },
|
|
753
|
+
* async (totalDbExecutionTime, totalResponseSize, printQueries) => {
|
|
754
|
+
* const threshold = 500; // ms baseline for this resolver
|
|
755
|
+
*
|
|
756
|
+
* if (totalDbExecutionTime > threshold * 1.5) {
|
|
757
|
+
* console.warn(`[Performance Warning fetch] Resolver exceeded DB time: ${totalDbExecutionTime} ms`);
|
|
758
|
+
* await printQueries(); // Optionally log or capture diagnostics for further analysis
|
|
759
|
+
* } else if (totalDbExecutionTime > threshold) {
|
|
760
|
+
* console.debug(`[Performance Debug] High DB time: ${totalDbExecutionTime} ms`);
|
|
761
|
+
* }
|
|
762
|
+
*
|
|
763
|
+
* console.log(`DB response size: ${totalResponseSize} bytes`);
|
|
764
|
+
* }
|
|
765
|
+
* );
|
|
766
|
+
* } catch (e) {
|
|
767
|
+
* const error = e?.cause?.debug?.sqlMessage ?? e?.cause;
|
|
768
|
+
* console.error(error, e);
|
|
769
|
+
* throw error;
|
|
770
|
+
* }
|
|
771
|
+
* });
|
|
772
|
+
* ```
|
|
773
|
+
*
|
|
774
|
+
* @note **Important**: When multiple resolvers are running concurrently, their query data may also appear in `printQueries()` analysis, as it queries the global `CLUSTER_STATEMENTS_SUMMARY` table.
|
|
775
|
+
*/
|
|
776
|
+
async executeWithMetadata(query, onMetadata) {
|
|
777
|
+
return this.ormInstance.executeWithMetadata(query, onMetadata);
|
|
778
|
+
}
|
|
779
|
+
selectCacheable(fields, cacheTTL) {
|
|
780
|
+
return this.ormInstance.selectCacheable(fields, cacheTTL);
|
|
781
|
+
}
|
|
782
|
+
selectDistinctCacheable(fields, cacheTTL) {
|
|
783
|
+
return this.ormInstance.selectDistinctCacheable(fields, cacheTTL);
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Creates a select query builder for all columns from a table with field aliasing support.
|
|
787
|
+
* This is a convenience method that automatically selects all columns from the specified table.
|
|
788
|
+
*
|
|
789
|
+
* @template T - The type of the table
|
|
790
|
+
* @param table - The table to select from
|
|
791
|
+
* @returns Select query builder with all table columns and field aliasing support
|
|
792
|
+
* @example
|
|
793
|
+
* ```typescript
|
|
794
|
+
* const users = await forgeSQL.selectFrom(userTable).where(eq(userTable.id, 1));
|
|
795
|
+
* ```
|
|
796
|
+
*/
|
|
797
|
+
selectFrom(table) {
|
|
798
|
+
return this.ormInstance.getDrizzleQueryBuilder().selectFrom(table);
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Creates a select distinct query builder for all columns from a table with field aliasing support.
|
|
802
|
+
* This is a convenience method that automatically selects all distinct columns from the specified table.
|
|
803
|
+
*
|
|
804
|
+
* @template T - The type of the table
|
|
805
|
+
* @param table - The table to select from
|
|
806
|
+
* @returns Select distinct query builder with all table columns and field aliasing support
|
|
807
|
+
* @example
|
|
808
|
+
* ```typescript
|
|
809
|
+
* const uniqueUsers = await forgeSQL.selectDistinctFrom(userTable).where(eq(userTable.status, 'active'));
|
|
810
|
+
* ```
|
|
811
|
+
*/
|
|
812
|
+
selectDistinctFrom(table) {
|
|
813
|
+
return this.ormInstance.getDrizzleQueryBuilder().selectDistinctFrom(table);
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Creates a cacheable select query builder for all columns from a table with field aliasing and caching support.
|
|
817
|
+
* This is a convenience method that automatically selects all columns from the specified table with caching enabled.
|
|
818
|
+
*
|
|
819
|
+
* @template T - The type of the table
|
|
820
|
+
* @param table - The table to select from
|
|
821
|
+
* @param cacheTTL - Optional cache TTL override (defaults to global cache TTL)
|
|
822
|
+
* @returns Select query builder with all table columns, field aliasing, and caching support
|
|
823
|
+
* @example
|
|
824
|
+
* ```typescript
|
|
825
|
+
* const users = await forgeSQL.selectCacheableFrom(userTable, 300).where(eq(userTable.id, 1));
|
|
826
|
+
* ```
|
|
827
|
+
*/
|
|
828
|
+
selectCacheableFrom(table, cacheTTL) {
|
|
829
|
+
return this.ormInstance.getDrizzleQueryBuilder().selectFromCacheable(table, cacheTTL);
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Creates a cacheable select distinct query builder for all columns from a table with field aliasing and caching support.
|
|
833
|
+
* This is a convenience method that automatically selects all distinct columns from the specified table with caching enabled.
|
|
834
|
+
*
|
|
835
|
+
* @template T - The type of the table
|
|
836
|
+
* @param table - The table to select from
|
|
837
|
+
* @param cacheTTL - Optional cache TTL override (defaults to global cache TTL)
|
|
838
|
+
* @returns Select distinct query builder with all table columns, field aliasing, and caching support
|
|
839
|
+
* @example
|
|
840
|
+
* ```typescript
|
|
841
|
+
* const uniqueUsers = await forgeSQL.selectDistinctCacheableFrom(userTable, 300).where(eq(userTable.status, 'active'));
|
|
842
|
+
* ```
|
|
843
|
+
*/
|
|
844
|
+
selectDistinctCacheableFrom(table, cacheTTL) {
|
|
845
|
+
return this.ormInstance.getDrizzleQueryBuilder().selectDistinctFromCacheable(table, cacheTTL);
|
|
846
|
+
}
|
|
847
|
+
executeWithCacheContext(cacheContext) {
|
|
848
|
+
return this.ormInstance.executeWithCacheContext(cacheContext);
|
|
849
|
+
}
|
|
850
|
+
executeWithCacheContextAndReturnValue(cacheContext) {
|
|
851
|
+
return this.ormInstance.executeWithCacheContextAndReturnValue(cacheContext);
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* Executes operations within a local cache context.
|
|
855
|
+
* This provides in-memory caching for select queries within a single request scope.
|
|
856
|
+
*
|
|
857
|
+
* @param cacheContext - Function containing operations that will benefit from local caching
|
|
858
|
+
* @returns Promise that resolves when all operations are complete
|
|
859
|
+
*/
|
|
860
|
+
executeWithLocalContext(cacheContext) {
|
|
861
|
+
return this.ormInstance.executeWithLocalContext(cacheContext);
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
864
|
+
* Executes operations within a local cache context and returns a value.
|
|
865
|
+
* This provides in-memory caching for select queries within a single request scope.
|
|
866
|
+
*
|
|
867
|
+
* @param cacheContext - Function containing operations that will benefit from local caching
|
|
868
|
+
* @returns Promise that resolves to the return value of the cacheContext function
|
|
869
|
+
*/
|
|
870
|
+
executeWithLocalCacheContextAndReturnValue(cacheContext) {
|
|
871
|
+
return this.ormInstance.executeWithLocalCacheContextAndReturnValue(cacheContext);
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Creates an insert query builder.
|
|
875
|
+
*
|
|
876
|
+
* ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
|
|
877
|
+
* For versioned inserts, use `modifyWithVersioning().insert()` or `modifyWithVersioningAndEvictCache().insert()` instead.
|
|
878
|
+
*
|
|
879
|
+
* @param table - The table to insert into
|
|
880
|
+
* @returns Insert query builder (no versioning, no cache management)
|
|
881
|
+
*/
|
|
882
|
+
insert(table) {
|
|
883
|
+
return this.ormInstance.insert(table);
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Creates an insert query builder that automatically evicts cache after execution.
|
|
887
|
+
*
|
|
888
|
+
* ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
|
|
889
|
+
* For versioned inserts, use `modifyWithVersioning().insert()` or `modifyWithVersioningAndEvictCache().insert()` instead.
|
|
890
|
+
*
|
|
891
|
+
* @param table - The table to insert into
|
|
892
|
+
* @returns Insert query builder with automatic cache eviction (no versioning)
|
|
893
|
+
*/
|
|
894
|
+
insertAndEvictCache(table) {
|
|
895
|
+
return this.ormInstance.insertAndEvictCache(table);
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* Creates an update query builder.
|
|
899
|
+
*
|
|
900
|
+
* ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
|
|
901
|
+
* For versioned updates, use `modifyWithVersioning().updateById()` or `modifyWithVersioningAndEvictCache().updateById()` instead.
|
|
902
|
+
*
|
|
903
|
+
* @param table - The table to update
|
|
904
|
+
* @returns Update query builder (no versioning, no cache management)
|
|
905
|
+
*/
|
|
906
|
+
update(table) {
|
|
907
|
+
return this.ormInstance.update(table);
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* Creates an update query builder that automatically evicts cache after execution.
|
|
911
|
+
*
|
|
912
|
+
* ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
|
|
913
|
+
* For versioned updates, use `modifyWithVersioning().updateById()` or `modifyWithVersioningAndEvictCache().updateById()` instead.
|
|
914
|
+
*
|
|
915
|
+
* @param table - The table to update
|
|
916
|
+
* @returns Update query builder with automatic cache eviction (no versioning)
|
|
917
|
+
*/
|
|
918
|
+
updateAndEvictCache(table) {
|
|
919
|
+
return this.ormInstance.updateAndEvictCache(table);
|
|
920
|
+
}
|
|
921
|
+
/**
|
|
922
|
+
* Creates a delete query builder.
|
|
923
|
+
*
|
|
924
|
+
* ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
|
|
925
|
+
* For versioned deletes, use `modifyWithVersioning().deleteById()` or `modifyWithVersioningAndEvictCache().deleteById()` instead.
|
|
926
|
+
*
|
|
927
|
+
* @param table - The table to delete from
|
|
928
|
+
* @returns Delete query builder (no versioning, no cache management)
|
|
929
|
+
*/
|
|
930
|
+
delete(table) {
|
|
931
|
+
return this.ormInstance.delete(table);
|
|
932
|
+
}
|
|
933
|
+
/**
|
|
934
|
+
* Creates a delete query builder that automatically evicts cache after execution.
|
|
935
|
+
*
|
|
936
|
+
* ⚠️ **IMPORTANT**: This method does NOT support optimistic locking/versioning.
|
|
937
|
+
* For versioned deletes, use `modifyWithVersioning().deleteById()` or `modifyWithVersioningAndEvictCache().deleteById()` instead.
|
|
938
|
+
*
|
|
939
|
+
* @param table - The table to delete from
|
|
940
|
+
* @returns Delete query builder with automatic cache eviction (no versioning)
|
|
941
|
+
*/
|
|
942
|
+
deleteAndEvictCache(table) {
|
|
943
|
+
return this.ormInstance.deleteAndEvictCache(table);
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* Creates a select query with unique field aliases to prevent field name collisions in joins.
|
|
947
|
+
* This is particularly useful when working with Atlassian Forge SQL, which collapses fields with the same name in joined tables.
|
|
948
|
+
*
|
|
949
|
+
* @template TSelection - The type of the selected fields
|
|
950
|
+
* @param {TSelection} fields - Object containing the fields to select, with table schemas as values
|
|
951
|
+
* @returns {MySqlSelectBuilder<TSelection, MySql2PreparedQueryHKT>} A select query builder with unique field aliases
|
|
952
|
+
* @throws {Error} If fields parameter is empty
|
|
953
|
+
* @example
|
|
954
|
+
* ```typescript
|
|
955
|
+
* await forgeSQL
|
|
956
|
+
* .select({user: users, order: orders})
|
|
957
|
+
* .from(orders)
|
|
958
|
+
* .innerJoin(users, eq(orders.userId, users.id));
|
|
959
|
+
* ```
|
|
960
|
+
*/
|
|
961
|
+
select(fields) {
|
|
962
|
+
return this.ormInstance.select(fields);
|
|
963
|
+
}
|
|
964
|
+
/**
|
|
965
|
+
* Creates a distinct select query with unique field aliases to prevent field name collisions in joins.
|
|
966
|
+
* This is particularly useful when working with Atlassian Forge SQL, which collapses fields with the same name in joined tables.
|
|
967
|
+
*
|
|
968
|
+
* @template TSelection - The type of the selected fields
|
|
969
|
+
* @param {TSelection} fields - Object containing the fields to select, with table schemas as values
|
|
970
|
+
* @returns {MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>} A distinct select query builder with unique field aliases
|
|
971
|
+
* @throws {Error} If fields parameter is empty
|
|
972
|
+
* @example
|
|
973
|
+
* ```typescript
|
|
974
|
+
* await forgeSQL
|
|
975
|
+
* .selectDistinct({user: users, order: orders})
|
|
976
|
+
* .from(orders)
|
|
977
|
+
* .innerJoin(users, eq(orders.userId, users.id));
|
|
978
|
+
* ```
|
|
979
|
+
*/
|
|
980
|
+
selectDistinct(fields) {
|
|
981
|
+
return this.ormInstance.selectDistinct(fields);
|
|
982
|
+
}
|
|
983
|
+
/**
|
|
984
|
+
* Proxies the `modify` method from `ForgeSQLORMImpl`.
|
|
985
|
+
* @returns Modify operations.
|
|
986
|
+
*/
|
|
987
|
+
modifyWithVersioning() {
|
|
988
|
+
return this.ormInstance.modifyWithVersioning();
|
|
989
|
+
}
|
|
990
|
+
/**
|
|
991
|
+
* Proxies the `fetch` method from `ForgeSQLORMImpl`.
|
|
992
|
+
* @returns Fetch operations.
|
|
993
|
+
*/
|
|
994
|
+
fetch() {
|
|
995
|
+
return this.ormInstance.fetch();
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* Provides query analysis capabilities including EXPLAIN ANALYZE and slow query analysis.
|
|
999
|
+
* @returns {SchemaAnalyzeForgeSql} Interface for analyzing query performance
|
|
1000
|
+
*/
|
|
1001
|
+
analyze() {
|
|
1002
|
+
return this.ormInstance.analyze();
|
|
1003
|
+
}
|
|
1004
|
+
/**
|
|
1005
|
+
* Provides schema-level SQL cacheable operations with type safety.
|
|
1006
|
+
* @returns {ForgeSQLCacheOperations} Interface for executing schema-bound SQL queries
|
|
1007
|
+
*/
|
|
1008
|
+
modifyWithVersioningAndEvictCache() {
|
|
1009
|
+
return this.ormInstance.modifyWithVersioningAndEvictCache();
|
|
1010
|
+
}
|
|
1011
|
+
/**
|
|
1012
|
+
* Returns a Drizzle query builder instance.
|
|
1013
|
+
*
|
|
1014
|
+
* @returns A Drizzle query builder instance for query construction only.
|
|
1015
|
+
*/
|
|
1016
|
+
getDrizzleQueryBuilder() {
|
|
1017
|
+
return this.ormInstance.getDrizzleQueryBuilder();
|
|
1018
|
+
}
|
|
1019
|
+
/**
|
|
1020
|
+
* Executes a raw SQL query with local cache support.
|
|
1021
|
+
* This method provides local caching for raw SQL queries within the current invocation context.
|
|
1022
|
+
* Results are cached locally and will be returned from cache on subsequent identical queries.
|
|
1023
|
+
*
|
|
1024
|
+
* @param query - The SQL query to execute (SQLWrapper or string)
|
|
1025
|
+
* @returns Promise with query results
|
|
1026
|
+
* @example
|
|
1027
|
+
* ```typescript
|
|
1028
|
+
* // Using SQLWrapper
|
|
1029
|
+
* const result = await forgeSQL.execute(sql`SELECT * FROM users WHERE id = ${userId}`);
|
|
1030
|
+
*
|
|
1031
|
+
* // Using string
|
|
1032
|
+
* const result = await forgeSQL.execute("SELECT * FROM users WHERE status = 'active'");
|
|
1033
|
+
* ```
|
|
1034
|
+
*/
|
|
1035
|
+
execute(query) {
|
|
1036
|
+
return this.ormInstance.execute(query);
|
|
1037
|
+
}
|
|
1038
|
+
/**
|
|
1039
|
+
* Executes a Data Definition Language (DDL) SQL query.
|
|
1040
|
+
* DDL operations include CREATE, ALTER, DROP, TRUNCATE, and other schema modification statements.
|
|
1041
|
+
*
|
|
1042
|
+
* This method is specifically designed for DDL operations and provides:
|
|
1043
|
+
* - Proper operation type context for DDL queries
|
|
1044
|
+
* - No caching (DDL operations should not be cached)
|
|
1045
|
+
* - Direct execution without query optimization
|
|
1046
|
+
*
|
|
1047
|
+
* @template T - The expected return type of the query result
|
|
1048
|
+
* @param query - The DDL SQL query to execute (SQLWrapper or string)
|
|
1049
|
+
* @returns Promise with query results
|
|
1050
|
+
* @throws {Error} If the DDL operation fails
|
|
1051
|
+
*
|
|
1052
|
+
* @example
|
|
1053
|
+
* ```typescript
|
|
1054
|
+
* // Create a new table
|
|
1055
|
+
* await forgeSQL.executeDDL(`
|
|
1056
|
+
* CREATE TABLE users (
|
|
1057
|
+
* id INT PRIMARY KEY AUTO_INCREMENT,
|
|
1058
|
+
* name VARCHAR(255) NOT NULL,
|
|
1059
|
+
* email VARCHAR(255) UNIQUE
|
|
1060
|
+
* )
|
|
1061
|
+
* `);
|
|
1062
|
+
*
|
|
1063
|
+
* // Alter table structure
|
|
1064
|
+
* await forgeSQL.executeDDL(sql`
|
|
1065
|
+
* ALTER TABLE users
|
|
1066
|
+
* ADD COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
1067
|
+
* `);
|
|
1068
|
+
*
|
|
1069
|
+
* // Drop a table
|
|
1070
|
+
* await forgeSQL.executeDDL("DROP TABLE IF EXISTS old_users");
|
|
1071
|
+
* ```
|
|
1072
|
+
*/
|
|
1073
|
+
executeDDL(query) {
|
|
1074
|
+
return this.ormInstance.executeDDL(query);
|
|
1075
|
+
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Executes a series of actions within a DDL operation context.
|
|
1078
|
+
* This method provides a way to execute regular SQL queries that should be treated
|
|
1079
|
+
* as DDL operations, ensuring proper operation type context for performance monitoring.
|
|
1080
|
+
*
|
|
1081
|
+
* This method is useful for:
|
|
1082
|
+
* - Executing regular SQL queries in DDL context for monitoring purposes
|
|
1083
|
+
* - Wrapping non-DDL operations that should be treated as DDL for analysis
|
|
1084
|
+
* - Ensuring proper operation type context for complex workflows
|
|
1085
|
+
* - Maintaining DDL operation context across multiple function calls
|
|
1086
|
+
*
|
|
1087
|
+
* @template T - The return type of the actions function
|
|
1088
|
+
* @param actions - Function containing SQL operations to execute in DDL context
|
|
1089
|
+
* @returns Promise that resolves to the return value of the actions function
|
|
1090
|
+
*
|
|
1091
|
+
* @example
|
|
1092
|
+
* ```typescript
|
|
1093
|
+
* // Execute regular SQL queries in DDL context for monitoring
|
|
1094
|
+
* await forgeSQL.executeDDLActions(async () => {
|
|
1095
|
+
* const slowQueries = await forgeSQL.execute(`
|
|
1096
|
+
* SELECT * FROM INFORMATION_SCHEMA.STATEMENTS_SUMMARY
|
|
1097
|
+
* WHERE AVG_LATENCY > 1000000
|
|
1098
|
+
* `);
|
|
1099
|
+
* return slowQueries;
|
|
1100
|
+
* });
|
|
1101
|
+
*
|
|
1102
|
+
* // Execute complex analysis queries in DDL context
|
|
1103
|
+
* const result = await forgeSQL.executeDDLActions(async () => {
|
|
1104
|
+
* const tableInfo = await forgeSQL.execute("SHOW TABLES");
|
|
1105
|
+
* const performanceData = await forgeSQL.execute(`
|
|
1106
|
+
* SELECT * FROM INFORMATION_SCHEMA.CLUSTER_STATEMENTS_SUMMARY_HISTORY
|
|
1107
|
+
* WHERE SUMMARY_END_TIME > DATE_SUB(NOW(), INTERVAL 1 HOUR)
|
|
1108
|
+
* `);
|
|
1109
|
+
* return { tableInfo, performanceData };
|
|
1110
|
+
* });
|
|
1111
|
+
*
|
|
1112
|
+
* // Execute monitoring queries with error handling
|
|
1113
|
+
* try {
|
|
1114
|
+
* await forgeSQL.executeDDLActions(async () => {
|
|
1115
|
+
* const metrics = await forgeSQL.execute(`
|
|
1116
|
+
* SELECT COUNT(*) as query_count
|
|
1117
|
+
* FROM INFORMATION_SCHEMA.STATEMENTS_SUMMARY
|
|
1118
|
+
* `);
|
|
1119
|
+
* console.log(`Total queries: ${metrics[0].query_count}`);
|
|
1120
|
+
* });
|
|
1121
|
+
* } catch (error) {
|
|
1122
|
+
* console.error("Monitoring query failed:", error);
|
|
1123
|
+
* }
|
|
1124
|
+
* ```
|
|
1125
|
+
*/
|
|
1126
|
+
executeDDLActions(actions) {
|
|
1127
|
+
return this.ormInstance.executeDDLActions(actions);
|
|
1128
|
+
}
|
|
1129
|
+
/**
|
|
1130
|
+
* Executes a raw SQL query with both local and global cache support.
|
|
1131
|
+
* This method provides comprehensive caching for raw SQL queries:
|
|
1132
|
+
* - Local cache: Within the current invocation context
|
|
1133
|
+
* - Global cache: Cross-invocation caching using @forge/kvs
|
|
1134
|
+
*
|
|
1135
|
+
* @param query - The SQL query to execute (SQLWrapper or string)
|
|
1136
|
+
* @param cacheTtl - Optional cache TTL override (defaults to global cache TTL)
|
|
1137
|
+
* @returns Promise with query results
|
|
1138
|
+
* @example
|
|
1139
|
+
* ```typescript
|
|
1140
|
+
* // Using SQLWrapper with custom TTL
|
|
1141
|
+
* const result = await forgeSQL.executeCacheable(sql`SELECT * FROM users WHERE id = ${userId}`, 300);
|
|
1142
|
+
*
|
|
1143
|
+
* // Using string with default TTL
|
|
1144
|
+
* const result = await forgeSQL.executeCacheable("SELECT * FROM users WHERE status = 'active'");
|
|
1145
|
+
* ```
|
|
1146
|
+
*/
|
|
1147
|
+
executeCacheable(query, cacheTtl) {
|
|
1148
|
+
return this.ormInstance.executeCacheable(query, cacheTtl);
|
|
1149
|
+
}
|
|
1150
|
+
/**
|
|
1151
|
+
* Creates a Common Table Expression (CTE) builder for complex queries.
|
|
1152
|
+
* CTEs allow you to define temporary named result sets that exist within the scope of a single query.
|
|
1153
|
+
*
|
|
1154
|
+
* @returns WithBuilder for creating CTEs
|
|
1155
|
+
* @example
|
|
1156
|
+
* ```typescript
|
|
1157
|
+
* const withQuery = forgeSQL.$with('userStats').as(
|
|
1158
|
+
* forgeSQL.getDrizzleQueryBuilder().select({ userId: users.id, count: sql<number>`count(*)` })
|
|
1159
|
+
* .from(users)
|
|
1160
|
+
* .groupBy(users.id)
|
|
1161
|
+
* );
|
|
1162
|
+
* ```
|
|
1163
|
+
*/
|
|
1164
|
+
get $with() {
|
|
1165
|
+
return this.ormInstance.getDrizzleQueryBuilder().$with;
|
|
1166
|
+
}
|
|
1167
|
+
/**
|
|
1168
|
+
* Creates a query builder that uses Common Table Expressions (CTEs).
|
|
1169
|
+
* CTEs allow you to define temporary named result sets that exist within the scope of a single query.
|
|
1170
|
+
*
|
|
1171
|
+
* @param queries - Array of CTE queries created with $with()
|
|
1172
|
+
* @returns Query builder with CTE support
|
|
1173
|
+
* @example
|
|
1174
|
+
* ```typescript
|
|
1175
|
+
* const withQuery = forgeSQL.$with('userStats').as(
|
|
1176
|
+
* forgeSQL.getDrizzleQueryBuilder().select({ userId: users.id, count: sql<number>`count(*)` })
|
|
1177
|
+
* .from(users)
|
|
1178
|
+
* .groupBy(users.id)
|
|
1179
|
+
* );
|
|
1180
|
+
*
|
|
1181
|
+
* const result = await forgeSQL.with(withQuery)
|
|
1182
|
+
* .select({ userId: withQuery.userId, count: withQuery.count })
|
|
1183
|
+
* .from(withQuery);
|
|
1184
|
+
* ```
|
|
1185
|
+
*/
|
|
1186
|
+
with(...queries) {
|
|
1187
|
+
return this.ormInstance.getDrizzleQueryBuilder().with(...queries);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
exports.default = ForgeSQLORM;
|
|
1191
|
+
//# sourceMappingURL=ForgeSQLORM.js.map
|