forge-sql-orm 2.1.11 → 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 +800 -541
- 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.d.ts +1 -1
- package/dist/core/ForgeSQLORM.d.ts.map +1 -1
- 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.d.ts.map +1 -1
- 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.d.ts.map +1 -1
- 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/core/ForgeSQLORM.ts +33 -27
- package/src/lib/drizzle/extensions/additionalActions.ts +11 -0
- package/src/utils/cacheContextUtils.ts +9 -6
- package/src/utils/cacheUtils.ts +28 -5
- package/src/utils/forgeDriver.ts +10 -6
- package/src/utils/metadataContextUtils.ts +1 -4
- package/src/utils/sqlUtils.ts +136 -125
- package/src/webtriggers/slowQuerySchedulerTrigger.ts +40 -33
- package/dist/ForgeSQLORM.js +0 -3896
- package/dist/ForgeSQLORM.js.map +0 -1
- package/dist/ForgeSQLORM.mjs +0 -3879
- package/dist/ForgeSQLORM.mjs.map +0 -1
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.applySchemaMigrations = void 0;
|
|
4
|
+
const sql_1 = require("@forge/sql");
|
|
5
|
+
/**
|
|
6
|
+
* Web trigger for applying database schema migrations in Atlassian Forge SQL.
|
|
7
|
+
* This function handles the complete migration process including:
|
|
8
|
+
* - Database provisioning
|
|
9
|
+
* - Migration execution
|
|
10
|
+
* - Migration history tracking
|
|
11
|
+
*
|
|
12
|
+
* @param migration - A function that takes a MigrationRunner instance and returns a Promise of MigrationRunner
|
|
13
|
+
* This function should define the sequence of migrations to be applied
|
|
14
|
+
* @returns {Promise<{
|
|
15
|
+
* headers: { "Content-Type": ["application/json"] },
|
|
16
|
+
* statusCode: number,
|
|
17
|
+
* statusText: string,
|
|
18
|
+
* body: string
|
|
19
|
+
* }>} A response object containing:
|
|
20
|
+
* - headers: Content-Type header set to application/json
|
|
21
|
+
* - statusCode: 200 on success
|
|
22
|
+
* - statusText: "OK" on success
|
|
23
|
+
* - body: Success message or error details
|
|
24
|
+
*
|
|
25
|
+
* @throws {Error} If database provisioning fails
|
|
26
|
+
* @throws {Error} If migration execution fails
|
|
27
|
+
*/
|
|
28
|
+
const applySchemaMigrations = async (migration) => {
|
|
29
|
+
try {
|
|
30
|
+
if (typeof migration !== "function") {
|
|
31
|
+
throw new Error("migration is not a function");
|
|
32
|
+
}
|
|
33
|
+
// eslint-disable-next-line no-console
|
|
34
|
+
console.debug("Provisioning the database");
|
|
35
|
+
await sql_1.sql._provision();
|
|
36
|
+
// eslint-disable-next-line no-console
|
|
37
|
+
console.debug("Running schema migrations");
|
|
38
|
+
const migrations = await migration(sql_1.migrationRunner);
|
|
39
|
+
const successfulMigrations = await migrations.run();
|
|
40
|
+
// eslint-disable-next-line no-console
|
|
41
|
+
console.debug("Migrations applied:", successfulMigrations);
|
|
42
|
+
const migrationList = await sql_1.migrationRunner.list();
|
|
43
|
+
let migrationHistory = "No migrations found";
|
|
44
|
+
if (Array.isArray(migrationList) && migrationList.length > 0) {
|
|
45
|
+
const sortedMigrations = migrationList.toSorted((a, b) => a.migratedAt.getTime() - b.migratedAt.getTime());
|
|
46
|
+
migrationHistory = sortedMigrations
|
|
47
|
+
.map((y) => `${y.id}, ${y.name}, ${y.migratedAt.toUTCString()}`)
|
|
48
|
+
.join("\n");
|
|
49
|
+
}
|
|
50
|
+
// eslint-disable-next-line no-console
|
|
51
|
+
console.debug("Migrations history:\nid, name, migrated_at\n", migrationHistory);
|
|
52
|
+
return {
|
|
53
|
+
headers: { "Content-Type": ["application/json"] },
|
|
54
|
+
statusCode: 200,
|
|
55
|
+
statusText: "OK",
|
|
56
|
+
body: "Migrations successfully executed",
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
const errorMessage = error?.cause?.context?.debug?.sqlMessage ??
|
|
61
|
+
error?.cause?.context?.debug?.message ??
|
|
62
|
+
error?.debug?.context?.sqlMessage ??
|
|
63
|
+
error?.debug?.context?.message ??
|
|
64
|
+
error.message ??
|
|
65
|
+
"Unknown error occurred";
|
|
66
|
+
// eslint-disable-next-line no-console
|
|
67
|
+
console.error("Error during migration:", errorMessage);
|
|
68
|
+
return {
|
|
69
|
+
headers: { "Content-Type": ["application/json"] },
|
|
70
|
+
statusCode: 500,
|
|
71
|
+
statusText: "Internal Server Error",
|
|
72
|
+
body: error instanceof Error ? errorMessage : "Unknown error during migration",
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
exports.applySchemaMigrations = applySchemaMigrations;
|
|
77
|
+
//# sourceMappingURL=applyMigrationsWebTrigger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applyMigrationsWebTrigger.js","sourceRoot":"","sources":["../../src/webtriggers/applyMigrationsWebTrigger.ts"],"names":[],"mappings":";;;AAAA,oCAAkD;AAGlD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACI,MAAM,qBAAqB,GAAG,KAAK,EACxC,SAAyE,EACzE,EAAE;IACF,IAAI,CAAC;QACH,IAAI,OAAO,SAAS,KAAK,UAAU,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACjD,CAAC;QACD,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC3C,MAAM,SAAG,CAAC,UAAU,EAAE,CAAC;QACvB,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC3C,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,qBAAe,CAAC,CAAC;QACpD,MAAM,oBAAoB,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,CAAC;QACpD,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,oBAAoB,CAAC,CAAC;QAE3D,MAAM,aAAa,GAAG,MAAM,qBAAe,CAAC,IAAI,EAAE,CAAC;QACnD,IAAI,gBAAgB,GAAG,qBAAqB,CAAC;QAE7C,IAAI,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7D,MAAM,gBAAgB,GAAG,aAAa,CAAC,QAAQ,CAC7C,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,UAAU,CAAC,OAAO,EAAE,CAC1D,CAAC;YAEF,gBAAgB,GAAG,gBAAgB;iBAChC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,CAAC;iBAC/D,IAAI,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC;QACD,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,8CAA8C,EAAE,gBAAgB,CAAC,CAAC;QAEhF,OAAO;YACL,OAAO,EAAE,EAAE,cAAc,EAAE,CAAC,kBAAkB,CAAC,EAAE;YACjD,UAAU,EAAE,GAAG;YACf,UAAU,EAAE,IAAI;YAChB,IAAI,EAAE,kCAAkC;SACzC,CAAC;IACJ,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,MAAM,YAAY,GAChB,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU;YACxC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO;YACrC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU;YACjC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO;YAC9B,KAAK,CAAC,OAAO;YACb,wBAAwB,CAAC;QAC3B,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,YAAY,CAAC,CAAC;QACvD,OAAO;YACL,OAAO,EAAE,EAAE,cAAc,EAAE,CAAC,kBAAkB,CAAC,EAAE;YACjD,UAAU,EAAE,GAAG;YACf,UAAU,EAAE,uBAAuB;YACnC,IAAI,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,gCAAgC;SAC/E,CAAC;IACJ,CAAC;AACH,CAAC,CAAC;AAvDW,QAAA,qBAAqB,yBAuDhC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.clearCacheSchedulerTrigger = void 0;
|
|
4
|
+
const cacheUtils_1 = require("../utils/cacheUtils");
|
|
5
|
+
/**
|
|
6
|
+
* Scheduler trigger for clearing expired cache entries.
|
|
7
|
+
*
|
|
8
|
+
* This trigger should be configured as a Forge scheduler to automatically
|
|
9
|
+
* clean up expired cache entries based on their TTL (Time To Live).
|
|
10
|
+
*
|
|
11
|
+
* @param options - Optional ForgeSQL ORM configuration. If not provided,
|
|
12
|
+
* uses default cache settings with cacheEntityName: "cache"
|
|
13
|
+
* @returns Promise that resolves to HTTP response object
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* // In your index.ts
|
|
18
|
+
* import { clearCacheSchedulerTrigger } from "forge-sql-orm";
|
|
19
|
+
*
|
|
20
|
+
* export const clearCache = () => {
|
|
21
|
+
* return clearCacheSchedulerTrigger({
|
|
22
|
+
* cacheEntityName: "cache",
|
|
23
|
+
* logRawSqlQuery: true
|
|
24
|
+
* });
|
|
25
|
+
* };
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```yaml
|
|
30
|
+
* # In manifest.yml
|
|
31
|
+
* scheduledTrigger:
|
|
32
|
+
* - key: clear-cache-trigger
|
|
33
|
+
* function: clearCache
|
|
34
|
+
* interval: fiveMinute
|
|
35
|
+
*
|
|
36
|
+
* function:
|
|
37
|
+
* - key: clearCache
|
|
38
|
+
* handler: index.clearCache
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
const clearCacheSchedulerTrigger = async (options) => {
|
|
42
|
+
try {
|
|
43
|
+
const newOptions = options ?? {
|
|
44
|
+
logRawSqlQuery: false,
|
|
45
|
+
disableOptimisticLocking: false,
|
|
46
|
+
cacheTTL: 120,
|
|
47
|
+
cacheEntityName: "cache",
|
|
48
|
+
cacheEntityQueryName: "sql",
|
|
49
|
+
cacheEntityExpirationName: "expiration",
|
|
50
|
+
cacheEntityDataName: "data",
|
|
51
|
+
};
|
|
52
|
+
if (!newOptions.cacheEntityName) {
|
|
53
|
+
throw new Error("cacheEntityName is not configured");
|
|
54
|
+
}
|
|
55
|
+
await (0, cacheUtils_1.clearExpiredCache)(newOptions);
|
|
56
|
+
return {
|
|
57
|
+
headers: { "Content-Type": ["application/json"] },
|
|
58
|
+
statusCode: 200,
|
|
59
|
+
statusText: "OK",
|
|
60
|
+
body: JSON.stringify({
|
|
61
|
+
success: true,
|
|
62
|
+
message: "Cache cleanup completed successfully",
|
|
63
|
+
timestamp: new Date().toISOString(),
|
|
64
|
+
}),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
// eslint-disable-next-line no-console
|
|
69
|
+
console.error("Error during cache cleanup: ", JSON.stringify(error));
|
|
70
|
+
return {
|
|
71
|
+
headers: { "Content-Type": ["application/json"] },
|
|
72
|
+
statusCode: 500,
|
|
73
|
+
statusText: "Internal Server Error",
|
|
74
|
+
body: JSON.stringify({
|
|
75
|
+
success: false,
|
|
76
|
+
error: error instanceof Error ? error.message : "Unknown error during cache cleanup",
|
|
77
|
+
timestamp: new Date().toISOString(),
|
|
78
|
+
}),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
exports.clearCacheSchedulerTrigger = clearCacheSchedulerTrigger;
|
|
83
|
+
//# sourceMappingURL=clearCacheSchedulerTrigger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clearCacheSchedulerTrigger.js","sourceRoot":"","sources":["../../src/webtriggers/clearCacheSchedulerTrigger.ts"],"names":[],"mappings":";;;AAAA,oDAAwD;AAGxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACI,MAAM,0BAA0B,GAAG,KAAK,EAAE,OAA4B,EAAE,EAAE;IAC/E,IAAI,CAAC;QACH,MAAM,UAAU,GAAuB,OAAO,IAAI;YAChD,cAAc,EAAE,KAAK;YACrB,wBAAwB,EAAE,KAAK;YAC/B,QAAQ,EAAE,GAAG;YACb,eAAe,EAAE,OAAO;YACxB,oBAAoB,EAAE,KAAK;YAC3B,yBAAyB,EAAE,YAAY;YACvC,mBAAmB,EAAE,MAAM;SAC5B,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,eAAe,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvD,CAAC;QACD,MAAM,IAAA,8BAAiB,EAAC,UAAU,CAAC,CAAC;QAEpC,OAAO;YACL,OAAO,EAAE,EAAE,cAAc,EAAE,CAAC,kBAAkB,CAAC,EAAE;YACjD,UAAU,EAAE,GAAG;YACf,UAAU,EAAE,IAAI;YAChB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,sCAAsC;gBAC/C,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;SACH,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;QACrE,OAAO;YACL,OAAO,EAAE,EAAE,cAAc,EAAE,CAAC,kBAAkB,CAAC,EAAE;YACjD,UAAU,EAAE,GAAG;YACf,UAAU,EAAE,uBAAuB;YACnC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,oCAAoC;gBACpF,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;SACH,CAAC;IACJ,CAAC;AACH,CAAC,CAAC;AAxCW,QAAA,0BAA0B,8BAwCrC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dropSchemaMigrations = dropSchemaMigrations;
|
|
4
|
+
const sql_1 = require("@forge/sql");
|
|
5
|
+
const sqlUtils_1 = require("../utils/sqlUtils");
|
|
6
|
+
const index_1 = require("./index");
|
|
7
|
+
const SystemTables_1 = require("../core/SystemTables");
|
|
8
|
+
/**
|
|
9
|
+
* ⚠️ DEVELOPMENT ONLY WEB TRIGGER ⚠️
|
|
10
|
+
*
|
|
11
|
+
* This web trigger is designed for development environments only and will permanently delete all data in the specified tables and sequences.
|
|
12
|
+
* It generates and executes SQL statements to drop tables, their associated constraints, and sequences.
|
|
13
|
+
*
|
|
14
|
+
* @warning This trigger should NEVER be used in production environments because:
|
|
15
|
+
* - It permanently deletes all data in the specified tables and sequences
|
|
16
|
+
* - The operation cannot be undone
|
|
17
|
+
* - It may affect application functionality
|
|
18
|
+
* - It could lead to data loss and system instability
|
|
19
|
+
*
|
|
20
|
+
* @returns {Promise<TriggerResponse<string>>} A response containing:
|
|
21
|
+
* - On success: 200 status with warning message about permanent deletion of tables and sequences
|
|
22
|
+
* - On failure: 500 status with error message
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* // Example usage in development only
|
|
27
|
+
* await dropSchemaMigrations();
|
|
28
|
+
* // ⚠️ Warning: This will permanently delete all data in users and orders tables and their sequences
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
async function dropSchemaMigrations() {
|
|
32
|
+
try {
|
|
33
|
+
const tables = await (0, SystemTables_1.getTables)();
|
|
34
|
+
// Generate drop statements
|
|
35
|
+
const dropStatements = (0, sqlUtils_1.generateDropTableStatements)(tables, { sequence: true, table: true });
|
|
36
|
+
// Execute each statement
|
|
37
|
+
for (const statement of dropStatements) {
|
|
38
|
+
// eslint-disable-next-line no-console
|
|
39
|
+
console.debug(`execute DDL: ${statement}`);
|
|
40
|
+
await sql_1.sql.executeDDL(statement);
|
|
41
|
+
}
|
|
42
|
+
return (0, index_1.getHttpResponse)(200, "⚠️ All data in these tables has been permanently deleted. This operation cannot be undone.");
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
const errorMessage = error?.debug?.sqlMessage ??
|
|
46
|
+
error?.debug?.message ??
|
|
47
|
+
error.message ??
|
|
48
|
+
"Unknown error occurred";
|
|
49
|
+
// eslint-disable-next-line no-console
|
|
50
|
+
console.error(errorMessage);
|
|
51
|
+
return (0, index_1.getHttpResponse)(500, errorMessage);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=dropMigrationWebTrigger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dropMigrationWebTrigger.js","sourceRoot":"","sources":["../../src/webtriggers/dropMigrationWebTrigger.ts"],"names":[],"mappings":";;AA4BA,oDA2BC;AAvDD,oCAAiC;AACjC,gDAAsF;AACtF,mCAA2D;AAC3D,uDAAiD;AAEjD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACI,KAAK,UAAU,oBAAoB;IACxC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAA,wBAAS,GAAE,CAAC;QACjC,2BAA2B;QAC3B,MAAM,cAAc,GAAG,IAAA,sCAAkB,EAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAEnF,yBAAyB;QACzB,KAAK,MAAM,SAAS,IAAI,cAAc,EAAE,CAAC;YACvC,sCAAsC;YACtC,OAAO,CAAC,KAAK,CAAC,gBAAgB,SAAS,EAAE,CAAC,CAAC;YAC3C,MAAM,SAAG,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC;QAED,OAAO,IAAA,uBAAe,EACpB,GAAG,EACH,4FAA4F,CAC7F,CAAC;IACJ,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,MAAM,YAAY,GAChB,KAAK,EAAE,KAAK,EAAE,UAAU;YACxB,KAAK,EAAE,KAAK,EAAE,OAAO;YACrB,KAAK,CAAC,OAAO;YACb,wBAAwB,CAAC;QAC3B,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAC5B,OAAO,IAAA,uBAAe,EAAS,GAAG,EAAE,YAAY,CAAC,CAAC;IACpD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dropTableSchemaMigrations = dropTableSchemaMigrations;
|
|
4
|
+
const sql_1 = require("@forge/sql");
|
|
5
|
+
const sqlUtils_1 = require("../utils/sqlUtils");
|
|
6
|
+
const index_1 = require("./index");
|
|
7
|
+
const SystemTables_1 = require("../core/SystemTables");
|
|
8
|
+
/**
|
|
9
|
+
* ⚠️ DEVELOPMENT ONLY WEB TRIGGER ⚠️
|
|
10
|
+
*
|
|
11
|
+
* This web trigger is designed for development environments only and will permanently delete all data in the specified tables.
|
|
12
|
+
* It generates and executes SQL statements to drop tables and their associated constraints.
|
|
13
|
+
*
|
|
14
|
+
* @warning This trigger should NEVER be used in production environments because:
|
|
15
|
+
* - It permanently deletes all data in the specified tables
|
|
16
|
+
* - The operation cannot be undone
|
|
17
|
+
* - It may affect application functionality
|
|
18
|
+
* - It could lead to data loss and system instability
|
|
19
|
+
*
|
|
20
|
+
* @returns {Promise<TriggerResponse<string>>} A response containing:
|
|
21
|
+
* - On success: 200 status with warning message about permanent deletion
|
|
22
|
+
* - On failure: 500 status with error message
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* // Example usage in development only
|
|
27
|
+
* await dropTableSchemaMigrations();
|
|
28
|
+
* // ⚠️ Warning: This will permanently delete all data in users and orders tables
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
async function dropTableSchemaMigrations() {
|
|
32
|
+
try {
|
|
33
|
+
const tables = await (0, SystemTables_1.getTables)();
|
|
34
|
+
// Generate drop statements
|
|
35
|
+
const dropStatements = (0, sqlUtils_1.generateDropTableStatements)(tables, { sequence: false, table: true });
|
|
36
|
+
// Execute each statement
|
|
37
|
+
for (const statement of dropStatements) {
|
|
38
|
+
// eslint-disable-next-line no-console
|
|
39
|
+
console.debug(`execute DDL: ${statement}`);
|
|
40
|
+
await sql_1.sql.executeDDL(statement);
|
|
41
|
+
}
|
|
42
|
+
return (0, index_1.getHttpResponse)(200, "⚠️ All data in these tables has been permanently deleted. This operation cannot be undone.");
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
const errorMessage = error?.debug?.sqlMessage ??
|
|
46
|
+
error?.debug?.message ??
|
|
47
|
+
error.message ??
|
|
48
|
+
"Unknown error occurred";
|
|
49
|
+
// eslint-disable-next-line no-console
|
|
50
|
+
console.error(errorMessage);
|
|
51
|
+
return (0, index_1.getHttpResponse)(500, errorMessage);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=dropTablesMigrationWebTrigger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dropTablesMigrationWebTrigger.js","sourceRoot":"","sources":["../../src/webtriggers/dropTablesMigrationWebTrigger.ts"],"names":[],"mappings":";;AA4BA,8DA2BC;AAvDD,oCAAiC;AACjC,gDAAsF;AACtF,mCAA2D;AAC3D,uDAAiD;AAEjD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACI,KAAK,UAAU,yBAAyB;IAC7C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAA,wBAAS,GAAE,CAAC;QACjC,2BAA2B;QAC3B,MAAM,cAAc,GAAG,IAAA,sCAAkB,EAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAEpF,yBAAyB;QACzB,KAAK,MAAM,SAAS,IAAI,cAAc,EAAE,CAAC;YACvC,sCAAsC;YACtC,OAAO,CAAC,KAAK,CAAC,gBAAgB,SAAS,EAAE,CAAC,CAAC;YAC3C,MAAM,SAAG,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC;QAED,OAAO,IAAA,uBAAe,EACpB,GAAG,EACH,4FAA4F,CAC7F,CAAC;IACJ,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,MAAM,YAAY,GAChB,KAAK,EAAE,KAAK,EAAE,UAAU;YACxB,KAAK,EAAE,KAAK,EAAE,OAAO;YACrB,KAAK,CAAC,OAAO;YACb,wBAAwB,CAAC;QAC3B,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAC5B,OAAO,IAAA,uBAAe,EAAS,GAAG,EAAE,YAAY,CAAC,CAAC;IACpD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchSchemaWebTrigger = fetchSchemaWebTrigger;
|
|
4
|
+
const sql_1 = require("@forge/sql");
|
|
5
|
+
const index_1 = require("./index");
|
|
6
|
+
const SystemTables_1 = require("../core/SystemTables");
|
|
7
|
+
const table_1 = require("drizzle-orm/table");
|
|
8
|
+
/**
|
|
9
|
+
* ⚠️ DEVELOPMENT ONLY WEB TRIGGER ⚠️
|
|
10
|
+
*
|
|
11
|
+
* This web trigger retrieves the current database schema from Atlassian Forge SQL.
|
|
12
|
+
* It generates SQL statements that can be used to recreate the database structure.
|
|
13
|
+
*
|
|
14
|
+
* @warning This trigger should ONLY be used in development environments. It:
|
|
15
|
+
* - Exposes your database structure
|
|
16
|
+
* - Disables foreign key checks temporarily
|
|
17
|
+
* - Generates SQL that could potentially be used maliciously
|
|
18
|
+
* - May expose sensitive table names and structures
|
|
19
|
+
*
|
|
20
|
+
* @returns {Promise<TriggerResponse<string>>} A response containing SQL statements to recreate the database schema
|
|
21
|
+
* - On success: Returns 200 status with SQL statements
|
|
22
|
+
* - On failure: Returns 500 status with error message
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* // The response will contain SQL statements like:
|
|
27
|
+
* // SET foreign_key_checks = 0;
|
|
28
|
+
* // CREATE TABLE IF NOT EXISTS users (...);
|
|
29
|
+
* // CREATE TABLE IF NOT EXISTS orders (...);
|
|
30
|
+
* // SET foreign_key_checks = 1;
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
async function fetchSchemaWebTrigger() {
|
|
34
|
+
try {
|
|
35
|
+
const tables = await (0, SystemTables_1.getTables)();
|
|
36
|
+
const createTableStatements = await generateCreateTableStatements(tables);
|
|
37
|
+
const sqlStatements = wrapWithForeignKeyChecks(createTableStatements);
|
|
38
|
+
return (0, index_1.getHttpResponse)(200, sqlStatements.join(";\n"));
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
const errorMessage = error?.debug?.sqlMessage ??
|
|
42
|
+
error?.debug?.message ??
|
|
43
|
+
error.message ??
|
|
44
|
+
"Unknown error occurred";
|
|
45
|
+
// eslint-disable-next-line no-console
|
|
46
|
+
console.error(errorMessage);
|
|
47
|
+
return (0, index_1.getHttpResponse)(500, errorMessage);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Generates CREATE TABLE statements for each table
|
|
52
|
+
*/
|
|
53
|
+
async function generateCreateTableStatements(tables) {
|
|
54
|
+
const statements = [];
|
|
55
|
+
for (const table of tables) {
|
|
56
|
+
const createTableResult = await sql_1.sql.executeDDL(`SHOW CREATE TABLE "${table}"`);
|
|
57
|
+
const createTableStatements = createTableResult.rows
|
|
58
|
+
.filter((row) => !isSystemTable(row.Table))
|
|
59
|
+
.map((row) => formatCreateTableStatement(row["Create Table"]));
|
|
60
|
+
statements.push(...createTableStatements);
|
|
61
|
+
}
|
|
62
|
+
return statements;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Checks if the table is a system table
|
|
66
|
+
*/
|
|
67
|
+
function isSystemTable(tableName) {
|
|
68
|
+
return SystemTables_1.forgeSystemTables.some((st) => (0, table_1.getTableName)(st) === tableName);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Formats the CREATE TABLE statement
|
|
72
|
+
*/
|
|
73
|
+
function formatCreateTableStatement(statement) {
|
|
74
|
+
return statement.replace(/"/g, "").replace("CREATE TABLE", "CREATE TABLE IF NOT EXISTS");
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Wraps the SQL statements with foreign key check controls
|
|
78
|
+
*/
|
|
79
|
+
function wrapWithForeignKeyChecks(statements) {
|
|
80
|
+
return ["SET foreign_key_checks = 0", ...statements, "SET foreign_key_checks = 1"];
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=fetchSchemaWebTrigger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetchSchemaWebTrigger.js","sourceRoot":"","sources":["../../src/webtriggers/fetchSchemaWebTrigger.ts"],"names":[],"mappings":";;AAmCA,sDAiBC;AApDD,oCAAiC;AACjC,mCAA2D;AAC3D,uDAAoE;AACpE,6CAAiD;AAOjD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACI,KAAK,UAAU,qBAAqB;IACzC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAA,wBAAS,GAAE,CAAC;QACjC,MAAM,qBAAqB,GAAG,MAAM,6BAA6B,CAAC,MAAM,CAAC,CAAC;QAC1E,MAAM,aAAa,GAAG,wBAAwB,CAAC,qBAAqB,CAAC,CAAC;QAEtE,OAAO,IAAA,uBAAe,EAAS,GAAG,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACjE,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,MAAM,YAAY,GAChB,KAAK,EAAE,KAAK,EAAE,UAAU;YACxB,KAAK,EAAE,KAAK,EAAE,OAAO;YACrB,KAAK,CAAC,OAAO;YACb,wBAAwB,CAAC;QAC3B,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAC5B,OAAO,IAAA,uBAAe,EAAS,GAAG,EAAE,YAAY,CAAC,CAAC;IACpD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,6BAA6B,CAAC,MAAgB;IAC3D,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,iBAAiB,GAAG,MAAM,SAAG,CAAC,UAAU,CAAiB,sBAAsB,KAAK,GAAG,CAAC,CAAC;QAE/F,MAAM,qBAAqB,GAAG,iBAAiB,CAAC,IAAI;aACjD,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;aAC1C,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,0BAA0B,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;QAEjE,UAAU,CAAC,IAAI,CAAC,GAAG,qBAAqB,CAAC,CAAC;IAC5C,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,SAAiB;IACtC,OAAO,gCAAiB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAA,oBAAY,EAAC,EAAE,CAAC,KAAK,SAAS,CAAC,CAAC;AACxE,CAAC;AAED;;GAEG;AACH,SAAS,0BAA0B,CAAC,SAAiB;IACnD,OAAO,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,4BAA4B,CAAC,CAAC;AAC3F,CAAC;AAED;;GAEG;AACH,SAAS,wBAAwB,CAAC,UAAoB;IACpD,OAAO,CAAC,4BAA4B,EAAE,GAAG,UAAU,EAAE,4BAA4B,CAAC,CAAC;AACrF,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.getHttpResponse = void 0;
|
|
18
|
+
__exportStar(require("./dropMigrationWebTrigger"), exports);
|
|
19
|
+
__exportStar(require("./applyMigrationsWebTrigger"), exports);
|
|
20
|
+
__exportStar(require("./fetchSchemaWebTrigger"), exports);
|
|
21
|
+
__exportStar(require("./dropTablesMigrationWebTrigger"), exports);
|
|
22
|
+
__exportStar(require("./clearCacheSchedulerTrigger"), exports);
|
|
23
|
+
__exportStar(require("./slowQuerySchedulerTrigger"), exports);
|
|
24
|
+
const getHttpResponse = (statusCode, body) => {
|
|
25
|
+
let statusText = "";
|
|
26
|
+
if (statusCode === 200) {
|
|
27
|
+
statusText = "Ok";
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
statusText = "Bad Request";
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
headers: { "Content-Type": ["application/json"] },
|
|
34
|
+
statusCode,
|
|
35
|
+
statusText,
|
|
36
|
+
body,
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
exports.getHttpResponse = getHttpResponse;
|
|
40
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/webtriggers/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,4DAA0C;AAC1C,8DAA4C;AAC5C,0DAAwC;AACxC,kEAAgD;AAChD,+DAA6C;AAC7C,8DAA4C;AASrC,MAAM,eAAe,GAAG,CAAO,UAAkB,EAAE,IAAU,EAAyB,EAAE;IAC7F,IAAI,UAAU,GAAG,EAAE,CAAC;IACpB,IAAI,UAAU,KAAK,GAAG,EAAE,CAAC;QACvB,UAAU,GAAG,IAAI,CAAC;IACpB,CAAC;SAAM,CAAC;QACN,UAAU,GAAG,aAAa,CAAC;IAC7B,CAAC;IAED,OAAO;QACL,OAAO,EAAE,EAAE,cAAc,EAAE,CAAC,kBAAkB,CAAC,EAAE;QACjD,UAAU;QACV,UAAU;QACV,IAAI;KACL,CAAC;AACJ,CAAC,CAAC;AAdW,QAAA,eAAe,mBAc1B"}
|
|
@@ -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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.slowQuerySchedulerTrigger = slowQuerySchedulerTrigger;
|
|
4
|
+
const index_1 = require("./index");
|
|
5
|
+
const sqlUtils_1 = require("../utils/sqlUtils");
|
|
6
|
+
/**
|
|
7
|
+
* Scheduler trigger for analyzing slow queries from the last specified number of hours.
|
|
8
|
+
*
|
|
9
|
+
* This trigger analyzes slow queries from TiDB's slow query log system table and provides
|
|
10
|
+
* detailed performance information including SQL query text, memory usage, execution time,
|
|
11
|
+
* and execution plans. It's designed to be used as a scheduled trigger in Atlassian Forge
|
|
12
|
+
* to monitor query performance over time.
|
|
13
|
+
*
|
|
14
|
+
* The function queries the slow query system table to find queries executed within the
|
|
15
|
+
* specified time window and logs detailed performance information to the console. Results
|
|
16
|
+
* are limited to the top 50 slow queries to prevent excessive output.
|
|
17
|
+
*
|
|
18
|
+
* @param forgeSQLORM - The ForgeSQL operation instance for database access
|
|
19
|
+
* @param options - Configuration options for the slow query analysis
|
|
20
|
+
* @param options.hours - Number of hours to look back for slow queries (default: 1)
|
|
21
|
+
* @param options.timeout - Timeout in milliseconds for the query execution (default: 2000ms)
|
|
22
|
+
*
|
|
23
|
+
* @returns Promise<TriggerResponse<string>> - HTTP response with JSON stringified query results or error message
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* import ForgeSQL, { slowQuerySchedulerTrigger } from "forge-sql-orm";
|
|
28
|
+
*
|
|
29
|
+
* const forgeSQL = new ForgeSQL();
|
|
30
|
+
*
|
|
31
|
+
* // Basic usage with default options (1 hour, 2000ms timeout)
|
|
32
|
+
* export const slowQueryTrigger = () =>
|
|
33
|
+
* slowQuerySchedulerTrigger(forgeSQL, { hours: 1, timeout: 2000 });
|
|
34
|
+
*
|
|
35
|
+
* // Analyze slow queries from the last 6 hours with extended timeout
|
|
36
|
+
* export const sixHourSlowQueryTrigger = () =>
|
|
37
|
+
* slowQuerySchedulerTrigger(forgeSQL, { hours: 6, timeout: 5000 });
|
|
38
|
+
*
|
|
39
|
+
* // Analyze slow queries from the last 24 hours
|
|
40
|
+
* export const dailySlowQueryTrigger = () =>
|
|
41
|
+
* slowQuerySchedulerTrigger(forgeSQL, { hours: 24, timeout: 3000 });
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```yaml
|
|
46
|
+
* # manifest.yml configuration
|
|
47
|
+
* scheduledTrigger:
|
|
48
|
+
* - key: slow-query-trigger
|
|
49
|
+
* function: slowQueryTrigger
|
|
50
|
+
* interval: hour
|
|
51
|
+
*
|
|
52
|
+
* function:
|
|
53
|
+
* - key: slowQueryTrigger
|
|
54
|
+
* handler: index.slowQueryTrigger
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @remarks
|
|
58
|
+
* - Results are automatically logged to the Forge Developer Console via `console.warn()`
|
|
59
|
+
* - The function returns up to 50 slow queries to prevent excessive logging
|
|
60
|
+
* - Transient timeouts are usually fine; repeated timeouts indicate the diagnostic query itself is slow
|
|
61
|
+
* - This trigger is best used with hourly intervals to catch slow queries in a timely manner
|
|
62
|
+
* - Error responses return HTTP 500 with error details
|
|
63
|
+
*
|
|
64
|
+
* @see {@link slowQueryPerHours} - The underlying function that performs the actual query analysis
|
|
65
|
+
*/
|
|
66
|
+
async function slowQuerySchedulerTrigger(forgeSQLORM, options) {
|
|
67
|
+
try {
|
|
68
|
+
return (0, index_1.getHttpResponse)(200, JSON.stringify(await (0, sqlUtils_1.slowQueryPerHours)(forgeSQLORM, options?.hours ?? 1, options?.timeout ?? 3000)));
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
const errorMessage = error?.debug?.sqlMessage ??
|
|
72
|
+
error?.debug?.message ??
|
|
73
|
+
error.message ??
|
|
74
|
+
"Unknown error occurred";
|
|
75
|
+
// eslint-disable-next-line no-console
|
|
76
|
+
console.error(errorMessage);
|
|
77
|
+
return (0, index_1.getHttpResponse)(500, errorMessage);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=slowQuerySchedulerTrigger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slowQuerySchedulerTrigger.js","sourceRoot":"","sources":["../../src/webtriggers/slowQuerySchedulerTrigger.ts"],"names":[],"mappings":";;AAgEA,8DAwBC;AAxFD,mCAA2D;AAC3D,gDAAsD;AAGtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACI,KAAK,UAAU,yBAAyB,CAC7C,WAA8B,EAC9B,OAGC;IAED,IAAI,CAAC;QACH,OAAO,IAAA,uBAAe,EACpB,GAAG,EACH,IAAI,CAAC,SAAS,CACZ,MAAM,IAAA,4BAAiB,EAAC,WAAW,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,IAAI,CAAC,CACpF,CACF,CAAC;IACJ,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,MAAM,YAAY,GAChB,KAAK,EAAE,KAAK,EAAE,UAAU;YACxB,KAAK,EAAE,KAAK,EAAE,OAAO;YACrB,KAAK,CAAC,OAAO;YACb,wBAAwB,CAAC;QAC3B,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAC5B,OAAO,IAAA,uBAAe,EAAS,GAAG,EAAE,YAAY,CAAC,CAAC;IACpD,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forge-sql-orm",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.13",
|
|
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
|
-
"main": "dist/
|
|
6
|
-
"module": "dist/ForgeSQLORM.mjs",
|
|
7
|
-
"types": "dist/index.d.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
"types": "./dist/index.d.ts",
|
|
10
|
-
"require": "./dist/ForgeSQLORM.js",
|
|
11
|
-
"import": "./dist/ForgeSQLORM.mjs",
|
|
12
|
-
"default": "./dist/ForgeSQLORM.mjs"
|
|
13
|
-
},
|
|
5
|
+
"main": "dist/index.js",
|
|
14
6
|
"homepage": "https://github.com/vzakharchenko/forge-sql-orm#readme",
|
|
15
7
|
"bugs": {
|
|
16
8
|
"url": "https://github.com/vzakharchenko/forge-sql-orm/issues"
|
|
@@ -32,24 +24,25 @@
|
|
|
32
24
|
"database"
|
|
33
25
|
],
|
|
34
26
|
"devDependencies": {
|
|
35
|
-
"@eslint/js": "^9.
|
|
27
|
+
"@eslint/js": "^9.39.1",
|
|
36
28
|
"@types/luxon": "^3.7.1",
|
|
37
|
-
"@types/node": "^24.
|
|
38
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
39
|
-
"@typescript-eslint/parser": "^8.
|
|
40
|
-
"@vitest/coverage-v8": "^4.0.
|
|
41
|
-
"@vitest/ui": "^4.0.
|
|
42
|
-
"eslint": "^9.
|
|
29
|
+
"@types/node": "^24.10.1",
|
|
30
|
+
"@typescript-eslint/eslint-plugin": "^8.47.0",
|
|
31
|
+
"@typescript-eslint/parser": "^8.47.0",
|
|
32
|
+
"@vitest/coverage-v8": "^4.0.12",
|
|
33
|
+
"@vitest/ui": "^4.0.12",
|
|
34
|
+
"eslint": "^9.39.1",
|
|
43
35
|
"eslint-config-prettier": "^10.1.8",
|
|
44
36
|
"eslint-plugin-import": "^2.32.0",
|
|
45
37
|
"eslint-plugin-vitest": "^0.5.4",
|
|
46
|
-
"
|
|
38
|
+
"husky": "^9.1.7",
|
|
39
|
+
"knip": "^5.70.1",
|
|
40
|
+
"patch-package": "^8.0.1",
|
|
47
41
|
"prettier": "^3.6.2",
|
|
48
42
|
"ts-node": "^10.9.2",
|
|
49
43
|
"typescript": "^5.9.3",
|
|
50
44
|
"uuid": "^13.0.0",
|
|
51
|
-
"
|
|
52
|
-
"vitest": "^4.0.6"
|
|
45
|
+
"vitest": "^4.0.12"
|
|
53
46
|
},
|
|
54
47
|
"license": "MIT",
|
|
55
48
|
"author": "Vasyl Zakharchenko",
|
|
@@ -62,11 +55,12 @@
|
|
|
62
55
|
"format": "prettier --write src examples __tests__",
|
|
63
56
|
"format:check": "prettier --write src examples __tests__ --check",
|
|
64
57
|
"clean": "rm -rf dist",
|
|
65
|
-
"build": "npm run clean &&
|
|
66
|
-
"build:types": "tsc
|
|
58
|
+
"build": "npm run clean && npm run build:types",
|
|
59
|
+
"build:types": "tsc",
|
|
67
60
|
"prepublish:npm": "npm run build",
|
|
68
61
|
"publish:npm": "npm publish --access public",
|
|
69
62
|
"generate:models": "ts-node scripts/generate-models.ts",
|
|
63
|
+
"prepare": "husky",
|
|
70
64
|
"knip": "knip"
|
|
71
65
|
},
|
|
72
66
|
"files": [
|
|
@@ -76,7 +70,7 @@
|
|
|
76
70
|
"README.md"
|
|
77
71
|
],
|
|
78
72
|
"peerDependencies": {
|
|
79
|
-
"@forge/sql": "^3.0.
|
|
73
|
+
"@forge/sql": "^3.0.10",
|
|
80
74
|
"drizzle-orm": "^0.44.7"
|
|
81
75
|
},
|
|
82
76
|
"optionalDependencies": {
|
|
@@ -84,5 +78,16 @@
|
|
|
84
78
|
},
|
|
85
79
|
"dependencies": {
|
|
86
80
|
"luxon": "^3.7.2"
|
|
81
|
+
},
|
|
82
|
+
"lint-staged": {
|
|
83
|
+
"*.{ts,tsx,css,scss,md}": [
|
|
84
|
+
"prettier --write",
|
|
85
|
+
"eslint --fix"
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
"husky": {
|
|
89
|
+
"hooks": {
|
|
90
|
+
"pre-commit": "cd .husky && ./pre-commit"
|
|
91
|
+
}
|
|
87
92
|
}
|
|
88
93
|
}
|
|
@@ -294,9 +294,10 @@ export class ForgeSQLAnalyseOperation implements SchemaAnalyzeForgeSql {
|
|
|
294
294
|
.map((s) => s.trim())
|
|
295
295
|
.filter(Boolean);
|
|
296
296
|
const row: Record<string, string> = {};
|
|
297
|
-
|
|
297
|
+
for (const key of headers) {
|
|
298
|
+
const i = headers.indexOf(key);
|
|
298
299
|
row[key] = values[i] ?? "";
|
|
299
|
-
}
|
|
300
|
+
}
|
|
300
301
|
return row as unknown as ExplainAnalyzeRow;
|
|
301
302
|
});
|
|
302
303
|
}
|