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
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
- ✅ **Custom Drizzle Driver** for direct integration with @forge/sql
|
|
19
19
|
- ✅ **Local Cache System (Level 1)** for in-memory query optimization within single resolver invocation scope
|
|
20
20
|
- ✅ **Global Cache System (Level 2)** with cross-invocation caching, automatic cache invalidation and context-aware operations (using [@forge/kvs](https://developer.atlassian.com/platform/forge/storage-reference/storage-api-custom-entities/) )
|
|
21
|
-
- ✅ **Performance Monitoring**: Query execution metrics and analysis capabilities with automatic error analysis for timeout and OOM errors
|
|
21
|
+
- ✅ **Performance Monitoring**: Query execution metrics and analysis capabilities with automatic error analysis for timeout and OOM errors, plus scheduled slow query monitoring with execution plans
|
|
22
22
|
- ✅ **Type-Safe Query Building**: Write SQL queries with full TypeScript support
|
|
23
23
|
- ✅ **Supports complex SQL queries** with joins and filtering using Drizzle ORM
|
|
24
24
|
- ✅ **Advanced Query Methods**: `selectFrom()`, `selectDistinctFrom()`, `selectCacheableFrom()`, `selectDistinctCacheableFrom()` for all-column queries with field aliasing
|
|
@@ -64,7 +64,8 @@
|
|
|
64
64
|
### 🔒 Advanced Features
|
|
65
65
|
- [Optimistic Locking](#optimistic-locking)
|
|
66
66
|
- [Query Analysis and Performance Optimization](#query-analysis-and-performance-optimization)
|
|
67
|
-
- [
|
|
67
|
+
- [Automatic Error Analysis](#automatic-error-analysis) - Automatic timeout and OOM error detection with execution plans
|
|
68
|
+
- [Slow Query Monitoring](#slow-query-monitoring) - Scheduled monitoring of slow queries with execution plans
|
|
68
69
|
- [Date and Time Types](#date-and-time-types)
|
|
69
70
|
|
|
70
71
|
### 🛠️ Development Tools
|
|
@@ -294,10 +295,8 @@ resolver.define("fetch", async (req: Request) => {
|
|
|
294
295
|
console.warn(`[Performance Warning fetch] Resolver exceeded DB time: ${totalDbExecutionTime} ms`);
|
|
295
296
|
await printQueriesWithPlan(); // Optionally log or capture diagnostics for further analysis
|
|
296
297
|
} else if (totalDbExecutionTime > threshold) {
|
|
297
|
-
console.debug(`[Performance Debug] High DB time: ${totalDbExecutionTime} ms`);
|
|
298
|
+
console.debug(`[Performance Debug fetch] High DB time: ${totalDbExecutionTime} ms`);
|
|
298
299
|
}
|
|
299
|
-
|
|
300
|
-
console.log(`DB response size: ${totalResponseSize} bytes`);
|
|
301
300
|
}
|
|
302
301
|
);
|
|
303
302
|
} catch (e) {
|
|
@@ -360,8 +359,9 @@ const rawUsers = await forgeSQL.execute(
|
|
|
360
359
|
);
|
|
361
360
|
|
|
362
361
|
// Raw SQL with caching
|
|
362
|
+
// ⚠️ IMPORTANT: When using executeCacheable(), all table names must be wrapped with backticks (`)
|
|
363
363
|
const cachedRawUsers = await forgeSQL.executeCacheable(
|
|
364
|
-
"SELECT * FROM users WHERE active = ?",
|
|
364
|
+
"SELECT * FROM `users` WHERE active = ?",
|
|
365
365
|
[true],
|
|
366
366
|
300
|
|
367
367
|
);
|
|
@@ -481,8 +481,9 @@ const rawUsers = await forgeSQL.execute(
|
|
|
481
481
|
);
|
|
482
482
|
|
|
483
483
|
// Raw SQL with caching
|
|
484
|
+
// ⚠️ IMPORTANT: When using executeCacheable(), all table names must be wrapped with backticks (`)
|
|
484
485
|
const cachedRawUsers = await forgeSQL.executeCacheable(
|
|
485
|
-
"SELECT * FROM users WHERE active = ?",
|
|
486
|
+
"SELECT * FROM `users` WHERE active = ?",
|
|
486
487
|
[true],
|
|
487
488
|
300
|
|
488
489
|
);
|
|
@@ -617,6 +618,9 @@ Please review the [official @forge/kvs quotas and limits](https://developer.atla
|
|
|
617
618
|
- Monitor cache usage to stay within quotas
|
|
618
619
|
- Use appropriate TTL values
|
|
619
620
|
|
|
621
|
+
**⚠️ Important Cache Limitations:**
|
|
622
|
+
- **Table names starting with `a_`**: Tables whose names start with `a_` (case-insensitive) are automatically ignored in cache operations. KVS Cache will not work with such tables, and they will be excluded from cache invalidation and cache key generation. This is by design to support special system tables or temporary tables.
|
|
623
|
+
|
|
620
624
|
### Step 1: Install Dependencies
|
|
621
625
|
|
|
622
626
|
```bash
|
|
@@ -1136,8 +1140,10 @@ const user = await forgeSQL
|
|
|
1136
1140
|
.execute("SELECT * FROM users WHERE id = ?", [1]);
|
|
1137
1141
|
|
|
1138
1142
|
// Using forgeSQL.executeCacheable() - Execute raw SQL with local and global caching
|
|
1143
|
+
// ⚠️ IMPORTANT: When using executeCacheable(), all table names in SQL queries must be wrapped with backticks (`)
|
|
1144
|
+
// Example: SELECT * FROM `users` WHERE id = ? (NOT: SELECT * FROM users WHERE id = ?)
|
|
1139
1145
|
const user = await forgeSQL
|
|
1140
|
-
.executeCacheable("SELECT * FROM users WHERE id = ?", [1], 300);
|
|
1146
|
+
.executeCacheable("SELECT * FROM `users` WHERE id = ?", [1], 300);
|
|
1141
1147
|
|
|
1142
1148
|
// Using forgeSQL.getDrizzleQueryBuilder()
|
|
1143
1149
|
const user = await forgeSQL
|
|
@@ -1266,8 +1272,10 @@ const users = await forgeSQL
|
|
|
1266
1272
|
.execute("SELECT * FROM users WHERE active = ?", [true]);
|
|
1267
1273
|
|
|
1268
1274
|
// Using executeCacheable() for raw SQL with local and global caching
|
|
1275
|
+
// ⚠️ IMPORTANT: When using executeCacheable(), all table names in SQL queries must be wrapped with backticks (`)
|
|
1276
|
+
// Example: SELECT * FROM `users` WHERE active = ? (NOT: SELECT * FROM users WHERE active = ?)
|
|
1269
1277
|
const users = await forgeSQL
|
|
1270
|
-
.executeCacheable("SELECT * FROM users WHERE active = ?", [true], 300);
|
|
1278
|
+
.executeCacheable("SELECT * FROM `users` WHERE active = ?", [true], 300);
|
|
1271
1279
|
|
|
1272
1280
|
// Using executeWithMetadata() for capturing execution metrics and performance monitoring
|
|
1273
1281
|
const usersWithMetadata = await forgeSQL.executeWithMetadata(
|
|
@@ -1760,8 +1768,9 @@ await forgeSQL.executeWithLocalContext(async () => {
|
|
|
1760
1768
|
.where(eq(users.active, true));
|
|
1761
1769
|
|
|
1762
1770
|
// Raw SQL with multi-level caching
|
|
1771
|
+
// ⚠️ IMPORTANT: When using executeCacheable(), all table names must be wrapped with backticks (`)
|
|
1763
1772
|
const rawUsers = await forgeSQL.executeCacheable(
|
|
1764
|
-
"SELECT id, name FROM users WHERE active = ?",
|
|
1773
|
+
"SELECT id, name FROM `users` WHERE active = ?",
|
|
1765
1774
|
[true],
|
|
1766
1775
|
300 // TTL in seconds
|
|
1767
1776
|
);
|
|
@@ -1810,8 +1819,9 @@ const usersDistinct = await forgeSQL.selectDistinctCacheableFrom(Users)
|
|
|
1810
1819
|
.where(eq(Users.active, true));
|
|
1811
1820
|
|
|
1812
1821
|
// Raw SQL with local and global caching
|
|
1822
|
+
// ⚠️ IMPORTANT: When using executeCacheable(), all table names must be wrapped with backticks (`)
|
|
1813
1823
|
const rawUsers = await forgeSQL.executeCacheable(
|
|
1814
|
-
"SELECT * FROM users WHERE active = ?",
|
|
1824
|
+
"SELECT * FROM `users` WHERE active = ?",
|
|
1815
1825
|
[true],
|
|
1816
1826
|
300 // TTL in seconds
|
|
1817
1827
|
);
|
|
@@ -2122,6 +2132,34 @@ Configure in `manifest.yml`:
|
|
|
2122
2132
|
- `hour` - Every hour
|
|
2123
2133
|
- `day` - Every day
|
|
2124
2134
|
|
|
2135
|
+
### 5. Slow Query Scheduler Trigger
|
|
2136
|
+
|
|
2137
|
+
This scheduler trigger automatically monitors and analyzes slow queries on a scheduled basis. For detailed information, see the [Slow Query Monitoring](#slow-query-monitoring) section.
|
|
2138
|
+
|
|
2139
|
+
**Quick Setup:**
|
|
2140
|
+
|
|
2141
|
+
```typescript
|
|
2142
|
+
import ForgeSQL, { slowQuerySchedulerTrigger } from "forge-sql-orm";
|
|
2143
|
+
|
|
2144
|
+
const forgeSQL = new ForgeSQL();
|
|
2145
|
+
|
|
2146
|
+
export const slowQueryTrigger = () =>
|
|
2147
|
+
slowQuerySchedulerTrigger(forgeSQL, { hours: 1, timeout: 3000 });
|
|
2148
|
+
```
|
|
2149
|
+
|
|
2150
|
+
Configure in `manifest.yml`:
|
|
2151
|
+
```yaml
|
|
2152
|
+
scheduledTrigger:
|
|
2153
|
+
- key: slow-query-trigger
|
|
2154
|
+
function: slowQueryTrigger
|
|
2155
|
+
interval: hour
|
|
2156
|
+
function:
|
|
2157
|
+
- key: slowQueryTrigger
|
|
2158
|
+
handler: index.slowQueryTrigger
|
|
2159
|
+
```
|
|
2160
|
+
|
|
2161
|
+
> **💡 Note**: For complete documentation, examples, and configuration options, see the [Slow Query Monitoring](#slow-query-monitoring) section.
|
|
2162
|
+
|
|
2125
2163
|
### Important Notes
|
|
2126
2164
|
|
|
2127
2165
|
**Security Considerations**:
|
|
@@ -2210,6 +2248,112 @@ The error analysis mechanism:
|
|
|
2210
2248
|
|
|
2211
2249
|
> **💡 Tip**: The automatic error analysis only triggers for timeout and OOM errors. Other errors are logged normally without plan analysis.
|
|
2212
2250
|
|
|
2251
|
+
### Slow Query Monitoring
|
|
2252
|
+
|
|
2253
|
+
Forge-SQL-ORM provides a scheduler trigger (`slowQuerySchedulerTrigger`) that automatically monitors and analyzes slow queries on an hourly basis. This trigger queries TiDB's slow query log system table and provides detailed performance information including SQL query text, memory usage, execution time, and execution plans.
|
|
2254
|
+
|
|
2255
|
+
#### Key Features
|
|
2256
|
+
|
|
2257
|
+
- **Automatic Monitoring**: Runs on a scheduled interval (recommended: hourly)
|
|
2258
|
+
- **Detailed Performance Metrics**: Memory usage, execution time, and execution plans
|
|
2259
|
+
- **Console Logging**: Results are automatically logged to the Forge Developer Console
|
|
2260
|
+
- **Configurable Time Window**: Analyze queries from the last N hours (default: 1 hour)
|
|
2261
|
+
- **Automatic Plan Retrieval**: Execution plans are included for all slow queries
|
|
2262
|
+
|
|
2263
|
+
#### Basic Setup
|
|
2264
|
+
|
|
2265
|
+
**1. Create the trigger function:**
|
|
2266
|
+
|
|
2267
|
+
```typescript
|
|
2268
|
+
import ForgeSQL, { slowQuerySchedulerTrigger } from "forge-sql-orm";
|
|
2269
|
+
|
|
2270
|
+
const forgeSQL = new ForgeSQL();
|
|
2271
|
+
|
|
2272
|
+
// Monitor slow queries from the last hour (recommended for hourly schedule)
|
|
2273
|
+
export const slowQueryTrigger = () =>
|
|
2274
|
+
slowQuerySchedulerTrigger(forgeSQL, { hours: 1, timeout: 3000 });
|
|
2275
|
+
```
|
|
2276
|
+
|
|
2277
|
+
**2. Configure in `manifest.yml`:**
|
|
2278
|
+
|
|
2279
|
+
```yaml
|
|
2280
|
+
modules:
|
|
2281
|
+
scheduledTrigger:
|
|
2282
|
+
- key: slow-query-trigger
|
|
2283
|
+
function: slowQueryTrigger
|
|
2284
|
+
interval: hour # Run every hour
|
|
2285
|
+
|
|
2286
|
+
function:
|
|
2287
|
+
- key: slowQueryTrigger
|
|
2288
|
+
handler: index.slowQueryTrigger
|
|
2289
|
+
```
|
|
2290
|
+
|
|
2291
|
+
#### Configuration Options
|
|
2292
|
+
|
|
2293
|
+
| Option | Type | Default | Description |
|
|
2294
|
+
|--------|------|---------|-------------|
|
|
2295
|
+
| `hours` | `number` | `1` | Number of hours to look back for slow queries |
|
|
2296
|
+
| `timeout` | `number` | `3000` | Timeout in milliseconds for the diagnostic query execution |
|
|
2297
|
+
|
|
2298
|
+
#### Example Console Output
|
|
2299
|
+
|
|
2300
|
+
When slow queries are detected, you'll see output like this in the Forge Developer Console:
|
|
2301
|
+
|
|
2302
|
+
```
|
|
2303
|
+
Found SlowQuery SQL: SELECT * FROM users u INNER JOIN orders o ON u.id = o.user_id WHERE u.active = ? | Memory: 8.50 MB | Time: 2500.00 ms
|
|
2304
|
+
Plan:
|
|
2305
|
+
id task estRows operator info actRows execution info memory disk
|
|
2306
|
+
Projection_7 root 1000.00 forge_38dd1c6156b94bb59c2c9a45582bbfc7.users.id, ... 1000 time:2.5s, loops:1 8.50 MB N/A
|
|
2307
|
+
└─IndexHashJoin_14 root 1000.00 inner join, ... 1000 time:2.2s, loops:1 7.98 MB N/A
|
|
2308
|
+
|
|
2309
|
+
Found SlowQuery SQL: SELECT * FROM products WHERE category = ? ORDER BY created_at DESC | Memory: 6.25 MB | Time: 1800.00 ms
|
|
2310
|
+
Plan:
|
|
2311
|
+
...
|
|
2312
|
+
```
|
|
2313
|
+
|
|
2314
|
+
#### Advanced Configuration
|
|
2315
|
+
|
|
2316
|
+
```typescript
|
|
2317
|
+
import ForgeSQL, { slowQuerySchedulerTrigger } from "forge-sql-orm";
|
|
2318
|
+
|
|
2319
|
+
const forgeSQL = new ForgeSQL();
|
|
2320
|
+
|
|
2321
|
+
// Monitor queries from the last 6 hours (for less frequent checks)
|
|
2322
|
+
export const sixHourSlowQueryTrigger = () =>
|
|
2323
|
+
slowQuerySchedulerTrigger(forgeSQL, { hours: 6, timeout: 5000 });
|
|
2324
|
+
|
|
2325
|
+
// Monitor queries from the last 24 hours (daily monitoring)
|
|
2326
|
+
export const dailySlowQueryTrigger = () =>
|
|
2327
|
+
slowQuerySchedulerTrigger(forgeSQL, { hours: 24, timeout: 3000 });
|
|
2328
|
+
```
|
|
2329
|
+
|
|
2330
|
+
#### How It Works
|
|
2331
|
+
|
|
2332
|
+
1. **Scheduled Execution**: The trigger runs automatically on the configured interval (hourly recommended)
|
|
2333
|
+
2. **Query Analysis**: Queries TiDB's slow query log system table for queries executed within the specified time window
|
|
2334
|
+
3. **Performance Metrics**: Extracts and logs:
|
|
2335
|
+
- SQL query text (sanitized for readability)
|
|
2336
|
+
- Maximum memory usage (in MB)
|
|
2337
|
+
- Query execution time (in ms)
|
|
2338
|
+
- Detailed execution plan
|
|
2339
|
+
4. **Console Logging**: Results are logged to the Forge Developer Console via `console.warn()` for easy monitoring
|
|
2340
|
+
|
|
2341
|
+
#### Best Practices
|
|
2342
|
+
|
|
2343
|
+
- **Hourly Intervals**: Use `interval: hour` for timely detection of slow queries
|
|
2344
|
+
- **Default Time Window**: 1 hour is recommended for hourly schedules to avoid overlap
|
|
2345
|
+
- **Monitor Regularly**: Check console logs regularly to identify patterns in slow queries
|
|
2346
|
+
|
|
2347
|
+
#### Benefits
|
|
2348
|
+
|
|
2349
|
+
- **Proactive Monitoring**: Catch slow queries before they become critical issues
|
|
2350
|
+
- **Performance Trends**: Track query performance over time
|
|
2351
|
+
- **Optimization Insights**: Execution plans help identify optimization opportunities
|
|
2352
|
+
- **Zero Manual Intervention**: Fully automated monitoring with scheduled execution
|
|
2353
|
+
- **Production Safe**: Works silently in the background, only logs when slow queries are found
|
|
2354
|
+
|
|
2355
|
+
> **💡 Tip**: The trigger queries up to 50 slow queries to prevent excessive logging. Transient timeouts are usually fine; repeated timeouts indicate the diagnostic query itself is slow and should be investigated.
|
|
2356
|
+
|
|
2213
2357
|
### Available Analysis Tools
|
|
2214
2358
|
|
|
2215
2359
|
```typescript
|
|
@@ -2370,8 +2514,9 @@ const rawUsers = await forgeSQL.execute(
|
|
|
2370
2514
|
[true]
|
|
2371
2515
|
);
|
|
2372
2516
|
|
|
2517
|
+
// ⚠️ IMPORTANT: When using executeCacheable(), all table names must be wrapped with backticks (`)
|
|
2373
2518
|
const cachedRawUsers = await forgeSQL.executeCacheable(
|
|
2374
|
-
"SELECT * FROM users WHERE active = ?",
|
|
2519
|
+
"SELECT * FROM `users` WHERE active = ?",
|
|
2375
2520
|
[true],
|
|
2376
2521
|
300
|
|
2377
2522
|
);
|
package/dist/ForgeSQLORM.js
CHANGED
|
@@ -823,7 +823,14 @@ async function printQueriesWithPlan(forgeSQLORM, timeDiffMs, timeout) {
|
|
|
823
823
|
drizzleOrm.and(
|
|
824
824
|
drizzleOrm.isNotNull(statementsTable.digest),
|
|
825
825
|
drizzleOrm.not(drizzleOrm.ilike(statementsTable.digestText, "%information_schema%")),
|
|
826
|
-
drizzleOrm.notInArray(statementsTable.stmtType, [
|
|
826
|
+
drizzleOrm.notInArray(statementsTable.stmtType, [
|
|
827
|
+
"Use",
|
|
828
|
+
"Set",
|
|
829
|
+
"Show",
|
|
830
|
+
"Commit",
|
|
831
|
+
"Rollback",
|
|
832
|
+
"Begin"
|
|
833
|
+
]),
|
|
827
834
|
drizzleOrm.gte(
|
|
828
835
|
statementsTable.lastSeen,
|
|
829
836
|
drizzleOrm.sql`DATE_SUB
|
|
@@ -885,9 +892,7 @@ async function slowQueryPerHours(forgeSQLORM, hours, timeout) {
|
|
|
885
892
|
const message = `Found SlowQuery SQL: ${result.query} | Memory: ${memMaxMB.toFixed(2)} MB | Time: ${result.queryTime} ms
|
|
886
893
|
Plan:${result.plan}`;
|
|
887
894
|
response.push(message);
|
|
888
|
-
console.warn(
|
|
889
|
-
message
|
|
890
|
-
);
|
|
895
|
+
console.warn(message);
|
|
891
896
|
});
|
|
892
897
|
return response;
|
|
893
898
|
} catch (error) {
|
|
@@ -895,16 +900,16 @@ async function slowQueryPerHours(forgeSQLORM, hours, timeout) {
|
|
|
895
900
|
`Error occurred while retrieving query execution plan: ${error instanceof Error ? error.message : "Unknown error"}. Try again after some time`,
|
|
896
901
|
error
|
|
897
902
|
);
|
|
898
|
-
return [
|
|
903
|
+
return [
|
|
904
|
+
`Error occurred while retrieving query execution plan: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
905
|
+
];
|
|
899
906
|
}
|
|
900
907
|
}
|
|
901
908
|
async function withTimeout(promise, message, timeoutMs2) {
|
|
902
909
|
let timeoutId;
|
|
903
910
|
const timeoutPromise = new Promise((_, reject) => {
|
|
904
911
|
timeoutId = setTimeout(() => {
|
|
905
|
-
reject(
|
|
906
|
-
new Error(message)
|
|
907
|
-
);
|
|
912
|
+
reject(new Error(message));
|
|
908
913
|
}, timeoutMs2);
|
|
909
914
|
});
|
|
910
915
|
try {
|
|
@@ -936,6 +941,17 @@ function nowPlusSeconds(secondsToAdd) {
|
|
|
936
941
|
const dt = luxon.DateTime.now().plus({ seconds: secondsToAdd });
|
|
937
942
|
return Math.floor(dt.toSeconds());
|
|
938
943
|
}
|
|
944
|
+
function extractBacktickedValues(sql2) {
|
|
945
|
+
const regex = /`([^`]+)`/g;
|
|
946
|
+
const matches = /* @__PURE__ */ new Set();
|
|
947
|
+
let match;
|
|
948
|
+
while ((match = regex.exec(sql2.toLowerCase())) !== null) {
|
|
949
|
+
if (!match[1].startsWith("a_")) {
|
|
950
|
+
matches.add(`\`${match[1]}\``);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
return Array.from(matches).sort().join(",");
|
|
954
|
+
}
|
|
939
955
|
function hashKey(query) {
|
|
940
956
|
const h = crypto__namespace.createHash("sha256");
|
|
941
957
|
h.update(query.sql.toLowerCase());
|
|
@@ -1079,7 +1095,7 @@ async function getFromCache(query, options) {
|
|
|
1079
1095
|
}
|
|
1080
1096
|
try {
|
|
1081
1097
|
const cacheResult = await kvs.kvs.entity(options.cacheEntityName).get(key);
|
|
1082
|
-
if (cacheResult && cacheResult[expirationName] >= getCurrentTime() && sqlQuery.sql
|
|
1098
|
+
if (cacheResult && cacheResult[expirationName] >= getCurrentTime() && extractBacktickedValues(sqlQuery.sql) === cacheResult[entityQueryName]) {
|
|
1083
1099
|
if (options.logCache) {
|
|
1084
1100
|
console.warn(`Get value from cache, cacheKey: ${key}`);
|
|
1085
1101
|
}
|
|
@@ -1110,7 +1126,7 @@ async function setCacheResult(query, options, results, cacheTtl) {
|
|
|
1110
1126
|
await kvs.kvs.transact().set(
|
|
1111
1127
|
key,
|
|
1112
1128
|
{
|
|
1113
|
-
[entityQueryName]: sqlQuery.sql
|
|
1129
|
+
[entityQueryName]: extractBacktickedValues(sqlQuery.sql),
|
|
1114
1130
|
[expirationName]: nowPlusSeconds(cacheTtl),
|
|
1115
1131
|
[dataName]: JSON.stringify(results)
|
|
1116
1132
|
},
|
|
@@ -1613,10 +1629,7 @@ async function saveMetaDataToContext(metadata) {
|
|
|
1613
1629
|
if (process.env.NODE_ENV !== "test") {
|
|
1614
1630
|
await new Promise((r) => setTimeout(r, 200));
|
|
1615
1631
|
}
|
|
1616
|
-
await printQueriesWithPlan(
|
|
1617
|
-
context.forgeSQLORM,
|
|
1618
|
-
Date.now() - context.beginTime.getTime()
|
|
1619
|
-
);
|
|
1632
|
+
await printQueriesWithPlan(context.forgeSQLORM, Date.now() - context.beginTime.getTime());
|
|
1620
1633
|
};
|
|
1621
1634
|
if (metadata) {
|
|
1622
1635
|
context.totalResponseSize += metadata.responseSize;
|
|
@@ -1683,7 +1696,11 @@ async function processAllMethod(query, params) {
|
|
|
1683
1696
|
if (params) {
|
|
1684
1697
|
await sqlStatement.bindParams(...params);
|
|
1685
1698
|
}
|
|
1686
|
-
const result = await withTimeout(
|
|
1699
|
+
const result = await withTimeout(
|
|
1700
|
+
sqlStatement.execute(),
|
|
1701
|
+
timeoutMessage,
|
|
1702
|
+
timeoutMs
|
|
1703
|
+
);
|
|
1687
1704
|
await saveMetaDataToContext(result.metadata);
|
|
1688
1705
|
if (!result.rows) {
|
|
1689
1706
|
return { rows: [] };
|
|
@@ -1694,7 +1711,11 @@ async function processAllMethod(query, params) {
|
|
|
1694
1711
|
const forgeDriver = async (query, params, method) => {
|
|
1695
1712
|
const operationType = await getOperationType();
|
|
1696
1713
|
if (operationType === "DDL") {
|
|
1697
|
-
const result = await withTimeout(
|
|
1714
|
+
const result = await withTimeout(
|
|
1715
|
+
sql.sql.executeDDL(inlineParams(query, params)),
|
|
1716
|
+
timeoutMessage,
|
|
1717
|
+
timeoutMs
|
|
1718
|
+
);
|
|
1698
1719
|
return await processDDLResult(method, result);
|
|
1699
1720
|
}
|
|
1700
1721
|
if (method === "execute") {
|
|
@@ -3833,7 +3854,12 @@ const clearCacheSchedulerTrigger = async (options) => {
|
|
|
3833
3854
|
};
|
|
3834
3855
|
async function slowQuerySchedulerTrigger(forgeSQLORM, options) {
|
|
3835
3856
|
try {
|
|
3836
|
-
return getHttpResponse(
|
|
3857
|
+
return getHttpResponse(
|
|
3858
|
+
200,
|
|
3859
|
+
JSON.stringify(
|
|
3860
|
+
await slowQueryPerHours(forgeSQLORM, options?.hours ?? 1, options?.timeout ?? 3e3)
|
|
3861
|
+
)
|
|
3862
|
+
);
|
|
3837
3863
|
} catch (error) {
|
|
3838
3864
|
const errorMessage = error?.debug?.sqlMessage ?? error?.debug?.message ?? error.message ?? "Unknown error occurred";
|
|
3839
3865
|
console.error(errorMessage);
|