forge-sql-orm 2.1.3 → 2.1.5

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.
Files changed (52) hide show
  1. package/README.md +291 -0
  2. package/dist/ForgeSQLORM.js +713 -12
  3. package/dist/ForgeSQLORM.js.map +1 -1
  4. package/dist/ForgeSQLORM.mjs +716 -15
  5. package/dist/ForgeSQLORM.mjs.map +1 -1
  6. package/dist/core/ForgeSQLCrudOperations.d.ts.map +1 -1
  7. package/dist/core/ForgeSQLORM.d.ts +23 -0
  8. package/dist/core/ForgeSQLORM.d.ts.map +1 -1
  9. package/dist/core/ForgeSQLQueryBuilder.d.ts +36 -5
  10. package/dist/core/ForgeSQLQueryBuilder.d.ts.map +1 -1
  11. package/dist/core/ForgeSQLSelectOperations.d.ts.map +1 -1
  12. package/dist/core/SystemTables.d.ts +5039 -0
  13. package/dist/core/SystemTables.d.ts.map +1 -1
  14. package/dist/lib/drizzle/extensions/additionalActions.d.ts.map +1 -1
  15. package/dist/utils/cacheContextUtils.d.ts.map +1 -1
  16. package/dist/utils/cacheUtils.d.ts.map +1 -1
  17. package/dist/utils/forgeDriver.d.ts +21 -0
  18. package/dist/utils/forgeDriver.d.ts.map +1 -1
  19. package/dist/utils/forgeDriverProxy.d.ts.map +1 -1
  20. package/dist/utils/metadataContextUtils.d.ts +11 -0
  21. package/dist/utils/metadataContextUtils.d.ts.map +1 -0
  22. package/dist/utils/sqlUtils.d.ts.map +1 -1
  23. package/dist/webtriggers/applyMigrationsWebTrigger.d.ts +1 -1
  24. package/dist/webtriggers/applyMigrationsWebTrigger.d.ts.map +1 -1
  25. package/dist/webtriggers/clearCacheSchedulerTrigger.d.ts.map +1 -1
  26. package/dist/webtriggers/dropMigrationWebTrigger.d.ts.map +1 -1
  27. package/dist/webtriggers/dropTablesMigrationWebTrigger.d.ts.map +1 -1
  28. package/dist/webtriggers/fetchSchemaWebTrigger.d.ts.map +1 -1
  29. package/dist/webtriggers/index.d.ts +1 -0
  30. package/dist/webtriggers/index.d.ts.map +1 -1
  31. package/dist/webtriggers/topSlowestStatementLastHourTrigger.d.ts +89 -0
  32. package/dist/webtriggers/topSlowestStatementLastHourTrigger.d.ts.map +1 -0
  33. package/package.json +4 -3
  34. package/src/core/ForgeSQLCrudOperations.ts +3 -0
  35. package/src/core/ForgeSQLORM.ts +119 -51
  36. package/src/core/ForgeSQLQueryBuilder.ts +51 -17
  37. package/src/core/ForgeSQLSelectOperations.ts +2 -0
  38. package/src/core/SystemTables.ts +313 -1
  39. package/src/lib/drizzle/extensions/additionalActions.ts +2 -0
  40. package/src/utils/cacheContextUtils.ts +4 -2
  41. package/src/utils/cacheUtils.ts +20 -8
  42. package/src/utils/forgeDriver.ts +22 -1
  43. package/src/utils/forgeDriverProxy.ts +2 -0
  44. package/src/utils/metadataContextUtils.ts +24 -0
  45. package/src/utils/sqlUtils.ts +1 -0
  46. package/src/webtriggers/applyMigrationsWebTrigger.ts +10 -5
  47. package/src/webtriggers/clearCacheSchedulerTrigger.ts +1 -0
  48. package/src/webtriggers/dropMigrationWebTrigger.ts +2 -0
  49. package/src/webtriggers/dropTablesMigrationWebTrigger.ts +2 -0
  50. package/src/webtriggers/fetchSchemaWebTrigger.ts +1 -0
  51. package/src/webtriggers/index.ts +1 -0
  52. package/src/webtriggers/topSlowestStatementLastHourTrigger.ts +360 -0
