forge-sql-orm 2.0.17 → 2.0.19
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 +95 -4
- package/dist/ForgeSQLORM.js +382 -60
- package/dist/ForgeSQLORM.js.map +1 -1
- package/dist/ForgeSQLORM.mjs +382 -60
- package/dist/ForgeSQLORM.mjs.map +1 -1
- package/dist/core/ForgeSQLAnalyseOperations.d.ts +250 -0
- package/dist/core/ForgeSQLAnalyseOperations.d.ts.map +1 -0
- package/dist/core/ForgeSQLCrudOperations.d.ts +1 -1
- package/dist/core/ForgeSQLCrudOperations.d.ts.map +1 -1
- package/dist/core/ForgeSQLORM.d.ts +12 -2
- package/dist/core/ForgeSQLORM.d.ts.map +1 -1
- package/dist/core/ForgeSQLQueryBuilder.d.ts +112 -21
- package/dist/core/ForgeSQLQueryBuilder.d.ts.map +1 -1
- package/dist/core/ForgeSQLSelectOperations.d.ts.map +1 -1
- package/dist/core/SystemTables.d.ts +167 -0
- package/dist/core/SystemTables.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/utils/forgeDriverProxy.d.ts +11 -0
- package/dist/utils/forgeDriverProxy.d.ts.map +1 -0
- package/dist/utils/sqlHints.d.ts +21 -0
- package/dist/utils/sqlHints.d.ts.map +1 -0
- package/dist/utils/sqlUtils.d.ts +2 -8
- package/dist/utils/sqlUtils.d.ts.map +1 -1
- package/dist/webtriggers/applyMigrationsWebTrigger.d.ts.map +1 -1
- package/dist/webtriggers/dropMigrationWebTrigger.d.ts +2 -4
- package/dist/webtriggers/dropMigrationWebTrigger.d.ts.map +1 -1
- package/package.json +4 -12
- package/src/core/ForgeSQLAnalyseOperations.ts +461 -0
- package/src/core/ForgeSQLCrudOperations.ts +15 -8
- package/src/core/ForgeSQLORM.ts +46 -9
- package/src/core/ForgeSQLQueryBuilder.ts +129 -32
- package/src/core/ForgeSQLSelectOperations.ts +4 -6
- package/src/core/SystemTables.ts +175 -0
- package/src/index.ts +1 -0
- package/src/utils/forgeDriverProxy.ts +27 -0
- package/src/utils/sqlHints.ts +63 -0
- package/src/utils/sqlUtils.ts +36 -32
- package/src/webtriggers/applyMigrationsWebTrigger.ts +32 -16
- package/src/webtriggers/dropMigrationWebTrigger.ts +5 -6
- package/src/webtriggers/fetchSchemaWebTrigger.ts +2 -10
|
@@ -10,39 +10,61 @@ import {
|
|
|
10
10
|
MySqlSelectDynamic,
|
|
11
11
|
type SelectedFields,
|
|
12
12
|
} from "drizzle-orm/mysql-core/query-builders/select.types";
|
|
13
|
-
import { InferInsertModel, SQL } from "drizzle-orm";
|
|
13
|
+
import { InferInsertModel, Query, SQL } from "drizzle-orm";
|
|
14
14
|
import moment from "moment/moment";
|
|
15
15
|
import { parseDateTime } from "../utils/sqlUtils";
|
|
16
16
|
import { MySqlRemoteDatabase, MySqlRemotePreparedQueryHKT } from "drizzle-orm/mysql-proxy/index";
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
import { SqlHints } from "../utils/sqlHints";
|
|
18
|
+
import {
|
|
19
|
+
ClusterStatementRowCamelCase,
|
|
20
|
+
ExplainAnalyzeRow,
|
|
21
|
+
SlowQueryNormalized,
|
|
22
|
+
} from "./SystemTables";
|
|
19
23
|
|
|
20
24
|
/**
|
|
21
|
-
*
|
|
22
|
-
* Provides access to CRUD operations
|
|
25
|
+
* Core interface for ForgeSQL operations.
|
|
26
|
+
* Provides access to CRUD operations, schema-level SQL operations, and query analysis capabilities.
|
|
27
|
+
*
|
|
28
|
+
* @interface ForgeSqlOperation
|
|
29
|
+
* @extends {QueryBuilderForgeSql}
|
|
23
30
|
*/
|
|
24
31
|
export interface ForgeSqlOperation extends QueryBuilderForgeSql {
|
|
25
32
|
/**
|
|
26
|
-
* Provides CRUD (Create,
|
|
33
|
+
* Provides CRUD (Create, Update, Delete) operations.
|
|
34
|
+
* @deprecated Use modify() instead for better type safety and consistency
|
|
27
35
|
* @returns {CRUDForgeSQL} Interface for performing CRUD operations
|
|
28
36
|
*/
|
|
29
37
|
crud(): CRUDForgeSQL;
|
|
30
38
|
|
|
31
39
|
/**
|
|
32
|
-
* Provides
|
|
40
|
+
* Provides modify (Create, Update, Delete) operations with optimistic locking support.
|
|
41
|
+
* @returns {CRUDForgeSQL} Interface for performing CRUD operations
|
|
42
|
+
*/
|
|
43
|
+
modify(): CRUDForgeSQL;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Provides schema-level SQL fetch operations with type safety.
|
|
33
47
|
* @returns {SchemaSqlForgeSql} Interface for executing schema-bound SQL queries
|
|
34
48
|
*/
|
|
35
49
|
fetch(): SchemaSqlForgeSql;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Provides query analysis capabilities including EXPLAIN ANALYZE and slow query analysis.
|
|
53
|
+
* @returns {SchemaAnalyzeForgeSql} Interface for analyzing query performance
|
|
54
|
+
*/
|
|
55
|
+
analyze(): SchemaAnalyzeForgeSql;
|
|
36
56
|
}
|
|
37
57
|
|
|
38
58
|
/**
|
|
39
59
|
* Interface for Query Builder operations.
|
|
40
|
-
* Provides access to the underlying Drizzle ORM query builder.
|
|
60
|
+
* Provides access to the underlying Drizzle ORM query builder with enhanced functionality.
|
|
61
|
+
*
|
|
62
|
+
* @interface QueryBuilderForgeSql
|
|
41
63
|
*/
|
|
42
64
|
export interface QueryBuilderForgeSql {
|
|
43
65
|
/**
|
|
44
66
|
* Creates a new query builder for the given entity.
|
|
45
|
-
* @returns {
|
|
67
|
+
* @returns {MySqlRemoteDatabase<Record<string, unknown>>} The Drizzle database instance for building queries
|
|
46
68
|
*/
|
|
47
69
|
getDrizzleQueryBuilder(): MySqlRemoteDatabase<Record<string, unknown>>;
|
|
48
70
|
|
|
@@ -87,25 +109,25 @@ export interface QueryBuilderForgeSql {
|
|
|
87
109
|
): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
|
|
88
110
|
}
|
|
89
111
|
|
|
90
|
-
// ============= CRUD Operations =============
|
|
91
|
-
|
|
92
112
|
/**
|
|
93
|
-
* Interface for
|
|
113
|
+
* Interface for Modify (Create, Update, Delete) operations.
|
|
94
114
|
* Provides methods for basic database operations with support for optimistic locking.
|
|
115
|
+
*
|
|
116
|
+
* @interface CRUDForgeSQL
|
|
95
117
|
*/
|
|
96
118
|
export interface CRUDForgeSQL {
|
|
97
119
|
/**
|
|
98
120
|
* Inserts multiple records into the database.
|
|
99
121
|
* @template T - The type of the table schema
|
|
100
122
|
* @param {T} schema - The entity schema
|
|
101
|
-
* @param {
|
|
123
|
+
* @param {InferInsertModel<T>[]} models - The list of entities to insert
|
|
102
124
|
* @param {boolean} [updateIfExists] - Whether to update the row if it already exists (default: false)
|
|
103
125
|
* @returns {Promise<number>} The number of inserted rows
|
|
104
126
|
* @throws {Error} If the insert operation fails
|
|
105
127
|
*/
|
|
106
128
|
insert<T extends AnyMySqlTable>(
|
|
107
129
|
schema: T,
|
|
108
|
-
models:
|
|
130
|
+
models: InferInsertModel<T>[],
|
|
109
131
|
updateIfExists?: boolean,
|
|
110
132
|
): Promise<number>;
|
|
111
133
|
|
|
@@ -158,11 +180,81 @@ export interface CRUDForgeSQL {
|
|
|
158
180
|
): Promise<number>;
|
|
159
181
|
}
|
|
160
182
|
|
|
161
|
-
|
|
183
|
+
/**
|
|
184
|
+
* Interface for schema analysis operations.
|
|
185
|
+
* Provides methods for analyzing query performance and execution plans.
|
|
186
|
+
*
|
|
187
|
+
* @interface SchemaAnalyzeForgeSql
|
|
188
|
+
*/
|
|
189
|
+
export interface SchemaAnalyzeForgeSql {
|
|
190
|
+
/**
|
|
191
|
+
* Executes EXPLAIN on a Drizzle query.
|
|
192
|
+
* @param {{ toSQL: () => Query }} query - The Drizzle query to analyze
|
|
193
|
+
* @returns {Promise<ExplainAnalyzeRow[]>} The execution plan analysis results
|
|
194
|
+
*/
|
|
195
|
+
explain(query: { toSQL: () => Query }): Promise<ExplainAnalyzeRow[]>;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Executes EXPLAIN on a raw SQL query.
|
|
199
|
+
* @param {string} query - The SQL query to analyze
|
|
200
|
+
* @param {unknown[]} bindParams - The query parameters
|
|
201
|
+
* @returns {Promise<ExplainAnalyzeRow[]>} The execution plan analysis results
|
|
202
|
+
*/
|
|
203
|
+
explainRaw(query: string, bindParams: unknown[]): Promise<ExplainAnalyzeRow[]>;
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Executes EXPLAIN ANALYZE on a Drizzle query.
|
|
207
|
+
* @param {{ toSQL: () => Query }} query - The Drizzle query to analyze
|
|
208
|
+
* @returns {Promise<ExplainAnalyzeRow[]>} The execution plan analysis results
|
|
209
|
+
*/
|
|
210
|
+
explainAnalyze(query: { toSQL: () => Query }): Promise<ExplainAnalyzeRow[]>;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Executes EXPLAIN ANALYZE on a raw SQL query.
|
|
214
|
+
* @param {string} query - The SQL query to analyze
|
|
215
|
+
* @param {unknown[]} bindParams - The query parameters
|
|
216
|
+
* @returns {Promise<ExplainAnalyzeRow[]>} The execution plan analysis results
|
|
217
|
+
*/
|
|
218
|
+
explainAnalyzeRaw(query: string, bindParams: unknown[]): Promise<ExplainAnalyzeRow[]>;
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Analyzes slow queries from the database.
|
|
222
|
+
* @returns {Promise<SlowQueryNormalized[]>} The normalized slow query data
|
|
223
|
+
*/
|
|
224
|
+
analyzeSlowQueries(): Promise<SlowQueryNormalized[]>;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Analyzes query history for specific tables using Drizzle table objects.
|
|
228
|
+
* @param {AnyMySqlTable[]} tables - The Drizzle table objects to analyze
|
|
229
|
+
* @param {Date} [fromDate] - The start date for the analysis
|
|
230
|
+
* @param {Date} [toDate] - The end date for the analysis
|
|
231
|
+
* @returns {Promise<ClusterStatementRowCamelCase[]>} The analyzed query history
|
|
232
|
+
*/
|
|
233
|
+
analyzeQueriesHistory(
|
|
234
|
+
tables: AnyMySqlTable[],
|
|
235
|
+
fromDate?: Date,
|
|
236
|
+
toDate?: Date,
|
|
237
|
+
): Promise<ClusterStatementRowCamelCase[]>;
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Analyzes query history for specific tables using raw table names.
|
|
241
|
+
* @param {string[]} tables - The table names to analyze
|
|
242
|
+
* @param {Date} [fromDate] - The start date for the analysis
|
|
243
|
+
* @param {Date} [toDate] - The end date for the analysis
|
|
244
|
+
* @returns {Promise<ClusterStatementRowCamelCase[]>} The analyzed query history
|
|
245
|
+
*/
|
|
246
|
+
analyzeQueriesHistoryRaw(
|
|
247
|
+
tables: string[],
|
|
248
|
+
fromDate?: Date,
|
|
249
|
+
toDate?: Date,
|
|
250
|
+
): Promise<ClusterStatementRowCamelCase[]>;
|
|
251
|
+
}
|
|
162
252
|
|
|
163
253
|
/**
|
|
164
254
|
* Interface for schema-level SQL operations.
|
|
165
255
|
* Provides methods for executing SQL queries with schema binding and type safety.
|
|
256
|
+
*
|
|
257
|
+
* @interface SchemaSqlForgeSql
|
|
166
258
|
*/
|
|
167
259
|
export interface SchemaSqlForgeSql {
|
|
168
260
|
/**
|
|
@@ -199,11 +291,11 @@ export interface SchemaSqlForgeSql {
|
|
|
199
291
|
executeRawUpdateSQL(query: string, params?: unknown[]): Promise<UpdateQueryResponse>;
|
|
200
292
|
}
|
|
201
293
|
|
|
202
|
-
// ============= Configuration Types =============
|
|
203
|
-
|
|
204
294
|
/**
|
|
205
295
|
* Interface for version field metadata.
|
|
206
296
|
* Defines the configuration for optimistic locking version fields.
|
|
297
|
+
*
|
|
298
|
+
* @interface VersionFieldMetadata
|
|
207
299
|
*/
|
|
208
300
|
export interface VersionFieldMetadata {
|
|
209
301
|
/** Name of the version field */
|
|
@@ -213,6 +305,8 @@ export interface VersionFieldMetadata {
|
|
|
213
305
|
/**
|
|
214
306
|
* Interface for table metadata.
|
|
215
307
|
* Defines the configuration for a specific table.
|
|
308
|
+
*
|
|
309
|
+
* @interface TableMetadata
|
|
216
310
|
*/
|
|
217
311
|
export interface TableMetadata {
|
|
218
312
|
/** Name of the table */
|
|
@@ -224,26 +318,23 @@ export interface TableMetadata {
|
|
|
224
318
|
/**
|
|
225
319
|
* Type for additional metadata configuration.
|
|
226
320
|
* Maps table names to their metadata configuration.
|
|
321
|
+
*
|
|
322
|
+
* @type {AdditionalMetadata}
|
|
227
323
|
*/
|
|
228
324
|
export type AdditionalMetadata = Record<string, TableMetadata>;
|
|
229
325
|
|
|
230
326
|
/**
|
|
231
|
-
*
|
|
327
|
+
* Interface for ForgeSQL ORM options
|
|
328
|
+
*
|
|
329
|
+
* @interface ForgeSqlOrmOptions
|
|
232
330
|
*/
|
|
233
331
|
export interface ForgeSqlOrmOptions {
|
|
234
|
-
/**
|
|
235
|
-
* Enables logging of raw SQL queries in the Atlassian Forge Developer Console.
|
|
236
|
-
* Useful for debugging and monitoring SQL operations.
|
|
237
|
-
* @default false
|
|
238
|
-
*/
|
|
332
|
+
/** Whether to log raw SQL queries */
|
|
239
333
|
logRawSqlQuery?: boolean;
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Disables optimistic locking for all operations.
|
|
243
|
-
* When enabled, version checks are skipped during updates.
|
|
244
|
-
* @default false
|
|
245
|
-
*/
|
|
334
|
+
/** Whether to disable optimistic locking */
|
|
246
335
|
disableOptimisticLocking?: boolean;
|
|
336
|
+
/** SQL hints to be applied to queries */
|
|
337
|
+
hints?: SqlHints;
|
|
247
338
|
|
|
248
339
|
/**
|
|
249
340
|
* Additional metadata for table configuration.
|
|
@@ -265,11 +356,11 @@ export interface ForgeSqlOrmOptions {
|
|
|
265
356
|
additionalMetadata?: AdditionalMetadata;
|
|
266
357
|
}
|
|
267
358
|
|
|
268
|
-
// ============= Custom Types =============
|
|
269
|
-
|
|
270
359
|
/**
|
|
271
360
|
* Custom type for MySQL datetime fields.
|
|
272
361
|
* Handles conversion between JavaScript Date objects and MySQL datetime strings.
|
|
362
|
+
*
|
|
363
|
+
* @type {CustomType}
|
|
273
364
|
*/
|
|
274
365
|
export const forgeDateTimeString = customType<{
|
|
275
366
|
data: Date;
|
|
@@ -291,6 +382,8 @@ export const forgeDateTimeString = customType<{
|
|
|
291
382
|
/**
|
|
292
383
|
* Custom type for MySQL timestamp fields.
|
|
293
384
|
* Handles conversion between JavaScript Date objects and MySQL timestamp strings.
|
|
385
|
+
*
|
|
386
|
+
* @type {CustomType}
|
|
294
387
|
*/
|
|
295
388
|
export const forgeTimestampString = customType<{
|
|
296
389
|
data: Date;
|
|
@@ -301,7 +394,7 @@ export const forgeTimestampString = customType<{
|
|
|
301
394
|
return "timestamp";
|
|
302
395
|
},
|
|
303
396
|
toDriver(value: Date) {
|
|
304
|
-
return moment(
|
|
397
|
+
return moment(new Date(value)).format("YYYY-MM-DDTHH:mm:ss.SSS");
|
|
305
398
|
},
|
|
306
399
|
fromDriver(value: unknown) {
|
|
307
400
|
const format = "YYYY-MM-DDTHH:mm:ss.SSS";
|
|
@@ -312,6 +405,8 @@ export const forgeTimestampString = customType<{
|
|
|
312
405
|
/**
|
|
313
406
|
* Custom type for MySQL date fields.
|
|
314
407
|
* Handles conversion between JavaScript Date objects and MySQL date strings.
|
|
408
|
+
*
|
|
409
|
+
* @type {CustomType}
|
|
315
410
|
*/
|
|
316
411
|
export const forgeDateString = customType<{
|
|
317
412
|
data: Date;
|
|
@@ -333,6 +428,8 @@ export const forgeDateString = customType<{
|
|
|
333
428
|
/**
|
|
334
429
|
* Custom type for MySQL time fields.
|
|
335
430
|
* Handles conversion between JavaScript Date objects and MySQL time strings.
|
|
431
|
+
*
|
|
432
|
+
* @type {CustomType}
|
|
336
433
|
*/
|
|
337
434
|
export const forgeTimeString = customType<{
|
|
338
435
|
data: Date;
|
|
@@ -57,9 +57,8 @@ export class ForgeSQLSelectOperations implements SchemaSqlForgeSql {
|
|
|
57
57
|
*/
|
|
58
58
|
async executeRawSQL<T extends object | unknown>(query: string, params?: unknown[]): Promise<T[]> {
|
|
59
59
|
if (this.options.logRawSqlQuery) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
);
|
|
60
|
+
const paramsStr = params ? `, with params: ${JSON.stringify(params)}` : "";
|
|
61
|
+
console.debug(`Executing with SQL ${query}${paramsStr}`);
|
|
63
62
|
}
|
|
64
63
|
const sqlStatement = sql.prepare<T>(query);
|
|
65
64
|
if (params) {
|
|
@@ -82,9 +81,8 @@ export class ForgeSQLSelectOperations implements SchemaSqlForgeSql {
|
|
|
82
81
|
}
|
|
83
82
|
if (this.options.logRawSqlQuery) {
|
|
84
83
|
console.debug(
|
|
85
|
-
`Executing Update with SQL ${query}` +
|
|
86
|
-
? `, with params: ${JSON.stringify(params)}`
|
|
87
|
-
: "",
|
|
84
|
+
`Executing Update with SQL ${query}` +
|
|
85
|
+
(params ? `, with params: ${JSON.stringify(params)}` : ""),
|
|
88
86
|
);
|
|
89
87
|
}
|
|
90
88
|
const updateQueryResponseResults = await sqlStatement.execute();
|
package/src/core/SystemTables.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { bigint, mysqlTable, timestamp, varchar } from "drizzle-orm/mysql-core";
|
|
2
2
|
import { Table } from "drizzle-orm";
|
|
3
|
+
import { sql } from "@forge/sql";
|
|
3
4
|
|
|
4
5
|
export const migrations = mysqlTable("__migrations", {
|
|
5
6
|
id: bigint("id", { mode: "number" }).primaryKey().autoincrement(),
|
|
@@ -7,4 +8,178 @@ export const migrations = mysqlTable("__migrations", {
|
|
|
7
8
|
migratedAt: timestamp("migratedAt").defaultNow().notNull(),
|
|
8
9
|
});
|
|
9
10
|
|
|
11
|
+
export interface ExplainAnalyzeRow {
|
|
12
|
+
id: string;
|
|
13
|
+
estRows?: string;
|
|
14
|
+
estCost?: string;
|
|
15
|
+
actRows?: string;
|
|
16
|
+
task?: string;
|
|
17
|
+
accessObject?: string;
|
|
18
|
+
executionInfo?: string;
|
|
19
|
+
operatorInfo?: string;
|
|
20
|
+
memory?: string;
|
|
21
|
+
disk?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface SlowQueryNormalized {
|
|
25
|
+
time: string;
|
|
26
|
+
txnStartTs: number;
|
|
27
|
+
user: string;
|
|
28
|
+
host: string;
|
|
29
|
+
connId: number;
|
|
30
|
+
db: string;
|
|
31
|
+
query: string;
|
|
32
|
+
digest: string;
|
|
33
|
+
queryTime: number;
|
|
34
|
+
compileTime: number;
|
|
35
|
+
optimizeTime: number;
|
|
36
|
+
processTime: number;
|
|
37
|
+
waitTime: number;
|
|
38
|
+
parseTime: number;
|
|
39
|
+
rewriteTime: number;
|
|
40
|
+
copTime: number;
|
|
41
|
+
copProcAvg: number;
|
|
42
|
+
copProcMax: number;
|
|
43
|
+
copProcP90: number;
|
|
44
|
+
copProcAddr: string;
|
|
45
|
+
copWaitAvg: number;
|
|
46
|
+
copWaitMax: number;
|
|
47
|
+
copWaitP90: number;
|
|
48
|
+
copWaitAddr: string;
|
|
49
|
+
memMax: number;
|
|
50
|
+
diskMax: number;
|
|
51
|
+
totalKeys: number;
|
|
52
|
+
processKeys: number;
|
|
53
|
+
requestCount: number;
|
|
54
|
+
kvTotal: number;
|
|
55
|
+
pdTotal: number;
|
|
56
|
+
resultRows: number;
|
|
57
|
+
rocksdbBlockCacheHitCount: number;
|
|
58
|
+
rocksdbBlockReadCount: number;
|
|
59
|
+
rocksdbBlockReadByte: number;
|
|
60
|
+
plan: string;
|
|
61
|
+
parsedPlan?: ExplainAnalyzeRow[];
|
|
62
|
+
binaryPlan: string;
|
|
63
|
+
planDigest: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface ClusterStatementRowCamelCase {
|
|
67
|
+
instance: string;
|
|
68
|
+
summaryBeginTime: string;
|
|
69
|
+
summaryEndTime: string;
|
|
70
|
+
stmtType: string;
|
|
71
|
+
schemaName: string;
|
|
72
|
+
digest: string;
|
|
73
|
+
digestText: string;
|
|
74
|
+
tableNames: string;
|
|
75
|
+
indexNames: string | null;
|
|
76
|
+
sampleUser: string;
|
|
77
|
+
execCount: number;
|
|
78
|
+
sumErrors: number;
|
|
79
|
+
sumWarnings: number;
|
|
80
|
+
sumLatency: number;
|
|
81
|
+
maxLatency: number;
|
|
82
|
+
minLatency: number;
|
|
83
|
+
avgLatency: number;
|
|
84
|
+
avgParseLatency: number;
|
|
85
|
+
maxParseLatency: number;
|
|
86
|
+
avgCompileLatency: number;
|
|
87
|
+
maxCompileLatency: number;
|
|
88
|
+
sumCopTaskNum: number;
|
|
89
|
+
maxCopProcessTime: number;
|
|
90
|
+
maxCopProcessAddress: string;
|
|
91
|
+
maxCopWaitTime: number;
|
|
92
|
+
maxCopWaitAddress: string;
|
|
93
|
+
avgProcessTime: number;
|
|
94
|
+
maxProcessTime: number;
|
|
95
|
+
avgWaitTime: number;
|
|
96
|
+
maxWaitTime: number;
|
|
97
|
+
avgBackoffTime: number;
|
|
98
|
+
maxBackoffTime: number;
|
|
99
|
+
avgTotalKeys: number;
|
|
100
|
+
maxTotalKeys: number;
|
|
101
|
+
avgProcessedKeys: number;
|
|
102
|
+
maxProcessedKeys: number;
|
|
103
|
+
avgRocksdbDeleteSkippedCount: number;
|
|
104
|
+
maxRocksdbDeleteSkippedCount: number;
|
|
105
|
+
avgRocksdbKeySkippedCount: number;
|
|
106
|
+
maxRocksdbKeySkippedCount: number;
|
|
107
|
+
avgRocksdbBlockCacheHitCount: number;
|
|
108
|
+
maxRocksdbBlockCacheHitCount: number;
|
|
109
|
+
avgRocksdbBlockReadCount: number;
|
|
110
|
+
maxRocksdbBlockReadCount: number;
|
|
111
|
+
avgRocksdbBlockReadByte: number;
|
|
112
|
+
maxRocksdbBlockReadByte: number;
|
|
113
|
+
avgPrewriteTime: number;
|
|
114
|
+
maxPrewriteTime: number;
|
|
115
|
+
avgCommitTime: number;
|
|
116
|
+
maxCommitTime: number;
|
|
117
|
+
avgGetCommitTsTime: number;
|
|
118
|
+
maxGetCommitTsTime: number;
|
|
119
|
+
avgCommitBackoffTime: number;
|
|
120
|
+
maxCommitBackoffTime: number;
|
|
121
|
+
avgResolveLockTime: number;
|
|
122
|
+
maxResolveLockTime: number;
|
|
123
|
+
avgLocalLatchWaitTime: number;
|
|
124
|
+
maxLocalLatchWaitTime: number;
|
|
125
|
+
avgWriteKeys: number;
|
|
126
|
+
maxWriteKeys: number;
|
|
127
|
+
avgWriteSize: number;
|
|
128
|
+
maxWriteSize: number;
|
|
129
|
+
avgPrewriteRegions: number;
|
|
130
|
+
maxPrewriteRegions: number;
|
|
131
|
+
avgTxnRetry: number;
|
|
132
|
+
maxTxnRetry: number;
|
|
133
|
+
sumExecRetry: number;
|
|
134
|
+
sumExecRetryTime: number;
|
|
135
|
+
sumBackoffTimes: number;
|
|
136
|
+
backoffTypes: string | null;
|
|
137
|
+
avgMem: number;
|
|
138
|
+
maxMem: number;
|
|
139
|
+
avgDisk: number;
|
|
140
|
+
maxDisk: number;
|
|
141
|
+
avgKvTime: number;
|
|
142
|
+
avgPdTime: number;
|
|
143
|
+
avgBackoffTotalTime: number;
|
|
144
|
+
avgWriteSqlRespTime: number;
|
|
145
|
+
avgTidbCpuTime: number;
|
|
146
|
+
avgTikvCpuTime: number;
|
|
147
|
+
maxResultRows: number;
|
|
148
|
+
minResultRows: number;
|
|
149
|
+
avgResultRows: number;
|
|
150
|
+
prepared: number;
|
|
151
|
+
avgAffectedRows: number;
|
|
152
|
+
firstSeen: string;
|
|
153
|
+
lastSeen: string;
|
|
154
|
+
planInCache: number;
|
|
155
|
+
planCacheHits: number;
|
|
156
|
+
planInBinding: number;
|
|
157
|
+
querySampleText: string;
|
|
158
|
+
prevSampleText: string;
|
|
159
|
+
planDigest: string;
|
|
160
|
+
plan: string;
|
|
161
|
+
binaryPlan: string;
|
|
162
|
+
charset: string;
|
|
163
|
+
collation: string;
|
|
164
|
+
planHint: string;
|
|
165
|
+
maxRequestUnitRead: number;
|
|
166
|
+
avgRequestUnitRead: number;
|
|
167
|
+
maxRequestUnitWrite: number;
|
|
168
|
+
avgRequestUnitWrite: number;
|
|
169
|
+
maxQueuedRcTime: number;
|
|
170
|
+
avgQueuedRcTime: number;
|
|
171
|
+
resourceGroup: string;
|
|
172
|
+
planCacheUnqualified: number;
|
|
173
|
+
planCacheUnqualifiedLastReason: string;
|
|
174
|
+
parsedPlan?: ExplainAnalyzeRow[];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Retrieves all tables from the database
|
|
179
|
+
*/
|
|
180
|
+
export async function getTables(): Promise<string[]> {
|
|
181
|
+
const tables = await sql.executeDDL<string>("SHOW TABLES");
|
|
182
|
+
return tables.rows.flatMap((tableInfo) => Object.values(tableInfo));
|
|
183
|
+
}
|
|
184
|
+
|
|
10
185
|
export const forgeSystemTables: Table[] = [migrations];
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { forgeDriver } from "./forgeDriver";
|
|
2
|
+
import { injectSqlHints, SqlHints } from "./sqlHints";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a proxy for the forgeDriver that injects SQL hints
|
|
6
|
+
* @returns A proxied version of the forgeDriver
|
|
7
|
+
*/
|
|
8
|
+
export function createForgeDriverProxy(options?: SqlHints, logRawSqlQuery?: boolean) {
|
|
9
|
+
return async (
|
|
10
|
+
query: string,
|
|
11
|
+
params: any[],
|
|
12
|
+
method: "all" | "execute",
|
|
13
|
+
): Promise<{
|
|
14
|
+
rows: any[];
|
|
15
|
+
insertId?: number;
|
|
16
|
+
affectedRows?: number;
|
|
17
|
+
}> => {
|
|
18
|
+
// Inject SQL hints into the query
|
|
19
|
+
const modifiedQuery = injectSqlHints(query, options);
|
|
20
|
+
|
|
21
|
+
if (options && logRawSqlQuery && modifiedQuery !== query) {
|
|
22
|
+
console.warn("modified query: " + modifiedQuery);
|
|
23
|
+
}
|
|
24
|
+
// Call the original forgeDriver with the modified query
|
|
25
|
+
return forgeDriver(modifiedQuery, params, method);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface for SQL hints configuration
|
|
3
|
+
*/
|
|
4
|
+
export interface SqlHints {
|
|
5
|
+
/** SQL hints for SELECT queries */
|
|
6
|
+
select?: string[];
|
|
7
|
+
/** SQL hints for INSERT queries */
|
|
8
|
+
insert?: string[];
|
|
9
|
+
/** SQL hints for UPDATE queries */
|
|
10
|
+
update?: string[];
|
|
11
|
+
/** SQL hints for DELETE queries */
|
|
12
|
+
delete?: string[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Detects the type of SQL query and injects appropriate hints
|
|
17
|
+
* @param query - The SQL query to analyze
|
|
18
|
+
* @param hints - The hints configuration
|
|
19
|
+
* @returns The modified query with injected hints
|
|
20
|
+
*/
|
|
21
|
+
export function injectSqlHints(query: string, hints?: SqlHints): string {
|
|
22
|
+
if (!hints) {
|
|
23
|
+
return query;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Normalize the query for easier matching
|
|
27
|
+
const normalizedQuery = query.trim().toUpperCase();
|
|
28
|
+
|
|
29
|
+
// Get the appropriate hints based on query type
|
|
30
|
+
let queryHints: string[] | undefined;
|
|
31
|
+
|
|
32
|
+
if (normalizedQuery.startsWith("SELECT")) {
|
|
33
|
+
queryHints = hints.select;
|
|
34
|
+
} else if (normalizedQuery.startsWith("INSERT")) {
|
|
35
|
+
queryHints = hints.insert;
|
|
36
|
+
} else if (normalizedQuery.startsWith("UPDATE")) {
|
|
37
|
+
queryHints = hints.update;
|
|
38
|
+
} else if (normalizedQuery.startsWith("DELETE")) {
|
|
39
|
+
queryHints = hints.delete;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// If no hints for this query type, return original query
|
|
43
|
+
if (!queryHints || queryHints.length === 0) {
|
|
44
|
+
return query;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Join all hints with spaces
|
|
48
|
+
const hintsString = queryHints.join(" ");
|
|
49
|
+
|
|
50
|
+
// Inject hints into the query
|
|
51
|
+
if (normalizedQuery.startsWith("SELECT")) {
|
|
52
|
+
return `SELECT /*+ ${hintsString} */ ${query.substring(6)}`;
|
|
53
|
+
} else if (normalizedQuery.startsWith("INSERT")) {
|
|
54
|
+
return `INSERT /*+ ${hintsString} */ ${query.substring(6)}`;
|
|
55
|
+
} else if (normalizedQuery.startsWith("UPDATE")) {
|
|
56
|
+
return `UPDATE /*+ ${hintsString} */ ${query.substring(6)}`;
|
|
57
|
+
} else if (normalizedQuery.startsWith("DELETE")) {
|
|
58
|
+
return `DELETE /*+ ${hintsString} */ ${query.substring(6)}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// If no match found, return original query
|
|
62
|
+
return query;
|
|
63
|
+
}
|