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.
- package/README.md +291 -0
- package/dist/ForgeSQLORM.js +713 -12
- package/dist/ForgeSQLORM.js.map +1 -1
- package/dist/ForgeSQLORM.mjs +716 -15
- package/dist/ForgeSQLORM.mjs.map +1 -1
- package/dist/core/ForgeSQLCrudOperations.d.ts.map +1 -1
- package/dist/core/ForgeSQLORM.d.ts +23 -0
- package/dist/core/ForgeSQLORM.d.ts.map +1 -1
- package/dist/core/ForgeSQLQueryBuilder.d.ts +36 -5
- package/dist/core/ForgeSQLQueryBuilder.d.ts.map +1 -1
- package/dist/core/ForgeSQLSelectOperations.d.ts.map +1 -1
- package/dist/core/SystemTables.d.ts +5039 -0
- package/dist/core/SystemTables.d.ts.map +1 -1
- package/dist/lib/drizzle/extensions/additionalActions.d.ts.map +1 -1
- package/dist/utils/cacheContextUtils.d.ts.map +1 -1
- package/dist/utils/cacheUtils.d.ts.map +1 -1
- package/dist/utils/forgeDriver.d.ts +21 -0
- package/dist/utils/forgeDriver.d.ts.map +1 -1
- package/dist/utils/forgeDriverProxy.d.ts.map +1 -1
- package/dist/utils/metadataContextUtils.d.ts +11 -0
- package/dist/utils/metadataContextUtils.d.ts.map +1 -0
- package/dist/utils/sqlUtils.d.ts.map +1 -1
- package/dist/webtriggers/applyMigrationsWebTrigger.d.ts +1 -1
- package/dist/webtriggers/applyMigrationsWebTrigger.d.ts.map +1 -1
- package/dist/webtriggers/clearCacheSchedulerTrigger.d.ts.map +1 -1
- package/dist/webtriggers/dropMigrationWebTrigger.d.ts.map +1 -1
- package/dist/webtriggers/dropTablesMigrationWebTrigger.d.ts.map +1 -1
- package/dist/webtriggers/fetchSchemaWebTrigger.d.ts.map +1 -1
- package/dist/webtriggers/index.d.ts +1 -0
- package/dist/webtriggers/index.d.ts.map +1 -1
- package/dist/webtriggers/topSlowestStatementLastHourTrigger.d.ts +89 -0
- package/dist/webtriggers/topSlowestStatementLastHourTrigger.d.ts.map +1 -0
- package/package.json +4 -3
- package/src/core/ForgeSQLCrudOperations.ts +3 -0
- package/src/core/ForgeSQLORM.ts +119 -51
- package/src/core/ForgeSQLQueryBuilder.ts +51 -17
- package/src/core/ForgeSQLSelectOperations.ts +2 -0
- package/src/core/SystemTables.ts +313 -1
- package/src/lib/drizzle/extensions/additionalActions.ts +2 -0
- package/src/utils/cacheContextUtils.ts +4 -2
- package/src/utils/cacheUtils.ts +20 -8
- package/src/utils/forgeDriver.ts +22 -1
- package/src/utils/forgeDriverProxy.ts +2 -0
- package/src/utils/metadataContextUtils.ts +24 -0
- package/src/utils/sqlUtils.ts +1 -0
- package/src/webtriggers/applyMigrationsWebTrigger.ts +10 -5
- package/src/webtriggers/clearCacheSchedulerTrigger.ts +1 -0
- package/src/webtriggers/dropMigrationWebTrigger.ts +2 -0
- package/src/webtriggers/dropTablesMigrationWebTrigger.ts +2 -0
- package/src/webtriggers/fetchSchemaWebTrigger.ts +1 -0
- package/src/webtriggers/index.ts +1 -0
- package/src/webtriggers/topSlowestStatementLastHourTrigger.ts +360 -0
|
@@ -26,19 +26,19 @@ import {
|
|
|
26
26
|
} from "./SystemTables";
|
|
27
27
|
import { ForgeSQLCacheOperations } from "./ForgeSQLCacheOperations";
|
|
28
28
|
import {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
29
|
+
DeleteAndEvictCacheType,
|
|
30
|
+
ExecuteQuery,
|
|
31
|
+
ExecuteQueryCacheable, ForgeSQLMetadata,
|
|
32
|
+
InsertAndEvictCacheType,
|
|
33
|
+
SelectAliasedCacheableType,
|
|
34
|
+
SelectAliasedDistinctCacheableType,
|
|
35
|
+
SelectAliasedDistinctType,
|
|
36
|
+
SelectAliasedType,
|
|
37
|
+
SelectAllDistinctFromAliasedType,
|
|
38
|
+
SelectAllDistinctFromCacheableAliasedType,
|
|
39
|
+
SelectAllFromAliasedType,
|
|
40
|
+
SelectAllFromCacheableAliasedType,
|
|
41
|
+
UpdateAndEvictCacheType,
|
|
42
42
|
} from "..";
|
|
43
43
|
import {
|
|
44
44
|
MySqlDeleteBase,
|
|
@@ -497,6 +497,31 @@ export interface QueryBuilderForgeSql {
|
|
|
497
497
|
*/
|
|
498
498
|
executeWithLocalCacheContextAndReturnValue<T>(cacheContext: () => Promise<T>): Promise<T>;
|
|
499
499
|
|
|
500
|
+
/**
|
|
501
|
+
* Executes a query and provides access to execution metadata.
|
|
502
|
+
* This method allows you to capture detailed information about query execution
|
|
503
|
+
* including database execution time, response size, and Forge SQL metadata.
|
|
504
|
+
*
|
|
505
|
+
* @template T - The return type of the query
|
|
506
|
+
* @param query - A function that returns a Promise with the query result
|
|
507
|
+
* @param onMetadata - Callback function that receives execution metadata
|
|
508
|
+
* @returns Promise with the query result
|
|
509
|
+
* @example
|
|
510
|
+
* ```typescript
|
|
511
|
+
* const result = await forgeSQL.executeWithMetadata(
|
|
512
|
+
* async () => await forgeSQL.select().from(users).where(eq(users.id, 1)),
|
|
513
|
+
* (dbTime, responseSize, metadata) => {
|
|
514
|
+
* console.log(`DB execution time: ${dbTime}ms`);
|
|
515
|
+
* console.log(`Response size: ${responseSize} bytes`);
|
|
516
|
+
* console.log('Forge metadata:', metadata);
|
|
517
|
+
* }
|
|
518
|
+
* );
|
|
519
|
+
* ```
|
|
520
|
+
*/
|
|
521
|
+
executeWithMetadata<T>(
|
|
522
|
+
query: () => Promise<T>,
|
|
523
|
+
onMetadata: (totalDbExecutionTime: number, totalResponseSize: number, forgeMetadata: ForgeSQLMetadata) => Promise<void> | void
|
|
524
|
+
): Promise<T>;
|
|
500
525
|
/**
|
|
501
526
|
* Executes a raw SQL query with local cache support.
|
|
502
527
|
* This method provides local caching for raw SQL queries within the current invocation context.
|
|
@@ -816,22 +841,31 @@ export type AdditionalMetadata = Record<string, TableMetadata>;
|
|
|
816
841
|
* @interface ForgeSqlOrmOptions
|
|
817
842
|
*/
|
|
818
843
|
export interface ForgeSqlOrmOptions {
|
|
819
|
-
/** Whether to log raw SQL queries */
|
|
844
|
+
/** Whether to log raw SQL queries to the console */
|
|
820
845
|
logRawSqlQuery?: boolean;
|
|
821
|
-
/** Whether to
|
|
846
|
+
/** Whether to log cache operations (hits, misses, evictions) */
|
|
847
|
+
logCache?: boolean;
|
|
848
|
+
/** Whether to disable optimistic locking for update operations */
|
|
822
849
|
disableOptimisticLocking?: boolean;
|
|
823
|
-
/** SQL hints to be applied to queries */
|
|
850
|
+
/** SQL hints to be applied to queries for optimization */
|
|
824
851
|
hints?: SqlHints;
|
|
852
|
+
/** Default Cache TTL (Time To Live) in seconds */
|
|
825
853
|
cacheTTL?: number;
|
|
854
|
+
/** Name of the KVS entity used for cache storage */
|
|
826
855
|
cacheEntityName?: string;
|
|
856
|
+
/** Name of the field in cache entity that stores SQL query */
|
|
827
857
|
cacheEntityQueryName?: string;
|
|
858
|
+
/** Whether to wrap table names with backticks in cache keys */
|
|
828
859
|
cacheWrapTable?: boolean;
|
|
860
|
+
/** Name of the field in cache entity that stores expiration timestamp */
|
|
829
861
|
cacheEntityExpirationName?: string;
|
|
862
|
+
/** Name of the field in cache entity that stores cached data */
|
|
830
863
|
cacheEntityDataName?: string;
|
|
831
864
|
|
|
832
865
|
/**
|
|
833
866
|
* Additional metadata for table configuration.
|
|
834
|
-
* Allows specifying table-specific settings and behaviors.
|
|
867
|
+
* Allows specifying table-specific settings and behaviors such as version fields for optimistic locking.
|
|
868
|
+
*
|
|
835
869
|
* @example
|
|
836
870
|
* ```typescript
|
|
837
871
|
* {
|
|
@@ -58,6 +58,7 @@ export class ForgeSQLSelectOperations implements SchemaSqlForgeSql {
|
|
|
58
58
|
async executeRawSQL<T extends object | unknown>(query: string, params?: unknown[]): Promise<T[]> {
|
|
59
59
|
if (this.options.logRawSqlQuery) {
|
|
60
60
|
const paramsStr = params ? `, with params: ${JSON.stringify(params)}` : "";
|
|
61
|
+
// eslint-disable-next-line no-console
|
|
61
62
|
console.debug(`Executing with SQL ${query}${paramsStr}`);
|
|
62
63
|
}
|
|
63
64
|
const sqlStatement = sql.prepare<T>(query);
|
|
@@ -80,6 +81,7 @@ export class ForgeSQLSelectOperations implements SchemaSqlForgeSql {
|
|
|
80
81
|
sqlStatement.bindParams(...params);
|
|
81
82
|
}
|
|
82
83
|
if (this.options.logRawSqlQuery) {
|
|
84
|
+
// eslint-disable-next-line no-console
|
|
83
85
|
console.debug(
|
|
84
86
|
`Executing Update with SQL ${query}` +
|
|
85
87
|
(params ? `, with params: ${JSON.stringify(params)}` : ""),
|
package/src/core/SystemTables.ts
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
bigint,
|
|
3
|
+
mysqlTable,
|
|
4
|
+
timestamp,
|
|
5
|
+
varchar,
|
|
6
|
+
double,
|
|
7
|
+
mysqlSchema,
|
|
8
|
+
longtext,
|
|
9
|
+
int,
|
|
10
|
+
text,
|
|
11
|
+
boolean,
|
|
12
|
+
} from "drizzle-orm/mysql-core";
|
|
2
13
|
import { Table } from "drizzle-orm";
|
|
3
14
|
import { sql } from "@forge/sql";
|
|
4
15
|
|
|
@@ -8,6 +19,307 @@ export const migrations = mysqlTable("__migrations", {
|
|
|
8
19
|
migratedAt: timestamp("migratedAt").defaultNow().notNull(),
|
|
9
20
|
});
|
|
10
21
|
|
|
22
|
+
const informationSchema = mysqlSchema("information_schema");
|
|
23
|
+
|
|
24
|
+
export const slowQuery = informationSchema.table("SLOW_QUERY", {
|
|
25
|
+
time: timestamp("Time", { fsp: 6, mode: "string" }).notNull(), // Timestamp when the slow query was recorded
|
|
26
|
+
|
|
27
|
+
txnStartTs: bigint("Txn_start_ts", { mode: "bigint", unsigned: true }), // Transaction start timestamp (TSO)
|
|
28
|
+
user: varchar("User", { length: 64 }), // User executing the query
|
|
29
|
+
host: varchar("Host", { length: 64 }), // Host from which the query originated
|
|
30
|
+
connId: bigint("Conn_ID", { mode: "bigint", unsigned: true }), // Connection ID
|
|
31
|
+
sessionAlias: varchar("Session_alias", { length: 64 }), // Session alias
|
|
32
|
+
|
|
33
|
+
execRetryCount: bigint("Exec_retry_count", { mode: "bigint", unsigned: true }), // Number of retries during execution
|
|
34
|
+
execRetryTime: double("Exec_retry_time"), // Time spent in retries
|
|
35
|
+
queryTime: double("Query_time"), // Total execution time
|
|
36
|
+
parseTime: double("Parse_time"), // Time spent parsing SQL
|
|
37
|
+
compileTime: double("Compile_time"), // Time spent compiling query plan
|
|
38
|
+
rewriteTime: double("Rewrite_time"), // Time spent rewriting query
|
|
39
|
+
preprocSubqueries: bigint("Preproc_subqueries", { mode: "bigint", unsigned: true }), // Number of subqueries preprocessed
|
|
40
|
+
preprocSubqueriesTime: double("Preproc_subqueries_time"), // Time spent preprocessing subqueries
|
|
41
|
+
optimizeTime: double("Optimize_time"), // Time spent in optimizer
|
|
42
|
+
waitTs: double("Wait_TS"), // Wait time for getting TSO
|
|
43
|
+
prewriteTime: double("Prewrite_time"), // Time spent in prewrite phase
|
|
44
|
+
waitPrewriteBinlogTime: double("Wait_prewrite_binlog_time"), // Time waiting for binlog prewrite
|
|
45
|
+
commitTime: double("Commit_time"), // Commit duration
|
|
46
|
+
getCommitTsTime: double("Get_commit_ts_time"), // Time waiting for commit TSO
|
|
47
|
+
commitBackoffTime: double("Commit_backoff_time"), // Backoff time during commit
|
|
48
|
+
backoffTypes: varchar("Backoff_types", { length: 64 }), // Types of backoff occurred
|
|
49
|
+
resolveLockTime: double("Resolve_lock_time"), // Time resolving locks
|
|
50
|
+
localLatchWaitTime: double("Local_latch_wait_time"), // Time waiting on local latch
|
|
51
|
+
|
|
52
|
+
writeKeys: bigint("Write_keys", { mode: "bigint" }), // Number of keys written
|
|
53
|
+
writeSize: bigint("Write_size", { mode: "bigint" }), // Amount of data written
|
|
54
|
+
prewriteRegion: bigint("Prewrite_region", { mode: "bigint" }), // Regions involved in prewrite
|
|
55
|
+
txnRetry: bigint("Txn_retry", { mode: "bigint" }), // Transaction retry count
|
|
56
|
+
|
|
57
|
+
copTime: double("Cop_time"), // Time spent in coprocessor
|
|
58
|
+
processTime: double("Process_time"), // Processing time
|
|
59
|
+
waitTime: double("Wait_time"), // Wait time in TiKV
|
|
60
|
+
backoffTime: double("Backoff_time"), // Backoff wait time
|
|
61
|
+
lockKeysTime: double("LockKeys_time"), // Time spent waiting for locks
|
|
62
|
+
|
|
63
|
+
requestCount: bigint("Request_count", { mode: "bigint", unsigned: true }), // Total number of requests
|
|
64
|
+
totalKeys: bigint("Total_keys", { mode: "bigint", unsigned: true }), // Total keys scanned
|
|
65
|
+
processKeys: bigint("Process_keys", { mode: "bigint", unsigned: true }), // Keys processed
|
|
66
|
+
|
|
67
|
+
rocksdbDeleteSkippedCount: bigint("Rocksdb_delete_skipped_count", {
|
|
68
|
+
mode: "bigint",
|
|
69
|
+
unsigned: true,
|
|
70
|
+
}), // RocksDB delete skips
|
|
71
|
+
rocksdbKeySkippedCount: bigint("Rocksdb_key_skipped_count", { mode: "bigint", unsigned: true }), // RocksDB key skips
|
|
72
|
+
rocksdbBlockCacheHitCount: bigint("Rocksdb_block_cache_hit_count", {
|
|
73
|
+
mode: "bigint",
|
|
74
|
+
unsigned: true,
|
|
75
|
+
}), // RocksDB block cache hits
|
|
76
|
+
rocksdbBlockReadCount: bigint("Rocksdb_block_read_count", { mode: "bigint", unsigned: true }), // RocksDB block reads
|
|
77
|
+
rocksdbBlockReadByte: bigint("Rocksdb_block_read_byte", { mode: "bigint", unsigned: true }), // RocksDB block read bytes
|
|
78
|
+
|
|
79
|
+
db: varchar("DB", { length: 64 }), // Database name
|
|
80
|
+
indexNames: varchar("Index_names", { length: 100 }), // Indexes used
|
|
81
|
+
|
|
82
|
+
isInternal: boolean("Is_internal"), // Whether the query is internal
|
|
83
|
+
digest: varchar("Digest", { length: 64 }), // SQL digest hash
|
|
84
|
+
stats: varchar("Stats", { length: 512 }), // Stats used during planning
|
|
85
|
+
|
|
86
|
+
copProcAvg: double("Cop_proc_avg"), // Coprocessor average processing time
|
|
87
|
+
copProcP90: double("Cop_proc_p90"), // Coprocessor 90th percentile processing time
|
|
88
|
+
copProcMax: double("Cop_proc_max"), // Coprocessor max processing time
|
|
89
|
+
copProcAddr: varchar("Cop_proc_addr", { length: 64 }), // Coprocessor address for processing
|
|
90
|
+
|
|
91
|
+
copWaitAvg: double("Cop_wait_avg"), // Coprocessor average wait time
|
|
92
|
+
copWaitP90: double("Cop_wait_p90"), // Coprocessor 90th percentile wait time
|
|
93
|
+
copWaitMax: double("Cop_wait_max"), // Coprocessor max wait time
|
|
94
|
+
copWaitAddr: varchar("Cop_wait_addr", { length: 64 }), // Coprocessor address for wait
|
|
95
|
+
|
|
96
|
+
memMax: bigint("Mem_max", { mode: "bigint" }), // Max memory usage
|
|
97
|
+
diskMax: bigint("Disk_max", { mode: "bigint" }), // Max disk usage
|
|
98
|
+
|
|
99
|
+
kvTotal: double("KV_total"), // Total KV request time
|
|
100
|
+
pdTotal: double("PD_total"), // Total PD request time
|
|
101
|
+
backoffTotal: double("Backoff_total"), // Total backoff time
|
|
102
|
+
writeSqlResponseTotal: double("Write_sql_response_total"), // SQL response write time
|
|
103
|
+
|
|
104
|
+
resultRows: bigint("Result_rows", { mode: "bigint" }), // Rows returned
|
|
105
|
+
warnings: longtext("Warnings"), // Warnings during execution
|
|
106
|
+
backoffDetail: varchar("Backoff_Detail", { length: 4096 }), // Detailed backoff info
|
|
107
|
+
|
|
108
|
+
prepared: boolean("Prepared"), // Whether query was prepared
|
|
109
|
+
succ: boolean("Succ"), // Success flag
|
|
110
|
+
isExplicitTxn: boolean("IsExplicitTxn"), // Whether explicit transaction
|
|
111
|
+
isWriteCacheTable: boolean("IsWriteCacheTable"), // Whether wrote to cache table
|
|
112
|
+
planFromCache: boolean("Plan_from_cache"), // Plan was from cache
|
|
113
|
+
planFromBinding: boolean("Plan_from_binding"), // Plan was from binding
|
|
114
|
+
hasMoreResults: boolean("Has_more_results"), // Query returned multiple results
|
|
115
|
+
|
|
116
|
+
resourceGroup: varchar("Resource_group", { length: 64 }), // Resource group name
|
|
117
|
+
requestUnitRead: double("Request_unit_read"), // RU consumed for read
|
|
118
|
+
requestUnitWrite: double("Request_unit_write"), // RU consumed for write
|
|
119
|
+
timeQueuedByRc: double("Time_queued_by_rc"), // Time queued by resource control
|
|
120
|
+
|
|
121
|
+
tidbCpuTime: double("Tidb_cpu_time"), // TiDB CPU time
|
|
122
|
+
tikvCpuTime: double("Tikv_cpu_time"), // TiKV CPU time
|
|
123
|
+
|
|
124
|
+
plan: longtext("Plan"), // Query execution plan
|
|
125
|
+
planDigest: varchar("Plan_digest", { length: 128 }), // Plan digest hash
|
|
126
|
+
binaryPlan: longtext("Binary_plan"), // Binary execution plan
|
|
127
|
+
prevStmt: longtext("Prev_stmt"), // Previous statement in session
|
|
128
|
+
query: longtext("Query"), // Original SQL query
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
export type SlowQuery = typeof slowQuery.$inferSelect;
|
|
132
|
+
|
|
133
|
+
// Common schema for cluster statements summary tables
|
|
134
|
+
const createClusterStatementsSummarySchema = () => ({
|
|
135
|
+
instance: varchar("INSTANCE", { length: 64 }), // TiDB/TiKV instance address
|
|
136
|
+
|
|
137
|
+
summaryBeginTime: timestamp("SUMMARY_BEGIN_TIME", { mode: "string" }).notNull(), // Begin time of this summary window
|
|
138
|
+
summaryEndTime: timestamp("SUMMARY_END_TIME", { mode: "string" }).notNull(), // End time of this summary window
|
|
139
|
+
|
|
140
|
+
stmtType: varchar("STMT_TYPE", { length: 64 }).notNull(), // Statement type (e.g., Select/Insert/Update)
|
|
141
|
+
schemaName: varchar("SCHEMA_NAME", { length: 64 }), // Current schema name
|
|
142
|
+
digest: varchar("DIGEST", { length: 64 }), // SQL digest (normalized hash)
|
|
143
|
+
digestText: text("DIGEST_TEXT").notNull(), // Normalized SQL text
|
|
144
|
+
|
|
145
|
+
tableNames: text("TABLE_NAMES"), // Involved table names
|
|
146
|
+
indexNames: text("INDEX_NAMES"), // Used index names
|
|
147
|
+
|
|
148
|
+
sampleUser: varchar("SAMPLE_USER", { length: 64 }), // Sampled user who executed the statements
|
|
149
|
+
|
|
150
|
+
execCount: bigint("EXEC_COUNT", { mode: "bigint", unsigned: true }).notNull(), // Total executions
|
|
151
|
+
sumErrors: int("SUM_ERRORS", { unsigned: true }).notNull(), // Sum of errors
|
|
152
|
+
sumWarnings: int("SUM_WARNINGS", { unsigned: true }).notNull(), // Sum of warnings
|
|
153
|
+
|
|
154
|
+
sumLatency: bigint("SUM_LATENCY", { mode: "bigint", unsigned: true }).notNull(), // Sum of latency (ns)
|
|
155
|
+
maxLatency: bigint("MAX_LATENCY", { mode: "bigint", unsigned: true }).notNull(), // Max latency (ns)
|
|
156
|
+
minLatency: bigint("MIN_LATENCY", { mode: "bigint", unsigned: true }).notNull(), // Min latency (ns)
|
|
157
|
+
avgLatency: bigint("AVG_LATENCY", { mode: "bigint", unsigned: true }).notNull(), // Avg latency (ns)
|
|
158
|
+
|
|
159
|
+
avgParseLatency: bigint("AVG_PARSE_LATENCY", { mode: "bigint", unsigned: true }).notNull(), // Avg parse time (ns)
|
|
160
|
+
maxParseLatency: bigint("MAX_PARSE_LATENCY", { mode: "bigint", unsigned: true }).notNull(), // Max parse time (ns)
|
|
161
|
+
avgCompileLatency: bigint("AVG_COMPILE_LATENCY", { mode: "bigint", unsigned: true }).notNull(), // Avg compile time (ns)
|
|
162
|
+
maxCompileLatency: bigint("MAX_COMPILE_LATENCY", { mode: "bigint", unsigned: true }).notNull(), // Max compile time (ns)
|
|
163
|
+
|
|
164
|
+
sumCopTaskNum: bigint("SUM_COP_TASK_NUM", { mode: "bigint", unsigned: true }).notNull(), // Total number of cop tasks
|
|
165
|
+
maxCopProcessTime: bigint("MAX_COP_PROCESS_TIME", { mode: "bigint", unsigned: true }).notNull(), // Max TiKV coprocessor processing time (ns)
|
|
166
|
+
maxCopProcessAddress: varchar("MAX_COP_PROCESS_ADDRESS", { length: 256 }), // Address of cop task with max processing time
|
|
167
|
+
maxCopWaitTime: bigint("MAX_COP_WAIT_TIME", { mode: "bigint", unsigned: true }).notNull(), // Max TiKV coprocessor wait time (ns)
|
|
168
|
+
maxCopWaitAddress: varchar("MAX_COP_WAIT_ADDRESS", { length: 256 }), // Address of cop task with max wait time
|
|
169
|
+
|
|
170
|
+
avgProcessTime: bigint("AVG_PROCESS_TIME", { mode: "bigint", unsigned: true }).notNull(), // Avg TiKV processing time (ns)
|
|
171
|
+
maxProcessTime: bigint("MAX_PROCESS_TIME", { mode: "bigint", unsigned: true }).notNull(), // Max TiKV processing time (ns)
|
|
172
|
+
avgWaitTime: bigint("AVG_WAIT_TIME", { mode: "bigint", unsigned: true }).notNull(), // Avg TiKV wait time (ns)
|
|
173
|
+
maxWaitTime: bigint("MAX_WAIT_TIME", { mode: "bigint", unsigned: true }).notNull(), // Max TiKV wait time (ns)
|
|
174
|
+
|
|
175
|
+
avgBackoffTime: bigint("AVG_BACKOFF_TIME", { mode: "bigint", unsigned: true }).notNull(), // Avg backoff time before retry (ns)
|
|
176
|
+
maxBackoffTime: bigint("MAX_BACKOFF_TIME", { mode: "bigint", unsigned: true }).notNull(), // Max backoff time before retry (ns)
|
|
177
|
+
|
|
178
|
+
avgTotalKeys: bigint("AVG_TOTAL_KEYS", { mode: "bigint", unsigned: true }).notNull(), // Avg scanned keys
|
|
179
|
+
maxTotalKeys: bigint("MAX_TOTAL_KEYS", { mode: "bigint", unsigned: true }).notNull(), // Max scanned keys
|
|
180
|
+
avgProcessedKeys: bigint("AVG_PROCESSED_KEYS", { mode: "bigint", unsigned: true }).notNull(), // Avg processed keys
|
|
181
|
+
maxProcessedKeys: bigint("MAX_PROCESSED_KEYS", { mode: "bigint", unsigned: true }).notNull(), // Max processed keys
|
|
182
|
+
|
|
183
|
+
avgRocksdbDeleteSkippedCount: double("AVG_ROCKSDB_DELETE_SKIPPED_COUNT").notNull(), // Avg RocksDB deletes skipped
|
|
184
|
+
maxRocksdbDeleteSkippedCount: int("MAX_ROCKSDB_DELETE_SKIPPED_COUNT", {
|
|
185
|
+
unsigned: true,
|
|
186
|
+
}).notNull(), // Max RocksDB deletes skipped
|
|
187
|
+
avgRocksdbKeySkippedCount: double("AVG_ROCKSDB_KEY_SKIPPED_COUNT").notNull(), // Avg RocksDB keys skipped
|
|
188
|
+
maxRocksdbKeySkippedCount: int("MAX_ROCKSDB_KEY_SKIPPED_COUNT", { unsigned: true }).notNull(), // Max RocksDB keys skipped
|
|
189
|
+
avgRocksdbBlockCacheHitCount: double("AVG_ROCKSDB_BLOCK_CACHE_HIT_COUNT").notNull(), // Avg RocksDB block cache hits
|
|
190
|
+
maxRocksdbBlockCacheHitCount: int("MAX_ROCKSDB_BLOCK_CACHE_HIT_COUNT", {
|
|
191
|
+
unsigned: true,
|
|
192
|
+
}).notNull(), // Max RocksDB block cache hits
|
|
193
|
+
avgRocksdbBlockReadCount: double("AVG_ROCKSDB_BLOCK_READ_COUNT").notNull(), // Avg RocksDB block reads
|
|
194
|
+
maxRocksdbBlockReadCount: int("MAX_ROCKSDB_BLOCK_READ_COUNT", { unsigned: true }).notNull(), // Max RocksDB block reads
|
|
195
|
+
avgRocksdbBlockReadByte: double("AVG_ROCKSDB_BLOCK_READ_BYTE").notNull(), // Avg RocksDB block read bytes
|
|
196
|
+
maxRocksdbBlockReadByte: int("MAX_ROCKSDB_BLOCK_READ_BYTE", { unsigned: true }).notNull(), // Max RocksDB block read bytes
|
|
197
|
+
|
|
198
|
+
avgPrewriteTime: bigint("AVG_PREWRITE_TIME", { mode: "bigint", unsigned: true }).notNull(), // Avg prewrite phase time (ns)
|
|
199
|
+
maxPrewriteTime: bigint("MAX_PREWRITE_TIME", { mode: "bigint", unsigned: true }).notNull(), // Max prewrite phase time (ns)
|
|
200
|
+
avgCommitTime: bigint("AVG_COMMIT_TIME", { mode: "bigint", unsigned: true }).notNull(), // Avg commit phase time (ns)
|
|
201
|
+
maxCommitTime: bigint("MAX_COMMIT_TIME", { mode: "bigint", unsigned: true }).notNull(), // Max commit phase time (ns)
|
|
202
|
+
avgGetCommitTsTime: bigint("AVG_GET_COMMIT_TS_TIME", {
|
|
203
|
+
mode: "bigint",
|
|
204
|
+
unsigned: true,
|
|
205
|
+
}).notNull(), // Avg get commit_ts time (ns)
|
|
206
|
+
maxGetCommitTsTime: bigint("MAX_GET_COMMIT_TS_TIME", {
|
|
207
|
+
mode: "bigint",
|
|
208
|
+
unsigned: true,
|
|
209
|
+
}).notNull(), // Max get commit_ts time (ns)
|
|
210
|
+
avgCommitBackoffTime: bigint("AVG_COMMIT_BACKOFF_TIME", {
|
|
211
|
+
mode: "bigint",
|
|
212
|
+
unsigned: true,
|
|
213
|
+
}).notNull(), // Avg backoff during commit (ns)
|
|
214
|
+
maxCommitBackoffTime: bigint("MAX_COMMIT_BACKOFF_TIME", {
|
|
215
|
+
mode: "bigint",
|
|
216
|
+
unsigned: true,
|
|
217
|
+
}).notNull(), // Max backoff during commit (ns)
|
|
218
|
+
avgResolveLockTime: bigint("AVG_RESOLVE_LOCK_TIME", {
|
|
219
|
+
mode: "bigint",
|
|
220
|
+
unsigned: true,
|
|
221
|
+
}).notNull(), // Avg resolve lock time (ns)
|
|
222
|
+
maxResolveLockTime: bigint("MAX_RESOLVE_LOCK_TIME", {
|
|
223
|
+
mode: "bigint",
|
|
224
|
+
unsigned: true,
|
|
225
|
+
}).notNull(), // Max resolve lock time (ns)
|
|
226
|
+
avgLocalLatchWaitTime: bigint("AVG_LOCAL_LATCH_WAIT_TIME", {
|
|
227
|
+
mode: "bigint",
|
|
228
|
+
unsigned: true,
|
|
229
|
+
}).notNull(), // Avg local latch wait (ns)
|
|
230
|
+
maxLocalLatchWaitTime: bigint("MAX_LOCAL_LATCH_WAIT_TIME", {
|
|
231
|
+
mode: "bigint",
|
|
232
|
+
unsigned: true,
|
|
233
|
+
}).notNull(), // Max local latch wait (ns)
|
|
234
|
+
|
|
235
|
+
avgWriteKeys: double("AVG_WRITE_KEYS").notNull(), // Avg number of written keys
|
|
236
|
+
maxWriteKeys: bigint("MAX_WRITE_KEYS", { mode: "bigint", unsigned: true }).notNull(), // Max written keys
|
|
237
|
+
avgWriteSize: double("AVG_WRITE_SIZE").notNull(), // Avg written bytes
|
|
238
|
+
maxWriteSize: bigint("MAX_WRITE_SIZE", { mode: "bigint", unsigned: true }).notNull(), // Max written bytes
|
|
239
|
+
avgPrewriteRegions: double("AVG_PREWRITE_REGIONS").notNull(), // Avg regions in prewrite
|
|
240
|
+
maxPrewriteRegions: int("MAX_PREWRITE_REGIONS", { unsigned: true }).notNull(), // Max regions in prewrite
|
|
241
|
+
avgTxnRetry: double("AVG_TXN_RETRY").notNull(), // Avg transaction retry count
|
|
242
|
+
maxTxnRetry: int("MAX_TXN_RETRY", { unsigned: true }).notNull(), // Max transaction retry count
|
|
243
|
+
|
|
244
|
+
sumExecRetry: bigint("SUM_EXEC_RETRY", { mode: "bigint", unsigned: true }).notNull(), // Sum of execution retries (pessimistic)
|
|
245
|
+
sumExecRetryTime: bigint("SUM_EXEC_RETRY_TIME", { mode: "bigint", unsigned: true }).notNull(), // Sum time of execution retries (ns)
|
|
246
|
+
sumBackoffTimes: bigint("SUM_BACKOFF_TIMES", { mode: "bigint", unsigned: true }).notNull(), // Sum of backoff retries
|
|
247
|
+
backoffTypes: varchar("BACKOFF_TYPES", { length: 1024 }), // Backoff types with counts
|
|
248
|
+
|
|
249
|
+
avgMem: bigint("AVG_MEM", { mode: "bigint", unsigned: true }).notNull(), // Avg memory used (bytes)
|
|
250
|
+
maxMem: bigint("MAX_MEM", { mode: "bigint", unsigned: true }).notNull(), // Max memory used (bytes)
|
|
251
|
+
avgDisk: bigint("AVG_DISK", { mode: "bigint", unsigned: true }).notNull(), // Avg disk used (bytes)
|
|
252
|
+
maxDisk: bigint("MAX_DISK", { mode: "bigint", unsigned: true }).notNull(), // Max disk used (bytes)
|
|
253
|
+
|
|
254
|
+
avgKvTime: bigint("AVG_KV_TIME", { mode: "bigint", unsigned: true }).notNull(), // Avg time spent in TiKV (ns)
|
|
255
|
+
avgPdTime: bigint("AVG_PD_TIME", { mode: "bigint", unsigned: true }).notNull(), // Avg time spent in PD (ns)
|
|
256
|
+
avgBackoffTotalTime: bigint("AVG_BACKOFF_TOTAL_TIME", {
|
|
257
|
+
mode: "bigint",
|
|
258
|
+
unsigned: true,
|
|
259
|
+
}).notNull(), // Avg total backoff time (ns)
|
|
260
|
+
avgWriteSqlRespTime: bigint("AVG_WRITE_SQL_RESP_TIME", {
|
|
261
|
+
mode: "bigint",
|
|
262
|
+
unsigned: true,
|
|
263
|
+
}).notNull(), // Avg write SQL response time (ns)
|
|
264
|
+
|
|
265
|
+
avgTidbCpuTime: bigint("AVG_TIDB_CPU_TIME", { mode: "bigint", unsigned: true }).notNull(), // Avg TiDB CPU time (ns)
|
|
266
|
+
avgTikvCpuTime: bigint("AVG_TIKV_CPU_TIME", { mode: "bigint", unsigned: true }).notNull(), // Avg TiKV CPU time (ns)
|
|
267
|
+
|
|
268
|
+
maxResultRows: bigint("MAX_RESULT_ROWS", { mode: "bigint" }).notNull(), // Max number of result rows
|
|
269
|
+
minResultRows: bigint("MIN_RESULT_ROWS", { mode: "bigint" }).notNull(), // Min number of result rows
|
|
270
|
+
avgResultRows: bigint("AVG_RESULT_ROWS", { mode: "bigint" }).notNull(), // Avg number of result rows
|
|
271
|
+
|
|
272
|
+
prepared: boolean("PREPARED").notNull(), // Whether statements are prepared
|
|
273
|
+
avgAffectedRows: double("AVG_AFFECTED_ROWS").notNull(), // Avg affected rows
|
|
274
|
+
|
|
275
|
+
firstSeen: timestamp("FIRST_SEEN", { mode: "string" }).notNull(), // First time statements observed
|
|
276
|
+
lastSeen: timestamp("LAST_SEEN", { mode: "string" }).notNull(), // Last time statements observed
|
|
277
|
+
|
|
278
|
+
planInCache: boolean("PLAN_IN_CACHE").notNull(), // Whether last stmt hit plan cache
|
|
279
|
+
planCacheHits: bigint("PLAN_CACHE_HITS", { mode: "bigint" }).notNull(), // Number of plan cache hits
|
|
280
|
+
planInBinding: boolean("PLAN_IN_BINDING").notNull(), // Whether matched bindings
|
|
281
|
+
|
|
282
|
+
querySampleText: text("QUERY_SAMPLE_TEXT"), // Sampled original SQL
|
|
283
|
+
prevSampleText: text("PREV_SAMPLE_TEXT"), // Sampled previous SQL before commit
|
|
284
|
+
|
|
285
|
+
planDigest: varchar("PLAN_DIGEST", { length: 64 }), // Plan digest hash
|
|
286
|
+
plan: text("PLAN"), // Sampled textual plan
|
|
287
|
+
binaryPlan: text("BINARY_PLAN"), // Sampled binary plan
|
|
288
|
+
|
|
289
|
+
charset: varchar("CHARSET", { length: 64 }), // Sampled charset
|
|
290
|
+
collation: varchar("COLLATION", { length: 64 }), // Sampled collation
|
|
291
|
+
planHint: varchar("PLAN_HINT", { length: 64 }), // Sampled plan hint
|
|
292
|
+
|
|
293
|
+
maxRequestUnitRead: double("MAX_REQUEST_UNIT_READ").notNull(), // Max RU cost (read)
|
|
294
|
+
avgRequestUnitRead: double("AVG_REQUEST_UNIT_READ").notNull(), // Avg RU cost (read)
|
|
295
|
+
maxRequestUnitWrite: double("MAX_REQUEST_UNIT_WRITE").notNull(), // Max RU cost (write)
|
|
296
|
+
avgRequestUnitWrite: double("AVG_REQUEST_UNIT_WRITE").notNull(), // Avg RU cost (write)
|
|
297
|
+
|
|
298
|
+
maxQueuedRcTime: bigint("MAX_QUEUED_RC_TIME", { mode: "bigint", unsigned: true }).notNull(), // Max queued time waiting for RU (ns)
|
|
299
|
+
avgQueuedRcTime: bigint("AVG_QUEUED_RC_TIME", { mode: "bigint", unsigned: true }).notNull(), // Avg queued time waiting for RU (ns)
|
|
300
|
+
|
|
301
|
+
resourceGroup: varchar("RESOURCE_GROUP", { length: 64 }), // Bound resource group name
|
|
302
|
+
|
|
303
|
+
planCacheUnqualified: bigint("PLAN_CACHE_UNQUALIFIED", { mode: "bigint" }).notNull(), // Times not eligible for plan cache
|
|
304
|
+
planCacheUnqualifiedLastReason: text("PLAN_CACHE_UNQUALIFIED_LAST_REASON"), // Last reason of plan cache ineligibility
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
export const clusterStatementsSummaryHistory = informationSchema.table(
|
|
308
|
+
"CLUSTER_STATEMENTS_SUMMARY_HISTORY",
|
|
309
|
+
createClusterStatementsSummarySchema(),
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
// Types
|
|
313
|
+
export type ClusterStatementsSummaryHistory = typeof clusterStatementsSummaryHistory.$inferSelect;
|
|
314
|
+
|
|
315
|
+
export const clusterStatementsSummary = informationSchema.table(
|
|
316
|
+
"CLUSTER_STATEMENTS_SUMMARY",
|
|
317
|
+
createClusterStatementsSummarySchema(),
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
// Types
|
|
321
|
+
export type ClusterStatementsSummary = typeof clusterStatementsSummary.$inferSelect;
|
|
322
|
+
|
|
11
323
|
export interface ExplainAnalyzeRow {
|
|
12
324
|
id: string;
|
|
13
325
|
estRows?: string;
|
|
@@ -268,6 +268,7 @@ async function handleSuccessfulExecution(
|
|
|
268
268
|
await evictLocalCacheQuery(table, options);
|
|
269
269
|
if (isCached) {
|
|
270
270
|
await clearCache(table, options).catch((e) => {
|
|
271
|
+
// eslint-disable-next-line no-console
|
|
271
272
|
console.warn("Ignore cache clear errors", e);
|
|
272
273
|
});
|
|
273
274
|
} else {
|
|
@@ -457,6 +458,7 @@ async function handleCachedQuery(
|
|
|
457
458
|
await saveQueryLocalCacheQuery(target, transformed, options);
|
|
458
459
|
await setCacheResult(target, options, transformed, cacheTtl).catch((cacheError) => {
|
|
459
460
|
// Log cache error but don't fail the query
|
|
461
|
+
// eslint-disable-next-line no-console
|
|
460
462
|
console.warn("Cache set error:", cacheError);
|
|
461
463
|
});
|
|
462
464
|
|
|
@@ -102,8 +102,9 @@ export async function saveQueryLocalCacheQuery<
|
|
|
102
102
|
sql: sql.toSQL().sql.toLowerCase(),
|
|
103
103
|
data: rows,
|
|
104
104
|
};
|
|
105
|
-
if (options.
|
|
105
|
+
if (options.logCache) {
|
|
106
106
|
const q = sql.toSQL();
|
|
107
|
+
// eslint-disable-next-line no-console
|
|
107
108
|
console.debug(
|
|
108
109
|
`[forge-sql-orm][local-cache][SAVE] Stored result in cache. sql="${q.sql}", params=${JSON.stringify(q.params)}`,
|
|
109
110
|
);
|
|
@@ -140,8 +141,9 @@ export async function getQueryLocalCacheQuery<
|
|
|
140
141
|
const sql = query as { toSQL: () => Query };
|
|
141
142
|
const key = hashKey(sql.toSQL());
|
|
142
143
|
if (context.cache[key] && context.cache[key].sql === sql.toSQL().sql.toLowerCase()) {
|
|
143
|
-
if (options.
|
|
144
|
+
if (options.logCache) {
|
|
144
145
|
const q = sql.toSQL();
|
|
146
|
+
// eslint-disable-next-line no-console
|
|
145
147
|
console.debug(
|
|
146
148
|
`[forge-sql-orm][local-cache][HIT] Returned cached result. sql="${q.sql}", params=${JSON.stringify(q.params)}`,
|
|
147
149
|
);
|
package/src/utils/cacheUtils.ts
CHANGED
|
@@ -123,7 +123,8 @@ async function clearCursorCache(
|
|
|
123
123
|
|
|
124
124
|
const listResult = await entityQueryBuilder.limit(100).getMany();
|
|
125
125
|
|
|
126
|
-
if (options.
|
|
126
|
+
if (options.logCache) {
|
|
127
|
+
// eslint-disable-next-line no-console
|
|
127
128
|
console.warn(`clear cache Records: ${JSON.stringify(listResult.results.map((r) => r.key))}`);
|
|
128
129
|
}
|
|
129
130
|
|
|
@@ -170,7 +171,8 @@ async function clearExpirationCursorCache(
|
|
|
170
171
|
|
|
171
172
|
const listResult = await entityQueryBuilder.limit(100).getMany();
|
|
172
173
|
|
|
173
|
-
if (options.
|
|
174
|
+
if (options.logCache) {
|
|
175
|
+
// eslint-disable-next-line no-console
|
|
174
176
|
console.warn(`clear expired Records: ${JSON.stringify(listResult.results.map((r) => r.key))}`);
|
|
175
177
|
}
|
|
176
178
|
|
|
@@ -201,10 +203,12 @@ async function executeWithRetry<T>(operation: () => Promise<T>, operationName: s
|
|
|
201
203
|
try {
|
|
202
204
|
return await operation();
|
|
203
205
|
} catch (err: any) {
|
|
206
|
+
// eslint-disable-next-line no-console
|
|
204
207
|
console.warn(`Error during ${operationName}: ${err.message}, retry ${attempt}`, err);
|
|
205
208
|
attempt++;
|
|
206
209
|
|
|
207
210
|
if (attempt >= CACHE_CONSTANTS.MAX_RETRY_ATTEMPTS) {
|
|
211
|
+
// eslint-disable-next-line no-console
|
|
208
212
|
console.error(`Error during ${operationName}: ${err.message}`, err);
|
|
209
213
|
throw err;
|
|
210
214
|
}
|
|
@@ -260,8 +264,9 @@ export async function clearTablesCache(
|
|
|
260
264
|
"clearing cache",
|
|
261
265
|
);
|
|
262
266
|
} finally {
|
|
263
|
-
if (options.
|
|
267
|
+
if (options.logCache) {
|
|
264
268
|
const duration = DateTime.now().toSeconds() - startTime.toSeconds();
|
|
269
|
+
// eslint-disable-next-line no-console
|
|
265
270
|
console.info(`Cleared ${totalRecords} cache records in ${duration} seconds`);
|
|
266
271
|
}
|
|
267
272
|
}
|
|
@@ -287,7 +292,8 @@ export async function clearExpiredCache(options: ForgeSqlOrmOptions): Promise<vo
|
|
|
287
292
|
);
|
|
288
293
|
} finally {
|
|
289
294
|
const duration = DateTime.now().toSeconds() - startTime.toSeconds();
|
|
290
|
-
if (options?.
|
|
295
|
+
if (options?.logCache) {
|
|
296
|
+
// eslint-disable-next-line no-console
|
|
291
297
|
console.debug(`Cleared ${totalRecords} expired cache records in ${duration} seconds`);
|
|
292
298
|
}
|
|
293
299
|
}
|
|
@@ -318,7 +324,8 @@ export async function getFromCache<T>(
|
|
|
318
324
|
|
|
319
325
|
// Skip cache if table is in cache context (will be cleared)
|
|
320
326
|
if (await isTableContainsTableInCacheContext(sqlQuery.sql, options)) {
|
|
321
|
-
if (options.
|
|
327
|
+
if (options.logCache) {
|
|
328
|
+
// eslint-disable-next-line no-console
|
|
322
329
|
console.warn(`Context contains value to clear. Skip getting from cache`);
|
|
323
330
|
}
|
|
324
331
|
return undefined;
|
|
@@ -332,13 +339,15 @@ export async function getFromCache<T>(
|
|
|
332
339
|
(cacheResult[expirationName] as number) >= getCurrentTime() &&
|
|
333
340
|
sqlQuery.sql.toLowerCase() === cacheResult[entityQueryName]
|
|
334
341
|
) {
|
|
335
|
-
if (options.
|
|
342
|
+
if (options.logCache) {
|
|
343
|
+
// eslint-disable-next-line no-console
|
|
336
344
|
console.warn(`Get value from cache, cacheKey: ${key}`);
|
|
337
345
|
}
|
|
338
346
|
const results = cacheResult[dataName];
|
|
339
347
|
return JSON.parse(results as string);
|
|
340
348
|
}
|
|
341
349
|
} catch (error: any) {
|
|
350
|
+
// eslint-disable-next-line no-console
|
|
342
351
|
console.error(`Error getting from cache: ${error.message}`, error);
|
|
343
352
|
}
|
|
344
353
|
|
|
@@ -375,7 +384,8 @@ export async function setCacheResult(
|
|
|
375
384
|
|
|
376
385
|
// Skip cache if table is in cache context (will be cleared)
|
|
377
386
|
if (await isTableContainsTableInCacheContext(sqlQuery.sql, options)) {
|
|
378
|
-
if (options.
|
|
387
|
+
if (options.logCache) {
|
|
388
|
+
// eslint-disable-next-line no-console
|
|
379
389
|
console.warn(`Context contains value to clear. Skip setting from cache`);
|
|
380
390
|
}
|
|
381
391
|
return;
|
|
@@ -396,10 +406,12 @@ export async function setCacheResult(
|
|
|
396
406
|
)
|
|
397
407
|
.execute();
|
|
398
408
|
|
|
399
|
-
if (options.
|
|
409
|
+
if (options.logCache) {
|
|
410
|
+
// eslint-disable-next-line no-console
|
|
400
411
|
console.warn(`Store value to cache, cacheKey: ${key}`);
|
|
401
412
|
}
|
|
402
413
|
} catch (error: any) {
|
|
414
|
+
// eslint-disable-next-line no-console
|
|
403
415
|
console.error(`Error setting cache: ${error.message}`, error);
|
|
404
416
|
}
|
|
405
417
|
}
|
package/src/utils/forgeDriver.ts
CHANGED
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
import { sql, UpdateQueryResponse } from "@forge/sql";
|
|
2
|
+
import {saveMetaDataInContextContext} from "./metadataContextUtils";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
export type ForgeSQLMetadata = {
|
|
5
|
+
dbExecutionTime: number,
|
|
6
|
+
responseSize: number,
|
|
7
|
+
fields: {
|
|
8
|
+
"catalog": string,
|
|
9
|
+
"name": string,
|
|
10
|
+
"schema": string,
|
|
11
|
+
"characterSet": number,
|
|
12
|
+
"decimals": number,
|
|
13
|
+
"table": string,
|
|
14
|
+
"orgTable": string,
|
|
15
|
+
"orgName": string,
|
|
16
|
+
"flags": number,
|
|
17
|
+
"columnType": number,
|
|
18
|
+
"columnLength": number
|
|
19
|
+
}[]
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export interface ForgeSQLResult {
|
|
4
23
|
rows: Record<string, unknown>[] | Record<string, unknown>;
|
|
24
|
+
metadata: ForgeSQLMetadata
|
|
5
25
|
}
|
|
6
26
|
|
|
7
27
|
export const forgeDriver = async (
|
|
@@ -27,6 +47,7 @@ export const forgeDriver = async (
|
|
|
27
47
|
await sqlStatement.bindParams(...params);
|
|
28
48
|
}
|
|
29
49
|
const result = (await sqlStatement.execute()) as ForgeSQLResult;
|
|
50
|
+
await saveMetaDataInContextContext(result.metadata)
|
|
30
51
|
let rows;
|
|
31
52
|
rows = (result.rows as any[]).map((r) => Object.values(r as Record<string, unknown>));
|
|
32
53
|
return { rows: rows };
|
|
@@ -19,6 +19,7 @@ export function createForgeDriverProxy(options?: SqlHints, logRawSqlQuery?: bool
|
|
|
19
19
|
const modifiedQuery = injectSqlHints(query, options);
|
|
20
20
|
|
|
21
21
|
if (options && logRawSqlQuery && modifiedQuery !== query) {
|
|
22
|
+
// eslint-disable-next-line no-console
|
|
22
23
|
console.debug("injected Hints: " + modifiedQuery);
|
|
23
24
|
}
|
|
24
25
|
try {
|
|
@@ -26,6 +27,7 @@ export function createForgeDriverProxy(options?: SqlHints, logRawSqlQuery?: bool
|
|
|
26
27
|
return await forgeDriver(modifiedQuery, params, method);
|
|
27
28
|
} catch (error) {
|
|
28
29
|
if (logRawSqlQuery) {
|
|
30
|
+
// eslint-disable-next-line no-console
|
|
29
31
|
console.debug("SQL Error:", JSON.stringify(error));
|
|
30
32
|
}
|
|
31
33
|
throw error;
|