package/README.md CHANGED
@@ -19,10 +19,12 @@
19
19
  - ✅ **Custom Drizzle Driver** for direct integration with @forge/sql
20
20
  - ✅ **Local Cache System (Level 1)** for in-memory query optimization within single resolver invocation scope
21
21
  - ✅ **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/) )
22
+ - ✅ **Memory Usage Monitoring**: Automated detection of memory-intensive queries with configurable thresholds (essential for Atlassian's 16 MiB per query limit)
22
23
  - ✅ **Type-Safe Query Building**: Write SQL queries with full TypeScript support
23
24
  - ✅ **Supports complex SQL queries** with joins and filtering using Drizzle ORM
24
25
  - ✅ **Advanced Query Methods**: `selectFrom()`, `selectDistinctFrom()`, `selectCacheableFrom()`, `selectDistinctCacheableFrom()` for all-column queries with field aliasing
25
26
  - ✅ **Raw SQL Execution**: `execute()` and `executeCacheable()` methods for direct SQL queries with local and global caching
27
+ - ✅ **Query Execution with Metadata**: `executeWithMetadata()` method for capturing detailed execution metrics including database execution time, response size, and Forge SQL metadata
26
28
  - ✅ **Common Table Expressions (CTEs)**: `with()` method for complex queries with subqueries
27
29
  - ✅ **Schema migration support**, allowing automatic schema evolution
28
30
  - ✅ **Automatic entity generation** from MySQL/tidb databases
@@ -63,6 +65,7 @@
63
65
  ### 🔒 Advanced Features
64
66
  - [Optimistic Locking](#optimistic-locking)
65
67
  - [Query Analysis and Performance Optimization](#query-analysis-and-performance-optimization)
68
+ - [Memory Usage Monitoring](#memory-usage-monitoring)
66
69
  - [Date and Time Types](#date-and-time-types)
67
70
 
68
71
  ### 🛠️ Development Tools
@@ -79,6 +82,7 @@
79
82
  - [Query Analysis Example](examples/forge-sql-orm-example-query-analyses)
80
83
  - [Organization Tracker Example](examples/forge-sql-orm-example-org-tracker)
81
84
  - [Checklist Example](examples/forge-sql-orm-example-checklist)
85
+ - [Cache Example](examples/forge-sql-orm-example-cache) - Advanced caching capabilities with `topSlowestStatementLastHourTrigger` memory monitoring
82
86
 
83
87
  ### 📚 Reference
84
88
  - [ForgeSqlOrmOptions](#forgesqlormoptions)
@@ -95,6 +99,7 @@
95
99
  - [Global Cache System (Level 2)](#global-cache-system-level-2) - Cross-invocation persistent caching
96
100
  - [Local Cache System (Level 1)](#local-cache-operations-level-1) - In-memory invocation caching
97
101
  - [Optimistic Locking](#optimistic-locking) - Data consistency
102
+ - [Memory Usage Monitoring](#memory-usage-monitoring) - Memory-intensive query detection
98
103
  - [Migration Tools](#web-triggers-for-migrations) - Database migrations
99
104
  - [Query Analysis](#query-analysis-and-performance-optimization) - Performance optimization
100
105
 
@@ -103,6 +108,7 @@
103
108
  - [Optimistic Locking Example](examples/forge-sql-orm-example-optimistic-locking) - Real-world conflict handling
104
109
  - [Organization Tracker Example](examples/forge-sql-orm-example-org-tracker) - Complex relationships
105
110
  - [Checklist Example](examples/forge-sql-orm-example-checklist) - Jira integration
111
+ - [Cache Example](examples/forge-sql-orm-example-cache) - Advanced caching with memory monitoring
106
112
 
107
113
  ## Usage Approaches
108
114
 
@@ -328,6 +334,16 @@ const cachedRawUsers = await forgeSQL.executeCacheable(
328
334
  300
329
335
  );
330
336
 
337
+ // Raw SQL with execution metadata
338
+ const usersWithMetadata = await forgeSQL.executeWithMetadata(
339
+ async () => await forgeSQL.execute("SELECT * FROM users WHERE active = ?", [true]),
340
+ (totalDbExecutionTime, totalResponseSize, forgeMetadata) => {
341
+ console.log(`DB execution time: ${totalDbExecutionTime}ms`);
342
+ console.log(`Response size: ${totalResponseSize} bytes`);
343
+ console.log('Forge metadata:', forgeMetadata);
344
+ }
345
+ );
346
+
331
347
  // Common Table Expressions (CTEs)
332
348
  const userStats = await forgeSQL
333
349
  .with(
@@ -401,6 +417,16 @@ const cachedRawUsers = await forgeSQL.executeCacheable(
401
417
  [true],
402
418
  300
403
419
  );
420
+
421
+ // Raw SQL with execution metadata
422
+ const usersWithMetadata = await forgeSQL.executeWithMetadata(
423
+ async () => await forgeSQL.execute("SELECT * FROM users WHERE active = ?", [true]),
424
+ (totalDbExecutionTime, totalResponseSize, forgeMetadata) => {
425
+ console.log(`DB execution time: ${totalDbExecutionTime}ms`);
426
+ console.log(`Response size: ${totalResponseSize} bytes`);
427
+ console.log('Forge metadata:', forgeMetadata);
428
+ }
429
+ );
404
430
  ```
405
431
 
406
432
  ## Setting Up Caching with @forge/kvs (Optional)
@@ -772,6 +798,7 @@ const optimizedData = await forgeSQL.executeWithLocalCacheContextAndReturnValue(
772
798
  | `selectDistinctCacheableFrom()` | Distinct all-column queries with field aliasing and caching | ❌ No | Local + Global Cache |
773
799
  | `execute()` | Raw SQL queries with local caching | ❌ No | Local Cache |
774
800
  | `executeCacheable()` | Raw SQL queries with local and global caching | ❌ No | Local + Global Cache |
801
+ | `executeWithMetadata()` | Raw SQL queries with execution metrics capture | ❌ No | Local Cache |
775
802
  | `with()` | Common Table Expressions (CTEs) | ❌ No | Local Cache |
776
803
  where Cache context - allows you to batch cache invalidation events and bypass cache reads for affected tables.
777
804
 
@@ -1158,6 +1185,17 @@ const users = await forgeSQL
1158
1185
  const users = await forgeSQL
1159
1186
  .executeCacheable("SELECT * FROM users WHERE active = ?", [true], 300);
1160
1187
 
1188
+ // Using executeWithMetadata() for capturing execution metrics
1189
+ const usersWithMetadata = await forgeSQL
1190
+ .executeWithMetadata(
1191
+ async () => await forgeSQL.execute("SELECT * FROM users WHERE active = ?", [true]),
1192
+ (totalDbExecutionTime, totalResponseSize, forgeMetadata) => {
1193
+ console.log(`DB execution time: ${totalDbExecutionTime}ms`);
1194
+ console.log(`Response size: ${totalResponseSize} bytes`);
1195
+ console.log('Forge metadata:', forgeMetadata);
1196
+ }
1197
+ );
1198
+
1161
1199
  // Using execute() with complex queries
1162
1200
  const userStats = await forgeSQL
1163
1201
  .execute(`
@@ -1473,6 +1511,16 @@ await forgeSQL.executeWithLocalContext(async () => {
1473
1511
  [true]
1474
1512
  );
1475
1513
 
1514
+ // Raw SQL with execution metadata and local caching
1515
+ const usersWithMetadata = await forgeSQL.executeWithMetadata(
1516
+ async () => await forgeSQL.execute("SELECT id, name FROM users WHERE active = ?", [true]),
1517
+ (totalDbExecutionTime, totalResponseSize, forgeMetadata) => {
1518
+ console.log(`DB execution time: ${totalDbExecutionTime}ms`);
1519
+ console.log(`Response size: ${totalResponseSize} bytes`);
1520
+ console.log('Forge metadata:', forgeMetadata);
1521
+ }
1522
+ );
1523
+
1476
1524
  // Insert operation - evicts local cache for users table
1477
1525
  await forgeSQL.insert(users).values({ name: 'New User', active: true });
1478
1526
 
@@ -1641,6 +1689,16 @@ const userStats = await forgeSQL
1641
1689
  })
1642
1690
  .from(sql`activeUsers au`)
1643
1691
  .leftJoin(sql`completedOrders co`, eq(sql`au.id`, sql`co.userId`));
1692
+
1693
+ // Using executeWithMetadata() for capturing execution metrics with caching
1694
+ const usersWithMetadata = await forgeSQL.executeWithMetadata(
1695
+ async () => await forgeSQL.executeCacheable("SELECT * FROM users WHERE active = ?", [true], 300),
1696
+ (totalDbExecutionTime, totalResponseSize, forgeMetadata) => {
1697
+ console.log(`DB execution time: ${totalDbExecutionTime}ms`);
1698
+ console.log(`Response size: ${totalResponseSize} bytes`);
1699
+ console.log('Forge metadata:', forgeMetadata);
1700
+ }
1701
+ );
1644
1702
  ```
1645
1703
 
1646
1704
  ### Manual Cache Management
@@ -1716,6 +1774,7 @@ The `ForgeSqlOrmOptions` object allows customization of ORM behavior:
1716
1774
  | Option | Type | Description |
1717
1775
  | -------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1718
1776
  | `logRawSqlQuery` | `boolean` | Enables logging of raw SQL queries in the Atlassian Forge Developer Console. Useful for debugging and monitoring. Defaults to `false`. |
1777
+ | `logCache` | `boolean` | Enables logging of cache operations (hits, misses, evictions) in the Atlassian Forge Developer Console. Useful for debugging caching issues. Defaults to `false`. |
1719
1778
  | `disableOptimisticLocking` | `boolean` | Disables optimistic locking. When set to `true`, no additional condition (e.g., a version check) is added during record updates, which can improve performance. However, this may lead to conflicts when multiple transactions attempt to update the same record concurrently. |
1720
1779
  | `additionalMetadata` | `object` | Allows adding custom metadata to all entities. This is useful for tracking common fields across all tables (e.g., `createdAt`, `updatedAt`, `createdBy`, etc.). The metadata will be automatically added to all generated entities. |
1721
1780
  | `cacheEntityName` | `string` | KVS Custom entity name for cache storage. Must match the `name` in your `manifest.yml` storage entities configuration. Required for caching functionality. Defaults to `"cache"`. |
@@ -2015,6 +2074,228 @@ This analysis provides insights into:
2015
2074
  - Resource usage at each step
2016
2075
  - Performance optimization opportunities
2017
2076
 
2077
+ ## Memory Usage Monitoring
2078
+
2079
+ [↑ Back to Top](#table-of-contents)
2080
+
2081
+ Forge-SQL-ORM provides automated memory usage monitoring capabilities to help you identify and track memory-intensive queries in your Forge SQL instance. This feature is **essential for Atlassian Forge applications** as it helps you stay within the **16 MiB per query memory limit** and provides detailed insights for optimization.
2082
+
2083
+ ### Why Memory Monitoring is Critical
2084
+
2085
+ Atlassian Forge SQL has a strict **16 MiB memory limit per query**. Unlike slow query detection (which is available in the Forge Developer Console), there's **no built-in way to monitor memory usage** of your queries. This monitoring system fills that gap by:
2086
+
2087
+ - **Detecting memory-intensive queries** before they hit the 16 MiB limit
2088
+ - **Providing detailed memory metrics** including average and maximum memory usage
2089
+ - **Showing execution plans** to help optimize memory consumption
2090
+ - **Configurable thresholds** to match your application's memory requirements
2091
+ - **Scheduled monitoring** via Forge scheduler triggers
2092
+
2093
+ ### Overview
2094
+
2095
+ The memory monitoring system:
2096
+ - **Automatically detects memory-intensive queries** based on configurable memory thresholds
2097
+ - **Provides detailed memory metrics** including execution time, memory usage, and execution plans
2098
+ - **Logs memory issues** to the Forge Developer Console for easy debugging
2099
+ - **Supports scheduled monitoring** via Forge scheduler triggers
2100
+ - **Filters out system queries** to focus on your application's performance
2101
+
2102
+ ### Key Features
2103
+
2104
+ - **Memory-Focused Monitoring**: Primary focus on memory usage with configurable thresholds
2105
+ - **Atlassian 16 MiB Limit Awareness**: Designed specifically for Forge SQL's memory constraints
2106
+ - **Execution Plan Analysis**: Shows detailed query plans to help optimize memory consumption
2107
+ - **Configurable Thresholds**: Set custom memory usage thresholds (default: 4MB warning)
2108
+ - **Automatic Filtering**: Excludes system queries (`Use`, `Set`, `Show`) and empty queries
2109
+ - **Scheduled Monitoring**: Run automatically on configurable intervals
2110
+
2111
+ ### Basic Usage
2112
+
2113
+ #### 1. Import the Trigger
2114
+
2115
+ ```typescript
2116
+ import ForgeSQL, { topSlowestStatementLastHourTrigger } from "forge-sql-orm";
2117
+ ```
2118
+
2119
+ #### 2. Create a Scheduler Function
2120
+
2121
+ ```typescript
2122
+ import ForgeSQL, { topSlowestStatementLastHourTrigger } from 'forge-sql-orm';
2123
+
2124
+ // Initialize ForgeSQL ORM instance
2125
+ const forgeSQL = new ForgeSQL();
2126
+
2127
+ // Basic usage with default thresholds (300ms latency, 8MB memory warning)
2128
+ export const memoryUsageTrigger = () =>
2129
+ topSlowestStatementLastHourTrigger(forgeSQL);
2130
+
2131
+ // Conservative memory monitoring: 4MB warning (well below 16MB limit)
2132
+ export const conservativeMemoryTrigger = () =>
2133
+ topSlowestStatementLastHourTrigger(forgeSQL, { memoryThresholdBytes: 4 * 1024 * 1024 });
2134
+
2135
+ // Aggressive memory monitoring: 12MB warning (75% of 16MB limit)
2136
+ export const aggressiveMemoryTrigger = () =>
2137
+ topSlowestStatementLastHourTrigger(forgeSQL, { memoryThresholdBytes: 12 * 1024 * 1024 });
2138
+
2139
+ // Memory-only monitoring: Only trigger on memory usage (latency effectively disabled)
2140
+ export const memoryOnlyTrigger = () =>
2141
+ topSlowestStatementLastHourTrigger(forgeSQL, { warnThresholdMs: 10000, memoryThresholdBytes: 4 * 1024 * 1024 });
2142
+
2143
+ // Latency-only monitoring: Only trigger on slow queries (memory effectively disabled)
2144
+ export const latencyOnlyTrigger = () =>
2145
+ topSlowestStatementLastHourTrigger(forgeSQL, { warnThresholdMs: 500, memoryThresholdBytes: 16 * 1024 * 1024 });
2146
+
2147
+ // With execution plan in logs
2148
+ export const withPlanTrigger = () =>
2149
+ topSlowestStatementLastHourTrigger(forgeSQL, { showPlan: true });
2150
+
2151
+ // With cache logging enabled
2152
+ export const withCacheLoggingTrigger = () =>
2153
+ topSlowestStatementLastHourTrigger(forgeSQL, { logCache: true });
2154
+
2155
+ // With both execution plan and cache logging
2156
+ export const withFullLoggingTrigger = () =>
2157
+ topSlowestStatementLastHourTrigger(forgeSQL, { showPlan: true, logCache: true });
2158
+
2159
+ // With custom ORM options for debugging
2160
+ const forgeSQL = new ForgeSQL({
2161
+ logRawSqlQuery: true,
2162
+ logCache: true,
2163
+ cacheEntityName: "cache"
2164
+ });
2165
+
2166
+
2167
+ #### 3. Configure in manifest.yml
2168
+
2169
+ **As Scheduler Trigger (Recommended for Production):**
2170
+ ```yaml
2171
+ scheduledTrigger:
2172
+ - key: memory-usage-trigger
2173
+ function: memoryUsageTrigger
2174
+ interval: hour # Required: only hour interval is supported
2175
+
2176
+ function:
2177
+ - key: memoryUsageTrigger
2178
+ handler: index.memoryUsageTrigger
2179
+ ```
2180
+
2181
+ **As Web Trigger (Development Only):**
2182
+ ```yaml
2183
+ webtrigger:
2184
+ - key: print-slowest-queries
2185
+ function: memoryUsageTrigger
2186
+
2187
+ function:
2188
+ - key: memoryUsageTrigger
2189
+ handler: index.memoryUsageTrigger
2190
+ ```
2191
+
2192
+ > **⚠️ Important**: Web triggers are not recommended for production as they violate the "run-on-atlassian" principle. Use scheduler triggers for production monitoring.
2193
+
2194
+ ### How It Works
2195
+
2196
+ The memory monitoring trigger works differently depending on how it's configured:
2197
+
2198
+ #### Scheduler Trigger Mode (Production)
2199
+
2200
+ When used as a **scheduler trigger**, the system:
2201
+ - **Runs automatically** on the configured interval (hour only)
2202
+ - **Logs to Forge Developer Console** only when thresholds are exceeded
2203
+ - **No HTTP response** - operates silently in the background
2204
+ - **Perfect for production** monitoring without violating "run-on-atlassian"
2205
+
2206
+ **Example Console Log Output:**
2207
+ ```
2208
+ 1. Select avg=3006.03ms max=3006.03ms mem≈0.08MB(max 0.08MB) exec=1
2209
+ digest=28344800f90f6c929484e83337404df7e55a660c5f4ce922c4b298ab5e90c425
2210
+ sql=select `demo_users` . `id` as `a_userid_id` , `demo_users` . `name` as `a_username_name` , `demo_orders` . `product` as `a_product_product` , `demo_orders` . `id` as `a_productid_id` , `sleep` ( ? ) from `demo_users` inner join `demo_orders` on `demo_orders` . `user_id` = `demo_users` . `id`
2211
+
2212
+ full plan:
2213
+ id task estRows operator info actRows execution info memory disk
2214
+ Projection_7 root 2.50 forge_38dd1c6156b94bb59c2c9a45582bbfc7.demo_users.id, forge_38dd1c6156b94bb59c2c9a45582bbfc7.demo_users.name, forge_38dd1c6156b94bb59c2c9a45582bbfc7.demo_orders.product, forge_38dd1c6156b94bb59c2c9a45582bbfc7.demo_orders.id, sleep(?)->Column#7 3 time:3s, loops:2, Concurrency:OFF 1.98 KB N/A
2215
+ └─IndexHashJoin_14 root 2.50 inner join, inner:IndexLookUp_11, outer key:forge_38dd1c6156b94bb59c2c9a45582bbfc7.demo_users.id, inner key:forge_38dd1c6156b94bb59c2c9a45582bbfc7.demo_orders.user_id, equal cond:eq(forge_38dd1c6156b94bb59c2c9a45582bbfc7.demo_users.id, forge_38dd1c6156b94bb59c2c9a45582bbfc7.demo_orders.user_id) 3 time:2.11ms, loops:2, inner:{total:1.31ms, concurrency:5, task:1, construct:6.62µs, fetch:1.3ms, build:4.68µs, join:6.14µs} 57.9 KB N/A
2216
+ ```
2217
+
2218
+ #### Web Trigger Mode (Development)
2219
+
2220
+ When used as a **web trigger**, the system:
2221
+ - **Runs on-demand** when the web endpoint is called
2222
+ - **Returns JSON response** with detailed metrics
2223
+ - **Logs to console** AND provides structured data
2224
+ - **Useful for development** and debugging
2225
+
2226
+ **Example JSON Response:**
2227
+ ```json
2228
+ {
2229
+ "success": true,
2230
+ "window": "last_1h",
2231
+ "top": 1,
2232
+ "warnThresholdMs": 300,
2233
+ "memoryThresholdBytes": 8388608,
2234
+ "rows": [
2235
+ {
2236
+ "rank": 1,
2237
+ "digest": "abc123...",
2238
+ "stmtType": "Select",
2239
+ "schemaName": "myapp",
2240
+ "execCount": 150,
2241
+ "avgLatencyMs": 450.25,
2242
+ "maxLatencyMs": 1200.50,
2243
+ "minLatencyMs": 200.10,
2244
+ "avgProcessTimeMs": 400.20,
2245
+ "avgWaitTimeMs": 50.05,
2246
+ "avgBackoffTimeMs": 0.00,
2247
+ "avgMemMB": 2.5,
2248
+ "maxMemMB": 8.2,
2249
+ "avgMemBytes": 2621440,
2250
+ "maxMemBytes": 8598323,
2251
+ "avgTotalKeys": 1000,
2252
+ "firstSeen": "2024-01-15 10:30:00",
2253
+ "lastSeen": "2024-01-15 11:30:00",
2254
+ "planInCache": true,
2255
+ "planCacheHits": 120,
2256
+ "digestText": "SELECT * FROM users WHERE active = ?",
2257
+ "plan": "IndexScan(users, idx_active)..."
2258
+ }
2259
+ ],
2260
+ "generatedAt": "2024-01-15T11:30:00.000Z"
2261
+ }
2262
+ ```
2263
+
2264
+ ### Configuration Options
2265
+
2266
+ #### Threshold Parameters
2267
+
2268
+ | Parameter | Type | Default | Description |
2269
+ |-----------|------|---------|-------------|
2270
+ | `warnThresholdMs` | `number` | `300` | Latency threshold in milliseconds (secondary) |
2271
+ | `memoryThresholdBytes` | `number` | `8 * 1024 * 1024` | **Memory usage threshold in bytes (primary focus)** |
2272
+ | `showPlan` | `boolean` | `false` | Whether to include execution plan in logs |
2273
+ | `logCache` | `boolean` | `false` | Whether to log cache operations |
2274
+
2275
+ **⚠️ Important: OR Logic**
2276
+ The monitoring uses **OR logic** - if **either** threshold is exceeded, the query will be logged/returned:
2277
+ - Query exceeds `warnThresholdMs` **OR** `memoryThresholdBytes` → Included in results
2278
+ - This means you can set different thresholds for different monitoring priorities
2279
+ - No need to exceed both thresholds simultaneously
2280
+
2281
+ **💡 Pro Tips:**
2282
+ - **Memory-only monitoring**: Set `warnThresholdMs` to a very high value (e.g., 10000ms) to trigger only on memory usage
2283
+ - **Latency-only monitoring**: Set `memoryThresholdBytes` to 16MB (16 * 1024 * 1024) to trigger only on latency
2284
+ - **Combined monitoring**: Use both thresholds for comprehensive monitoring
2285
+ - **Execution plan analysis**: Set `showPlan: true` to include detailed execution plans in logs (useful for debugging)
2286
+ - **Cache debugging**: Set `logCache: true` to log cache operations and debug caching issues
2287
+
2288
+ **Memory Threshold Guidelines:**
2289
+ - **Conservative**: 4MB (25% of 16MB limit)
2290
+ - **Default**: 8MB (50% of 16MB limit)
2291
+ - **Aggressive**: 12MB (75% of 16MB limit)
2292
+ - **Critical**: 14MB (87.5% of 16MB limit)
2293
+
2294
+ #### Available Intervals
2295
+
2296
+ - `hour` - **Every hour (Required)** - Statistics are available for approximately 12 hours
2297
+
2298
+ > **⚠️ Important**: Due to Forge SQL's statistics retention policy (approximately 12 hours), **only `hour` interval is supported**. Using `day` or `week` intervals will result in incomplete or missing data.
2018
2299
 
2019
2300
  ## Migration Guide
2020
2301
 
@@ -2107,6 +2388,16 @@ const cachedRawUsers = await forgeSQL.executeCacheable(
2107
2388
  300
2108
2389
  );
2109
2390
 
2391
+ // ✅ Raw SQL execution with metadata capture
2392
+ const usersWithMetadata = await forgeSQL.executeWithMetadata(
2393
+ async () => await forgeSQL.execute("SELECT * FROM users WHERE active = ?", [true]),
2394
+ (totalDbExecutionTime, totalResponseSize, forgeMetadata) => {
2395
+ console.log(`DB execution time: ${totalDbExecutionTime}ms`);
2396
+ console.log(`Response size: ${totalResponseSize} bytes`);
2397
+ console.log('Forge metadata:', forgeMetadata);
2398
+ }
2399
+ );
2400
+
2110
2401
  // ✅ Common Table Expressions (CTEs)
2111
2402
  const userStats = await forgeSQL
2112
2403
  .with(