forge-sql-orm 2.1.11 → 2.1.12
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 +157 -12
- package/dist/ForgeSQLORM.js +43 -17
- package/dist/ForgeSQLORM.js.map +1 -1
- package/dist/ForgeSQLORM.mjs +43 -17
- package/dist/ForgeSQLORM.mjs.map +1 -1
- package/dist/core/ForgeSQLORM.d.ts +1 -1
- package/dist/core/ForgeSQLORM.d.ts.map +1 -1
- package/dist/utils/cacheUtils.d.ts.map +1 -1
- package/dist/utils/forgeDriver.d.ts.map +1 -1
- package/dist/utils/metadataContextUtils.d.ts.map +1 -1
- package/dist/utils/sqlUtils.d.ts.map +1 -1
- package/dist/webtriggers/slowQuerySchedulerTrigger.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/core/ForgeSQLORM.ts +33 -27
- package/src/utils/cacheUtils.ts +23 -2
- package/src/utils/forgeDriver.ts +12 -4
- package/src/utils/metadataContextUtils.ts +1 -4
- package/src/utils/sqlUtils.ts +106 -94
- package/src/webtriggers/slowQuerySchedulerTrigger.ts +40 -33
|
@@ -426,7 +426,7 @@ declare class ForgeSQLORM implements ForgeSqlOperation {
|
|
|
426
426
|
* const result = await forgeSQL.executeCacheable("SELECT * FROM users WHERE status = 'active'");
|
|
427
427
|
* ```
|
|
428
428
|
*/
|
|
429
|
-
executeCacheable(query: SQLWrapper | string, cacheTtl?: number): Promise<
|
|
429
|
+
executeCacheable<T>(query: SQLWrapper | string, cacheTtl?: number): Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, T>>;
|
|
430
430
|
/**
|
|
431
431
|
* Creates a Common Table Expression (CTE) builder for complex queries.
|
|
432
432
|
* CTEs allow you to define temporary named result sets that exist within the scope of a single query.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ForgeSQLORM.d.ts","sourceRoot":"","sources":["../../src/core/ForgeSQLORM.ts"],"names":[],"mappings":"AACA,OAAO,EACL,6BAA6B,EAC7B,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAEL,mBAAmB,EACnB,2BAA2B,EAC3B,yBAAyB,EAC1B,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oDAAoD,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EAEvB,0BAA0B,EAC1B,kCAAkC,EAClC,yBAAyB,EACzB,iBAAiB,EACjB,uBAAuB,EACxB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,uCAAuC,CAAC;AAG/C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"ForgeSQLORM.d.ts","sourceRoot":"","sources":["../../src/core/ForgeSQLORM.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cacheUtils.d.ts","sourceRoot":"","sources":["../../src/utils/cacheUtils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAGvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"cacheUtils.d.ts","sourceRoot":"","sources":["../../src/utils/cacheUtils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAGvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAgElE;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAK5C;AAmKD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,CAAC,SAAS,aAAa,EACtD,MAAM,EAAE,CAAC,EACT,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAoBf;AACD;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBlF;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAClC,KAAK,EAAE;IAAE,KAAK,EAAE,MAAM,KAAK,CAAA;CAAE,EAC7B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CA6CxB;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE;IAAE,KAAK,EAAE,MAAM,KAAK,CAAA;CAAE,EAC7B,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CA8Cf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forgeDriver.d.ts","sourceRoot":"","sources":["../../src/utils/forgeDriver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAQtD;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;KACtB,EAAE,CAAC;CACL,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1D,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,CAAC;AAE5C;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,mBAAmB,CAO9E;
|
|
1
|
+
{"version":3,"file":"forgeDriver.d.ts","sourceRoot":"","sources":["../../src/utils/forgeDriver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAQtD;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;KACtB,EAAE,CAAC;CACL,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1D,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,CAAC;AAE5C;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,mBAAmB,CAO9E;AAiGD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,WAAW,GACtB,OAAO,MAAM,EACb,QAAQ,OAAO,EAAE,EACjB,QAAQ,WAAW,KAClB,OAAO,CAAC,iBAAiB,CAmB3B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadataContextUtils.d.ts","sourceRoot":"","sources":["../../src/utils/metadataContextUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAGjE,MAAM,MAAM,oBAAoB,GAAG;IACjC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,IAAI,CAAC;IAChB,oBAAoB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,WAAW,EAAE,iBAAiB,CAAC;CAChC,CAAC;AACF,eAAO,MAAM,oBAAoB,yCAAgD,CAAC;AAElF,wBAAsB,qBAAqB,CAAC,QAAQ,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"metadataContextUtils.d.ts","sourceRoot":"","sources":["../../src/utils/metadataContextUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAGjE,MAAM,MAAM,oBAAoB,GAAG;IACjC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,IAAI,CAAC;IAChB,oBAAoB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,WAAW,EAAE,iBAAiB,CAAC;CAChC,CAAC;AACF,eAAO,MAAM,oBAAoB,yCAAgD,CAAC;AAElF,wBAAsB,qBAAqB,CAAC,QAAQ,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAetF;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,CAEpF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlUtils.d.ts","sourceRoot":"","sources":["../../src/utils/sqlUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,SAAS,EAYV,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAqB,MAAM,8BAA8B,CAAC;AAEhF,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0CAA0C,CAAC;AACnF,OAAO,
|
|
1
|
+
{"version":3,"file":"sqlUtils.d.ts","sourceRoot":"","sources":["../../src/utils/sqlUtils.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slowQuerySchedulerTrigger.d.ts","sourceRoot":"","sources":["../../src/webtriggers/slowQuerySchedulerTrigger.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"slowQuerySchedulerTrigger.d.ts","sourceRoot":"","sources":["../../src/webtriggers/slowQuerySchedulerTrigger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,eAAe,EAAE,MAAM,SAAS,CAAC;AAE3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,wBAAsB,yBAAyB,CAC7C,WAAW,EAAE,iBAAiB,EAC9B,OAAO,EAAE;IACP,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB,GACA,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAkBlC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forge-sql-orm",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.12",
|
|
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",
|
|
@@ -32,14 +32,14 @@
|
|
|
32
32
|
"database"
|
|
33
33
|
],
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@eslint/js": "^9.
|
|
35
|
+
"@eslint/js": "^9.39.0",
|
|
36
36
|
"@types/luxon": "^3.7.1",
|
|
37
37
|
"@types/node": "^24.9.2",
|
|
38
38
|
"@typescript-eslint/eslint-plugin": "^8.46.2",
|
|
39
39
|
"@typescript-eslint/parser": "^8.46.2",
|
|
40
40
|
"@vitest/coverage-v8": "^4.0.6",
|
|
41
41
|
"@vitest/ui": "^4.0.6",
|
|
42
|
-
"eslint": "^9.
|
|
42
|
+
"eslint": "^9.39.0",
|
|
43
43
|
"eslint-config-prettier": "^10.1.8",
|
|
44
44
|
"eslint-plugin-import": "^2.32.0",
|
|
45
45
|
"eslint-plugin-vitest": "^0.5.4",
|
package/src/core/ForgeSQLORM.ts
CHANGED
|
@@ -204,31 +204,31 @@ class ForgeSQLORMImpl implements ForgeSqlOperation {
|
|
|
204
204
|
},
|
|
205
205
|
},
|
|
206
206
|
async () => {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
207
|
+
const result = await query();
|
|
208
|
+
const metadata = await getLastestMetadata();
|
|
209
|
+
try {
|
|
210
|
+
if (metadata) {
|
|
211
|
+
await onMetadata(
|
|
212
|
+
metadata.totalDbExecutionTime,
|
|
213
|
+
metadata.totalResponseSize,
|
|
214
|
+
metadata.printQueriesWithPlan,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
} catch (e: any) {
|
|
218
|
+
// eslint-disable-next-line no-console
|
|
219
|
+
console.error(
|
|
220
|
+
"[ForgeSQLORM][executeWithMetadata] Failed to run onMetadata callback",
|
|
221
|
+
{
|
|
222
|
+
errorMessage: e?.message,
|
|
223
|
+
errorStack: e?.stack,
|
|
224
|
+
totalDbExecutionTime: metadata?.totalDbExecutionTime,
|
|
225
|
+
totalResponseSize: metadata?.totalResponseSize,
|
|
226
|
+
beginTime: metadata?.beginTime,
|
|
227
|
+
},
|
|
228
|
+
e,
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
return result;
|
|
232
232
|
},
|
|
233
233
|
);
|
|
234
234
|
}
|
|
@@ -780,7 +780,10 @@ class ForgeSQLORMImpl implements ForgeSqlOperation {
|
|
|
780
780
|
* const result = await forgeSQL.executeCacheable("SELECT * FROM users WHERE status = 'active'");
|
|
781
781
|
* ```
|
|
782
782
|
*/
|
|
783
|
-
executeCacheable<T>(
|
|
783
|
+
executeCacheable<T>(
|
|
784
|
+
query: SQLWrapper | string,
|
|
785
|
+
cacheTtl?: number,
|
|
786
|
+
): Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, T>> {
|
|
784
787
|
return this.drizzle.executeQueryCacheable<T>(query, cacheTtl);
|
|
785
788
|
}
|
|
786
789
|
|
|
@@ -1340,7 +1343,10 @@ class ForgeSQLORM implements ForgeSqlOperation {
|
|
|
1340
1343
|
* const result = await forgeSQL.executeCacheable("SELECT * FROM users WHERE status = 'active'");
|
|
1341
1344
|
* ```
|
|
1342
1345
|
*/
|
|
1343
|
-
executeCacheable(
|
|
1346
|
+
executeCacheable<T>(
|
|
1347
|
+
query: SQLWrapper | string,
|
|
1348
|
+
cacheTtl?: number,
|
|
1349
|
+
): Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, T>> {
|
|
1344
1350
|
return this.ormInstance.executeCacheable(query, cacheTtl);
|
|
1345
1351
|
}
|
|
1346
1352
|
|
package/src/utils/cacheUtils.ts
CHANGED
|
@@ -47,6 +47,27 @@ function nowPlusSeconds(secondsToAdd: number): number {
|
|
|
47
47
|
return Math.floor(dt.toSeconds());
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Extracts all table/column names between backticks from SQL query and returns them as comma-separated string.
|
|
52
|
+
*
|
|
53
|
+
* @param sql - SQL query string
|
|
54
|
+
* @returns Comma-separated string of unique backticked values
|
|
55
|
+
*/
|
|
56
|
+
function extractBacktickedValues(sql: string): string {
|
|
57
|
+
const regex = /`([^`]+)`/g;
|
|
58
|
+
const matches = new Set<string>();
|
|
59
|
+
let match;
|
|
60
|
+
|
|
61
|
+
while ((match = regex.exec(sql.toLowerCase())) !== null) {
|
|
62
|
+
if (!match[1].startsWith("a_")) {
|
|
63
|
+
matches.add(`\`${match[1]}\``);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Sort to ensure consistent order for the same input
|
|
68
|
+
return Array.from(matches).sort().join(",");
|
|
69
|
+
}
|
|
70
|
+
|
|
50
71
|
/**
|
|
51
72
|
* Generates a hash key for a query based on its SQL and parameters.
|
|
52
73
|
*
|
|
@@ -339,7 +360,7 @@ export async function getFromCache<T>(
|
|
|
339
360
|
if (
|
|
340
361
|
cacheResult &&
|
|
341
362
|
(cacheResult[expirationName] as number) >= getCurrentTime() &&
|
|
342
|
-
sqlQuery.sql
|
|
363
|
+
extractBacktickedValues(sqlQuery.sql) === cacheResult[entityQueryName]
|
|
343
364
|
) {
|
|
344
365
|
if (options.logCache) {
|
|
345
366
|
// eslint-disable-next-line no-console
|
|
@@ -400,7 +421,7 @@ export async function setCacheResult(
|
|
|
400
421
|
.set(
|
|
401
422
|
key,
|
|
402
423
|
{
|
|
403
|
-
[entityQueryName]: sqlQuery.sql
|
|
424
|
+
[entityQueryName]: extractBacktickedValues(sqlQuery.sql),
|
|
404
425
|
[expirationName]: nowPlusSeconds(cacheTtl),
|
|
405
426
|
[dataName]: JSON.stringify(results),
|
|
406
427
|
},
|
package/src/utils/forgeDriver.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { sql, UpdateQueryResponse } from "@forge/sql";
|
|
2
2
|
import { saveMetaDataToContext } from "./metadataContextUtils";
|
|
3
3
|
import { getOperationType } from "./requestTypeContextUtils";
|
|
4
|
-
import {withTimeout} from "./sqlUtils";
|
|
4
|
+
import { withTimeout } from "./sqlUtils";
|
|
5
5
|
|
|
6
|
-
const timeoutMs =10000;
|
|
6
|
+
const timeoutMs = 10000;
|
|
7
7
|
const timeoutMessage = `Atlassian @forge/sql did not return a response within ${timeoutMs}ms (${timeoutMs / 1000} seconds), so the request is blocked. Possible causes: slow query, network issues, or exceeding Forge SQL limits.`;
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -145,7 +145,11 @@ async function processAllMethod(query: string, params: unknown[]): Promise<Forge
|
|
|
145
145
|
await sqlStatement.bindParams(...params);
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
const result = (await withTimeout(
|
|
148
|
+
const result = (await withTimeout(
|
|
149
|
+
sqlStatement.execute(),
|
|
150
|
+
timeoutMessage,
|
|
151
|
+
timeoutMs,
|
|
152
|
+
)) as ForgeSQLResult;
|
|
149
153
|
await saveMetaDataToContext(result.metadata);
|
|
150
154
|
|
|
151
155
|
if (!result.rows) {
|
|
@@ -188,7 +192,11 @@ export const forgeDriver = async (
|
|
|
188
192
|
const operationType = await getOperationType();
|
|
189
193
|
// Handle DDL operations
|
|
190
194
|
if (operationType === "DDL") {
|
|
191
|
-
const result = await withTimeout(
|
|
195
|
+
const result = await withTimeout(
|
|
196
|
+
sql.executeDDL(inlineParams(query, params)),
|
|
197
|
+
timeoutMessage,
|
|
198
|
+
timeoutMs,
|
|
199
|
+
);
|
|
192
200
|
return await processDDLResult(method, result);
|
|
193
201
|
}
|
|
194
202
|
|
|
@@ -19,10 +19,7 @@ export async function saveMetaDataToContext(metadata?: ForgeSQLMetadata): Promis
|
|
|
19
19
|
if (process.env.NODE_ENV !== "test") {
|
|
20
20
|
await new Promise((r) => setTimeout(r, 200));
|
|
21
21
|
}
|
|
22
|
-
|
|
23
|
-
context.forgeSQLORM,
|
|
24
|
-
Date.now() - context.beginTime.getTime(),
|
|
25
|
-
);
|
|
22
|
+
await printQueriesWithPlan(context.forgeSQLORM, Date.now() - context.beginTime.getTime());
|
|
26
23
|
};
|
|
27
24
|
if (metadata) {
|
|
28
25
|
context.totalResponseSize += metadata.responseSize;
|
package/src/utils/sqlUtils.ts
CHANGED
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
AnyColumn,
|
|
4
4
|
Column,
|
|
5
5
|
gte,
|
|
6
|
-
|
|
6
|
+
ilike,
|
|
7
7
|
isNotNull,
|
|
8
8
|
isTable,
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
ne,
|
|
10
|
+
not,
|
|
11
11
|
notInArray,
|
|
12
12
|
SQL,
|
|
13
13
|
sql,
|
|
@@ -20,16 +20,14 @@ import { AnyIndexBuilder } from "drizzle-orm/mysql-core/indexes";
|
|
|
20
20
|
import { CheckBuilder } from "drizzle-orm/mysql-core/checks";
|
|
21
21
|
import { ForeignKeyBuilder } from "drizzle-orm/mysql-core/foreign-keys";
|
|
22
22
|
import { UniqueConstraintBuilder } from "drizzle-orm/mysql-core/unique-constraint";
|
|
23
|
-
import {
|
|
24
|
-
SelectedFields
|
|
25
|
-
} from "drizzle-orm/mysql-core/query-builders/select.types";
|
|
23
|
+
import { SelectedFields } from "drizzle-orm/mysql-core/query-builders/select.types";
|
|
26
24
|
import { MySqlTable } from "drizzle-orm/mysql-core";
|
|
27
25
|
import { isSQLWrapper } from "drizzle-orm/sql/sql";
|
|
28
|
-
import {clusterStatementsSummary, slowQuery} from "../core/SystemTables";
|
|
26
|
+
import { clusterStatementsSummary, slowQuery } from "../core/SystemTables";
|
|
29
27
|
import { ForgeSqlOperation } from "../core/ForgeSQLQueryBuilder";
|
|
30
|
-
import { ColumnDataType} from "drizzle-orm/column-builder";
|
|
31
|
-
import {AnyMySqlColumn} from "drizzle-orm/mysql-core/columns/common";
|
|
32
|
-
import type {ColumnBaseConfig} from "drizzle-orm/column";
|
|
28
|
+
import { ColumnDataType } from "drizzle-orm/column-builder";
|
|
29
|
+
import { AnyMySqlColumn } from "drizzle-orm/mysql-core/columns/common";
|
|
30
|
+
import type { ColumnBaseConfig } from "drizzle-orm/column";
|
|
33
31
|
|
|
34
32
|
/**
|
|
35
33
|
* Interface representing table metadata information
|
|
@@ -591,8 +589,8 @@ export async function printQueriesWithPlan(
|
|
|
591
589
|
) {
|
|
592
590
|
try {
|
|
593
591
|
const statementsTable = clusterStatementsSummary;
|
|
594
|
-
|
|
595
|
-
|
|
592
|
+
const timeoutMs = timeout ?? 3000;
|
|
593
|
+
const results = await withTimeout(
|
|
596
594
|
forgeSQLORM
|
|
597
595
|
.getDrizzleQueryBuilder()
|
|
598
596
|
.select({
|
|
@@ -601,14 +599,21 @@ export async function printQueriesWithPlan(
|
|
|
601
599
|
avgMem: statementsTable.avgMem,
|
|
602
600
|
execCount: statementsTable.execCount,
|
|
603
601
|
plan: statementsTable.plan,
|
|
604
|
-
|
|
602
|
+
stmtType: statementsTable.stmtType,
|
|
605
603
|
})
|
|
606
604
|
.from(statementsTable)
|
|
607
605
|
.where(
|
|
608
606
|
and(
|
|
609
607
|
isNotNull(statementsTable.digest),
|
|
610
|
-
|
|
611
|
-
notInArray(statementsTable.stmtType, [
|
|
608
|
+
not(ilike(statementsTable.digestText, "%information_schema%")),
|
|
609
|
+
notInArray(statementsTable.stmtType, [
|
|
610
|
+
"Use",
|
|
611
|
+
"Set",
|
|
612
|
+
"Show",
|
|
613
|
+
"Commit",
|
|
614
|
+
"Rollback",
|
|
615
|
+
"Begin",
|
|
616
|
+
]),
|
|
612
617
|
gte(
|
|
613
618
|
statementsTable.lastSeen,
|
|
614
619
|
sql`DATE_SUB
|
|
@@ -619,9 +624,8 @@ export async function printQueriesWithPlan(
|
|
|
619
624
|
),
|
|
620
625
|
),
|
|
621
626
|
),
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
timeoutMs+200,
|
|
627
|
+
`Timeout ${timeoutMs}ms in printQueriesWithPlan - transient timeouts are usually fine; repeated timeouts mean this diagnostic query is consistently slow and should be investigated`,
|
|
628
|
+
timeoutMs + 200,
|
|
625
629
|
);
|
|
626
630
|
|
|
627
631
|
results.forEach((result) => {
|
|
@@ -644,11 +648,11 @@ export async function printQueriesWithPlan(
|
|
|
644
648
|
}
|
|
645
649
|
}
|
|
646
650
|
|
|
647
|
-
const SESSION_ALIAS_NAME_ORM =
|
|
651
|
+
const SESSION_ALIAS_NAME_ORM = "orm";
|
|
648
652
|
|
|
649
653
|
/**
|
|
650
654
|
* Analyzes and logs slow queries from the last specified number of hours.
|
|
651
|
-
*
|
|
655
|
+
*
|
|
652
656
|
* This function queries the slow query system table to find queries that were executed
|
|
653
657
|
* within the specified time window and logs detailed performance information including:
|
|
654
658
|
* - SQL query text
|
|
@@ -656,77 +660,81 @@ const SESSION_ALIAS_NAME_ORM = 'orm';
|
|
|
656
660
|
* - Query execution time (in ms)
|
|
657
661
|
* - Execution count
|
|
658
662
|
* - Execution plan
|
|
659
|
-
*
|
|
663
|
+
*
|
|
660
664
|
* @param forgeSQLORM - The ForgeSQL operation instance for database access
|
|
661
665
|
* @param hours - Number of hours to look back for slow queries (e.g., 1 for last hour, 24 for last day)
|
|
662
666
|
* @param timeout - Optional timeout in milliseconds for the query execution (defaults to 1500ms)
|
|
663
|
-
*
|
|
667
|
+
*
|
|
664
668
|
* @example
|
|
665
669
|
* ```typescript
|
|
666
670
|
* // Analyze slow queries from the last hour
|
|
667
671
|
* await slowQueryPerHours(forgeSQLORM, 1);
|
|
668
|
-
*
|
|
672
|
+
*
|
|
669
673
|
* // Analyze slow queries from the last 24 hours with custom timeout
|
|
670
674
|
* await slowQueryPerHours(forgeSQLORM, 24, 3000);
|
|
671
|
-
*
|
|
675
|
+
*
|
|
672
676
|
* // Analyze slow queries from the last 6 hours
|
|
673
677
|
* await slowQueryPerHours(forgeSQLORM, 6);
|
|
674
678
|
* ```
|
|
675
|
-
*
|
|
679
|
+
*
|
|
676
680
|
* @throws Does not throw - errors are logged to console.debug instead
|
|
677
681
|
*/
|
|
678
|
-
export async function slowQueryPerHours(
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
682
|
+
export async function slowQueryPerHours(
|
|
683
|
+
forgeSQLORM: ForgeSqlOperation,
|
|
684
|
+
hours: number,
|
|
685
|
+
timeout?: number,
|
|
686
|
+
) {
|
|
687
|
+
try {
|
|
688
|
+
const timeoutMs = timeout ?? 1500;
|
|
689
|
+
const results = await withTimeout(
|
|
690
|
+
forgeSQLORM
|
|
691
|
+
.getDrizzleQueryBuilder()
|
|
692
|
+
.select({
|
|
693
|
+
query: withTidbHint(slowQuery.query),
|
|
694
|
+
queryTime: slowQuery.queryTime,
|
|
695
|
+
memMax: slowQuery.memMax,
|
|
696
|
+
plan: slowQuery.plan,
|
|
697
|
+
})
|
|
698
|
+
.from(slowQuery)
|
|
699
|
+
.where(
|
|
700
|
+
and(
|
|
701
|
+
isNotNull(slowQuery.digest),
|
|
702
|
+
ne(slowQuery.sessionAlias, SESSION_ALIAS_NAME_ORM),
|
|
703
|
+
gte(
|
|
704
|
+
slowQuery.time,
|
|
705
|
+
sql`DATE_SUB
|
|
698
706
|
(NOW(), INTERVAL
|
|
699
707
|
${hours}
|
|
700
708
|
HOUR
|
|
701
709
|
)`,
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
710
|
+
),
|
|
711
|
+
),
|
|
712
|
+
),
|
|
713
|
+
`Timeout ${timeoutMs}ms in slowQueryPerHours - transient timeouts are usually fine; repeated timeouts mean this diagnostic query is consistently slow and should be investigated`,
|
|
714
|
+
timeoutMs,
|
|
715
|
+
);
|
|
716
|
+
const response: string[] = [];
|
|
717
|
+
results.forEach((result) => {
|
|
718
|
+
// Convert memory from bytes to MB and handle null values
|
|
719
|
+
const memMaxMB = result.memMax ? Number(result.memMax) / 1_000_000 : 0;
|
|
720
|
+
|
|
721
|
+
const message = `Found SlowQuery SQL: ${result.query} | Memory: ${memMaxMB.toFixed(2)} MB | Time: ${result.queryTime} ms\n Plan:${result.plan}`;
|
|
722
|
+
response.push(message);
|
|
723
|
+
// 1. Query info: SQL, memory, time, executions
|
|
724
|
+
// eslint-disable-next-line no-console
|
|
725
|
+
console.warn(message);
|
|
726
|
+
});
|
|
727
|
+
return response;
|
|
728
|
+
} catch (error) {
|
|
729
|
+
// eslint-disable-next-line no-console
|
|
730
|
+
console.debug(
|
|
731
|
+
`Error occurred while retrieving query execution plan: ${error instanceof Error ? error.message : "Unknown error"}. Try again after some time`,
|
|
732
|
+
error,
|
|
733
|
+
);
|
|
734
|
+
return [
|
|
735
|
+
`Error occurred while retrieving query execution plan: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
736
|
+
];
|
|
737
|
+
}
|
|
730
738
|
}
|
|
731
739
|
|
|
732
740
|
/**
|
|
@@ -737,29 +745,33 @@ export async function slowQueryPerHours(forgeSQLORM: ForgeSqlOperation, hours:nu
|
|
|
737
745
|
* @returns Promise that resolves with the result or rejects on timeout
|
|
738
746
|
* @throws {Error} When the operation times out
|
|
739
747
|
*/
|
|
740
|
-
export async function withTimeout<T>(
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
748
|
+
export async function withTimeout<T>(
|
|
749
|
+
promise: Promise<T>,
|
|
750
|
+
message: string,
|
|
751
|
+
timeoutMs: number,
|
|
752
|
+
): Promise<T> {
|
|
753
|
+
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
754
|
+
|
|
755
|
+
const timeoutPromise = new Promise<never>((_, reject) => {
|
|
756
|
+
timeoutId = setTimeout(() => {
|
|
757
|
+
reject(new Error(message));
|
|
758
|
+
}, timeoutMs);
|
|
759
|
+
});
|
|
750
760
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
}
|
|
761
|
+
try {
|
|
762
|
+
return await Promise.race([promise, timeoutPromise]);
|
|
763
|
+
} finally {
|
|
764
|
+
if (timeoutId) {
|
|
765
|
+
clearTimeout(timeoutId);
|
|
757
766
|
}
|
|
767
|
+
}
|
|
758
768
|
}
|
|
759
769
|
|
|
760
|
-
export function withTidbHint<
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
770
|
+
export function withTidbHint<
|
|
771
|
+
TDataType extends ColumnDataType,
|
|
772
|
+
TPartial extends Partial<ColumnBaseConfig<TDataType, string>>,
|
|
773
|
+
>(column: AnyMySqlColumn<TPartial>): AnyMySqlColumn<TPartial> {
|
|
774
|
+
// We lie a bit to TypeScript here: at runtime this is a new SQL fragment,
|
|
775
|
+
// but returning TExpr keeps the column type info in downstream inference.
|
|
776
|
+
return sql`/*+ SET_VAR(tidb_session_alias=${sql.raw(`${SESSION_ALIAS_NAME_ORM}`)}) */ ${column}` as unknown as AnyMySqlColumn<TPartial>;
|
|
764
777
|
}
|
|
765
|
-
|