@bhushanpawar/sqldb 1.0.0 → 1.0.1
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 +695 -4
- package/dist/cache/cache-manager.d.ts.map +1 -1
- package/dist/cache/cache-manager.js +2 -1
- package/dist/cache/cache-manager.js.map +1 -1
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +225 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/schema-generator.d.ts +28 -0
- package/dist/cli/schema-generator.d.ts.map +1 -0
- package/dist/cli/schema-generator.js +159 -0
- package/dist/cli/schema-generator.js.map +1 -0
- package/dist/client.d.ts +32 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +56 -14
- package/dist/client.js.map +1 -1
- package/dist/connection/mariadb.d.ts +21 -0
- package/dist/connection/mariadb.d.ts.map +1 -1
- package/dist/connection/mariadb.js +121 -3
- package/dist/connection/mariadb.js.map +1 -1
- package/dist/db-schema.d.ts +413 -0
- package/dist/db-schema.d.ts.map +1 -0
- package/dist/db-schema.js +1149 -0
- package/dist/db-schema.js.map +1 -0
- package/dist/discovery/dependency-graph.d.ts +3 -0
- package/dist/discovery/dependency-graph.d.ts.map +1 -1
- package/dist/discovery/dependency-graph.js +11 -0
- package/dist/discovery/dependency-graph.js.map +1 -1
- package/dist/discovery/schema-reader.d.ts +1 -1
- package/dist/discovery/schema-reader.d.ts.map +1 -1
- package/dist/discovery/schema-reader.js +48 -19
- package/dist/discovery/schema-reader.js.map +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +63 -3
- package/dist/index.js.map +1 -1
- package/dist/query/operations.d.ts +7 -0
- package/dist/query/operations.d.ts.map +1 -1
- package/dist/query/operations.js +204 -22
- package/dist/query/operations.js.map +1 -1
- package/dist/types/client.d.ts +32 -0
- package/dist/types/client.d.ts.map +1 -0
- package/dist/types/client.js +3 -0
- package/dist/types/client.js.map +1 -0
- package/dist/types/config.d.ts +3 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +14 -1
- package/dist/types/config.js.map +1 -1
- package/dist/types/query.d.ts +12 -0
- package/dist/types/query.d.ts.map +1 -1
- package/dist/types/schema.d.ts +6 -0
- package/dist/types/schema.d.ts.map +1 -1
- package/dist/types/warming.d.ts +47 -0
- package/dist/types/warming.d.ts.map +1 -0
- package/dist/types/warming.js +3 -0
- package/dist/types/warming.js.map +1 -0
- package/dist/warming/auto-warming-manager.d.ts +65 -0
- package/dist/warming/auto-warming-manager.d.ts.map +1 -0
- package/dist/warming/auto-warming-manager.js +256 -0
- package/dist/warming/auto-warming-manager.js.map +1 -0
- package/dist/warming/query-stats-tracker.d.ts +53 -0
- package/dist/warming/query-stats-tracker.d.ts.map +1 -0
- package/dist/warming/query-stats-tracker.js +273 -0
- package/dist/warming/query-stats-tracker.js.map +1 -0
- package/package.json +4 -1
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { MariaDBConnectionManager } from '../connection/mariadb';
|
|
2
|
+
import { CacheManager } from '../cache/cache-manager';
|
|
3
|
+
import { QueryStatsTracker } from './query-stats-tracker';
|
|
4
|
+
import { WarmingConfig, WarmingStats } from '../types/warming';
|
|
5
|
+
import { MariaDBConfig } from '../types/config';
|
|
6
|
+
export declare class AutoWarmingManager {
|
|
7
|
+
private dbManager;
|
|
8
|
+
private warmingDbManager?;
|
|
9
|
+
private cacheManager;
|
|
10
|
+
private statsTracker;
|
|
11
|
+
private config;
|
|
12
|
+
private warmingInterval?;
|
|
13
|
+
private isWarming;
|
|
14
|
+
private warmingStats;
|
|
15
|
+
constructor(dbManager: MariaDBConnectionManager, cacheManager: CacheManager, statsTracker: QueryStatsTracker, config: WarmingConfig, mariadbConfig: MariaDBConfig);
|
|
16
|
+
/**
|
|
17
|
+
* Start auto-warming
|
|
18
|
+
*/
|
|
19
|
+
start(): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Stop auto-warming
|
|
22
|
+
*/
|
|
23
|
+
stop(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Warm cache with most frequently accessed queries
|
|
26
|
+
*/
|
|
27
|
+
warmCache(): Promise<WarmingStats>;
|
|
28
|
+
/**
|
|
29
|
+
* Warm queries for a specific table
|
|
30
|
+
*/
|
|
31
|
+
private warmTableQueries;
|
|
32
|
+
/**
|
|
33
|
+
* Warm a single query
|
|
34
|
+
*/
|
|
35
|
+
private warmQuery;
|
|
36
|
+
/**
|
|
37
|
+
* Build SQL for findMany
|
|
38
|
+
*/
|
|
39
|
+
private buildFindManySQL;
|
|
40
|
+
/**
|
|
41
|
+
* Build SQL for findOne
|
|
42
|
+
*/
|
|
43
|
+
private buildFindOneSQL;
|
|
44
|
+
/**
|
|
45
|
+
* Build SQL for findById
|
|
46
|
+
*/
|
|
47
|
+
private buildFindByIdSQL;
|
|
48
|
+
/**
|
|
49
|
+
* Build SQL for count
|
|
50
|
+
*/
|
|
51
|
+
private buildCountSQL;
|
|
52
|
+
/**
|
|
53
|
+
* Get current cache hit rate
|
|
54
|
+
*/
|
|
55
|
+
private getCacheHitRate;
|
|
56
|
+
/**
|
|
57
|
+
* Get last warming stats
|
|
58
|
+
*/
|
|
59
|
+
getLastWarmingStats(): WarmingStats | null;
|
|
60
|
+
/**
|
|
61
|
+
* Check if currently warming
|
|
62
|
+
*/
|
|
63
|
+
isCurrentlyWarming(): boolean;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=auto-warming-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-warming-manager.d.ts","sourceRoot":"","sources":["../../src/warming/auto-warming-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,YAAY,EAAc,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,SAAS,CAA2B;IAC5C,OAAO,CAAC,gBAAgB,CAAC,CAA2B;IACpD,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,eAAe,CAAC,CAAiB;IACzC,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,YAAY,CAA6B;gBAG/C,SAAS,EAAE,wBAAwB,EACnC,YAAY,EAAE,YAAY,EAC1B,YAAY,EAAE,iBAAiB,EAC/B,MAAM,EAAE,aAAa,EACrB,aAAa,EAAE,aAAa;IAgB9B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;IAyDxC;;OAEG;YACW,gBAAgB;IA6C9B;;OAEG;YACW,SAAS;IA0CvB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAsBxB;;OAEG;IACH,OAAO,CAAC,eAAe;IASvB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAexB;;OAEG;IACH,OAAO,CAAC,aAAa;IAsBrB;;OAEG;YACW,eAAe;IAgB7B;;OAEG;IACH,mBAAmB,IAAI,YAAY,GAAG,IAAI;IAI1C;;OAEG;IACH,kBAAkB,IAAI,OAAO;CAG9B"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AutoWarmingManager = void 0;
|
|
4
|
+
const mariadb_1 = require("../connection/mariadb");
|
|
5
|
+
class AutoWarmingManager {
|
|
6
|
+
constructor(dbManager, cacheManager, statsTracker, config, mariadbConfig) {
|
|
7
|
+
this.isWarming = false;
|
|
8
|
+
this.warmingStats = null;
|
|
9
|
+
this.dbManager = dbManager;
|
|
10
|
+
this.cacheManager = cacheManager;
|
|
11
|
+
this.statsTracker = statsTracker;
|
|
12
|
+
this.config = config;
|
|
13
|
+
// Create separate connection pool for warming if enabled
|
|
14
|
+
if (config.useSeperatePool !== false) {
|
|
15
|
+
this.warmingDbManager = new mariadb_1.MariaDBConnectionManager({
|
|
16
|
+
...mariadbConfig,
|
|
17
|
+
connectionLimit: config.warmingPoolSize || 2,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Start auto-warming
|
|
23
|
+
*/
|
|
24
|
+
async start() {
|
|
25
|
+
if (!this.config.enabled) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
// Connect warming pool if needed
|
|
29
|
+
if (this.warmingDbManager) {
|
|
30
|
+
await this.warmingDbManager.connect();
|
|
31
|
+
}
|
|
32
|
+
// Run initial warming
|
|
33
|
+
await this.warmCache();
|
|
34
|
+
// Schedule periodic warming
|
|
35
|
+
const intervalMs = this.config.intervalMs || 60000; // 1 minute default
|
|
36
|
+
this.warmingInterval = setInterval(async () => {
|
|
37
|
+
await this.warmCache();
|
|
38
|
+
}, intervalMs);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Stop auto-warming
|
|
42
|
+
*/
|
|
43
|
+
async stop() {
|
|
44
|
+
if (this.warmingInterval) {
|
|
45
|
+
clearInterval(this.warmingInterval);
|
|
46
|
+
this.warmingInterval = undefined;
|
|
47
|
+
}
|
|
48
|
+
// Close warming pool if needed
|
|
49
|
+
if (this.warmingDbManager) {
|
|
50
|
+
await this.warmingDbManager.close();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Warm cache with most frequently accessed queries
|
|
55
|
+
*/
|
|
56
|
+
async warmCache() {
|
|
57
|
+
if (this.isWarming) {
|
|
58
|
+
return this.warmingStats;
|
|
59
|
+
}
|
|
60
|
+
this.isWarming = true;
|
|
61
|
+
const startTime = Date.now();
|
|
62
|
+
const stats = {
|
|
63
|
+
timestamp: new Date(),
|
|
64
|
+
queriesWarmed: 0,
|
|
65
|
+
queriesFailed: 0,
|
|
66
|
+
totalTimeMs: 0,
|
|
67
|
+
cacheHitRateBefore: await this.getCacheHitRate(),
|
|
68
|
+
cacheHitRateAfter: 0,
|
|
69
|
+
tables: {},
|
|
70
|
+
};
|
|
71
|
+
try {
|
|
72
|
+
// Get all tracked tables
|
|
73
|
+
const tables = await this.statsTracker.getTrackedTables();
|
|
74
|
+
// Warm queries for each table
|
|
75
|
+
for (const tableName of tables) {
|
|
76
|
+
const tableStats = await this.warmTableQueries(tableName);
|
|
77
|
+
stats.queriesWarmed += tableStats.queriesWarmed;
|
|
78
|
+
stats.queriesFailed += tableStats.queriesFailed;
|
|
79
|
+
stats.tables[tableName] = {
|
|
80
|
+
queriesWarmed: tableStats.queriesWarmed,
|
|
81
|
+
avgExecutionTime: tableStats.avgExecutionTime,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
stats.cacheHitRateAfter = await this.getCacheHitRate();
|
|
85
|
+
stats.totalTimeMs = Date.now() - startTime;
|
|
86
|
+
this.warmingStats = stats;
|
|
87
|
+
// Call success callback
|
|
88
|
+
if (this.config.onWarmingComplete) {
|
|
89
|
+
this.config.onWarmingComplete(stats);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
console.error('[AutoWarmingManager] Cache warming failed:', error.message);
|
|
94
|
+
// Call error callback
|
|
95
|
+
if (this.config.onWarmingError) {
|
|
96
|
+
this.config.onWarmingError(error);
|
|
97
|
+
}
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
this.isWarming = false;
|
|
102
|
+
}
|
|
103
|
+
return stats;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Warm queries for a specific table
|
|
107
|
+
*/
|
|
108
|
+
async warmTableQueries(tableName) {
|
|
109
|
+
const limit = this.config.topQueriesPerTable || 10;
|
|
110
|
+
const minAccessCount = this.config.minAccessCount || 5;
|
|
111
|
+
// Get top queries for this table
|
|
112
|
+
const topQueries = await this.statsTracker.getTopQueries(tableName, limit, minAccessCount);
|
|
113
|
+
let queriesWarmed = 0;
|
|
114
|
+
let queriesFailed = 0;
|
|
115
|
+
let totalExecutionTime = 0;
|
|
116
|
+
// Warm each query
|
|
117
|
+
for (const queryStats of topQueries) {
|
|
118
|
+
try {
|
|
119
|
+
const executionTime = await this.warmQuery(queryStats);
|
|
120
|
+
totalExecutionTime += executionTime;
|
|
121
|
+
queriesWarmed++;
|
|
122
|
+
// Update warming time
|
|
123
|
+
await this.statsTracker.updateWarmingTime(queryStats.queryId);
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
console.error(`[AutoWarmingManager] Failed to warm query ${queryStats.queryId}:`, error.message);
|
|
127
|
+
queriesFailed++;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
queriesWarmed,
|
|
132
|
+
queriesFailed,
|
|
133
|
+
avgExecutionTime: queriesWarmed > 0 ? totalExecutionTime / queriesWarmed : 0,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Warm a single query
|
|
138
|
+
*/
|
|
139
|
+
async warmQuery(queryStats) {
|
|
140
|
+
const startTime = Date.now();
|
|
141
|
+
const dbManager = this.warmingDbManager || this.dbManager;
|
|
142
|
+
// Parse filters
|
|
143
|
+
const filters = queryStats.filters ? JSON.parse(queryStats.filters) : {};
|
|
144
|
+
// Build SQL based on query type
|
|
145
|
+
let sql;
|
|
146
|
+
const params = [];
|
|
147
|
+
switch (queryStats.queryType) {
|
|
148
|
+
case 'findMany':
|
|
149
|
+
sql = this.buildFindManySQL(queryStats.tableName, filters, params);
|
|
150
|
+
break;
|
|
151
|
+
case 'findOne':
|
|
152
|
+
sql = this.buildFindOneSQL(queryStats.tableName, filters, params);
|
|
153
|
+
break;
|
|
154
|
+
case 'findById':
|
|
155
|
+
sql = this.buildFindByIdSQL(queryStats.tableName, filters, params);
|
|
156
|
+
break;
|
|
157
|
+
case 'count':
|
|
158
|
+
sql = this.buildCountSQL(queryStats.tableName, filters, params);
|
|
159
|
+
break;
|
|
160
|
+
default:
|
|
161
|
+
throw new Error(`Unknown query type: ${queryStats.queryType}`);
|
|
162
|
+
}
|
|
163
|
+
// Execute query
|
|
164
|
+
const result = await dbManager.query(sql, params);
|
|
165
|
+
// Store in cache
|
|
166
|
+
const cacheKey = `query:${queryStats.queryId}`;
|
|
167
|
+
await this.cacheManager.set(cacheKey, result, 300); // 5 minute TTL
|
|
168
|
+
return Date.now() - startTime;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Build SQL for findMany
|
|
172
|
+
*/
|
|
173
|
+
buildFindManySQL(tableName, filters, params) {
|
|
174
|
+
let sql = `SELECT * FROM ${tableName}`;
|
|
175
|
+
const whereClauses = [];
|
|
176
|
+
for (const [key, value] of Object.entries(filters)) {
|
|
177
|
+
if (value !== undefined && value !== null) {
|
|
178
|
+
whereClauses.push(`${key} = ?`);
|
|
179
|
+
params.push(value);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (whereClauses.length > 0) {
|
|
183
|
+
sql += ` WHERE ${whereClauses.join(' AND ')}`;
|
|
184
|
+
}
|
|
185
|
+
return sql;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Build SQL for findOne
|
|
189
|
+
*/
|
|
190
|
+
buildFindOneSQL(tableName, filters, params) {
|
|
191
|
+
const sql = this.buildFindManySQL(tableName, filters, params);
|
|
192
|
+
return `${sql} LIMIT 1`;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Build SQL for findById
|
|
196
|
+
*/
|
|
197
|
+
buildFindByIdSQL(tableName, filters, params) {
|
|
198
|
+
// Assume filters contains the ID
|
|
199
|
+
const id = Object.values(filters)[0];
|
|
200
|
+
params.push(id);
|
|
201
|
+
// We'd need to know the primary key column name
|
|
202
|
+
// For now, assume it's in the filters keys
|
|
203
|
+
const idColumn = Object.keys(filters)[0] || 'id';
|
|
204
|
+
return `SELECT * FROM ${tableName} WHERE ${idColumn} = ? LIMIT 1`;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Build SQL for count
|
|
208
|
+
*/
|
|
209
|
+
buildCountSQL(tableName, filters, params) {
|
|
210
|
+
let sql = `SELECT COUNT(*) as count FROM ${tableName}`;
|
|
211
|
+
const whereClauses = [];
|
|
212
|
+
for (const [key, value] of Object.entries(filters)) {
|
|
213
|
+
if (value !== undefined && value !== null) {
|
|
214
|
+
whereClauses.push(`${key} = ?`);
|
|
215
|
+
params.push(value);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (whereClauses.length > 0) {
|
|
219
|
+
sql += ` WHERE ${whereClauses.join(' AND ')}`;
|
|
220
|
+
}
|
|
221
|
+
return sql;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Get current cache hit rate
|
|
225
|
+
*/
|
|
226
|
+
async getCacheHitRate() {
|
|
227
|
+
try {
|
|
228
|
+
const stats = await this.cacheManager.getStats();
|
|
229
|
+
if (!stats) {
|
|
230
|
+
return 0;
|
|
231
|
+
}
|
|
232
|
+
const totalRequests = stats.hits + stats.misses;
|
|
233
|
+
if (totalRequests === 0) {
|
|
234
|
+
return 0;
|
|
235
|
+
}
|
|
236
|
+
return stats.hits / totalRequests;
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
return 0;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Get last warming stats
|
|
244
|
+
*/
|
|
245
|
+
getLastWarmingStats() {
|
|
246
|
+
return this.warmingStats;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Check if currently warming
|
|
250
|
+
*/
|
|
251
|
+
isCurrentlyWarming() {
|
|
252
|
+
return this.isWarming;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
exports.AutoWarmingManager = AutoWarmingManager;
|
|
256
|
+
//# sourceMappingURL=auto-warming-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-warming-manager.js","sourceRoot":"","sources":["../../src/warming/auto-warming-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { MariaDBConnectionManager } from '../connection/mariadb';
|
|
2
|
+
import { QueryStats, QueryAccessLog, WarmingConfig } from '../types/warming';
|
|
3
|
+
export declare class QueryStatsTracker {
|
|
4
|
+
private dbManager;
|
|
5
|
+
private config;
|
|
6
|
+
private statsTableName;
|
|
7
|
+
private inMemoryStats;
|
|
8
|
+
private initialized;
|
|
9
|
+
constructor(dbManager: MariaDBConnectionManager, config: WarmingConfig);
|
|
10
|
+
initialize(): Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* Record a query access
|
|
13
|
+
*/
|
|
14
|
+
recordAccess(log: QueryAccessLog): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Update database stats (non-blocking)
|
|
17
|
+
*/
|
|
18
|
+
private updateDatabaseStats;
|
|
19
|
+
/**
|
|
20
|
+
* Get top queries for a specific table
|
|
21
|
+
*/
|
|
22
|
+
getTopQueries(tableName: string, limit?: number, minAccessCount?: number): Promise<QueryStats[]>;
|
|
23
|
+
/**
|
|
24
|
+
* Get top queries from database
|
|
25
|
+
*/
|
|
26
|
+
private getTopQueriesFromDatabase;
|
|
27
|
+
/**
|
|
28
|
+
* Get top queries from memory
|
|
29
|
+
*/
|
|
30
|
+
private getTopQueriesFromMemory;
|
|
31
|
+
/**
|
|
32
|
+
* Get all tables with tracked queries
|
|
33
|
+
*/
|
|
34
|
+
getTrackedTables(): Promise<string[]>;
|
|
35
|
+
/**
|
|
36
|
+
* Update last warming time for a query
|
|
37
|
+
*/
|
|
38
|
+
updateWarmingTime(queryId: string): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Clean old stats
|
|
41
|
+
*/
|
|
42
|
+
cleanOldStats(olderThanMs?: number): Promise<number>;
|
|
43
|
+
/**
|
|
44
|
+
* Get statistics summary
|
|
45
|
+
*/
|
|
46
|
+
getStatsSummary(): Promise<{
|
|
47
|
+
totalQueries: number;
|
|
48
|
+
totalAccesses: number;
|
|
49
|
+
tableCount: number;
|
|
50
|
+
avgAccessCount: number;
|
|
51
|
+
}>;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=query-stats-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-stats-tracker.d.ts","sourceRoot":"","sources":["../../src/warming/query-stats-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAG7E,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,SAAS,CAA2B;IAC5C,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,aAAa,CAA0B;IAC/C,OAAO,CAAC,WAAW,CAAkB;gBAEzB,SAAS,EAAE,wBAAwB,EAAE,MAAM,EAAE,aAAa;IAOhE,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAmCjC;;OAEG;IACG,YAAY,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAoCtD;;OAEG;YACW,mBAAmB;IAqBjC;;OAEG;IACG,aAAa,CACjB,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,MAAW,EAClB,cAAc,GAAE,MAAU,GACzB,OAAO,CAAC,UAAU,EAAE,CAAC;IAQxB;;OAEG;YACW,yBAAyB;IA6CvC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IA2B/B;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAkB3C;;OAEG;IACG,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBvD;;OAEG;IACG,aAAa,CAAC,WAAW,GAAE,MAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;IAyBpE;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC;QAC/B,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;QACnB,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;CAkCH"}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QueryStatsTracker = void 0;
|
|
4
|
+
class QueryStatsTracker {
|
|
5
|
+
constructor(dbManager, config) {
|
|
6
|
+
this.initialized = false;
|
|
7
|
+
this.dbManager = dbManager;
|
|
8
|
+
this.config = config;
|
|
9
|
+
this.statsTableName = config.statsTableName || '__sqldb_query_stats';
|
|
10
|
+
this.inMemoryStats = new Map();
|
|
11
|
+
}
|
|
12
|
+
async initialize() {
|
|
13
|
+
if (!this.config.trackInDatabase) {
|
|
14
|
+
this.initialized = true;
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
// Create stats table if it doesn't exist
|
|
18
|
+
const createTableSQL = `
|
|
19
|
+
CREATE TABLE IF NOT EXISTS ${this.statsTableName} (
|
|
20
|
+
query_id VARCHAR(64) PRIMARY KEY,
|
|
21
|
+
table_name VARCHAR(255) NOT NULL,
|
|
22
|
+
query_type VARCHAR(50) NOT NULL,
|
|
23
|
+
filters TEXT,
|
|
24
|
+
access_count INT DEFAULT 1,
|
|
25
|
+
last_accessed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
26
|
+
avg_execution_time DECIMAL(10,2) DEFAULT 0,
|
|
27
|
+
last_warming_time TIMESTAMP NULL,
|
|
28
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
29
|
+
INDEX idx_table_access (table_name, access_count DESC),
|
|
30
|
+
INDEX idx_last_accessed (last_accessed_at),
|
|
31
|
+
INDEX idx_warming (last_warming_time)
|
|
32
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
|
33
|
+
`;
|
|
34
|
+
try {
|
|
35
|
+
await this.dbManager.query(createTableSQL);
|
|
36
|
+
this.initialized = true;
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
console.error('[QueryStatsTracker] Failed to create stats table:', error.message);
|
|
40
|
+
// Fallback to in-memory only
|
|
41
|
+
this.config.trackInDatabase = false;
|
|
42
|
+
this.initialized = true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Record a query access
|
|
47
|
+
*/
|
|
48
|
+
async recordAccess(log) {
|
|
49
|
+
if (!this.initialized) {
|
|
50
|
+
await this.initialize();
|
|
51
|
+
}
|
|
52
|
+
const queryId = log.queryId;
|
|
53
|
+
// Update in-memory stats
|
|
54
|
+
const existing = this.inMemoryStats.get(queryId);
|
|
55
|
+
if (existing) {
|
|
56
|
+
existing.accessCount++;
|
|
57
|
+
existing.lastAccessedAt = log.timestamp;
|
|
58
|
+
// Update running average
|
|
59
|
+
existing.avgExecutionTime =
|
|
60
|
+
(existing.avgExecutionTime * (existing.accessCount - 1) + log.executionTimeMs) /
|
|
61
|
+
existing.accessCount;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
this.inMemoryStats.set(queryId, {
|
|
65
|
+
queryId,
|
|
66
|
+
tableName: log.tableName,
|
|
67
|
+
queryType: log.queryType,
|
|
68
|
+
filters: log.filters,
|
|
69
|
+
accessCount: 1,
|
|
70
|
+
lastAccessedAt: log.timestamp,
|
|
71
|
+
avgExecutionTime: log.executionTimeMs,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
// Update database stats (async, don't wait)
|
|
75
|
+
if (this.config.trackInDatabase) {
|
|
76
|
+
this.updateDatabaseStats(log).catch((err) => {
|
|
77
|
+
console.error('[QueryStatsTracker] Failed to update database stats:', err.message);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Update database stats (non-blocking)
|
|
83
|
+
*/
|
|
84
|
+
async updateDatabaseStats(log) {
|
|
85
|
+
const sql = `
|
|
86
|
+
INSERT INTO ${this.statsTableName}
|
|
87
|
+
(query_id, table_name, query_type, filters, access_count, avg_execution_time, last_accessed_at)
|
|
88
|
+
VALUES (?, ?, ?, ?, 1, ?, NOW())
|
|
89
|
+
ON DUPLICATE KEY UPDATE
|
|
90
|
+
access_count = access_count + 1,
|
|
91
|
+
avg_execution_time = (avg_execution_time * access_count + ?) / (access_count + 1),
|
|
92
|
+
last_accessed_at = NOW()
|
|
93
|
+
`;
|
|
94
|
+
await this.dbManager.query(sql, [
|
|
95
|
+
log.queryId,
|
|
96
|
+
log.tableName,
|
|
97
|
+
log.queryType,
|
|
98
|
+
log.filters,
|
|
99
|
+
log.executionTimeMs,
|
|
100
|
+
log.executionTimeMs,
|
|
101
|
+
]);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get top queries for a specific table
|
|
105
|
+
*/
|
|
106
|
+
async getTopQueries(tableName, limit = 10, minAccessCount = 5) {
|
|
107
|
+
if (this.config.trackInDatabase) {
|
|
108
|
+
return this.getTopQueriesFromDatabase(tableName, limit, minAccessCount);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
return this.getTopQueriesFromMemory(tableName, limit, minAccessCount);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get top queries from database
|
|
116
|
+
*/
|
|
117
|
+
async getTopQueriesFromDatabase(tableName, limit, minAccessCount) {
|
|
118
|
+
const maxAge = this.config.maxStatsAge || 3600000; // 1 hour
|
|
119
|
+
const maxAgeDate = new Date(Date.now() - maxAge);
|
|
120
|
+
const sql = `
|
|
121
|
+
SELECT
|
|
122
|
+
query_id as queryId,
|
|
123
|
+
table_name as tableName,
|
|
124
|
+
query_type as queryType,
|
|
125
|
+
filters,
|
|
126
|
+
access_count as accessCount,
|
|
127
|
+
last_accessed_at as lastAccessedAt,
|
|
128
|
+
avg_execution_time as avgExecutionTime,
|
|
129
|
+
last_warming_time as lastWarmingTime
|
|
130
|
+
FROM ${this.statsTableName}
|
|
131
|
+
WHERE table_name = ?
|
|
132
|
+
AND access_count >= ?
|
|
133
|
+
AND last_accessed_at >= ?
|
|
134
|
+
ORDER BY access_count DESC, avg_execution_time ASC
|
|
135
|
+
LIMIT ?
|
|
136
|
+
`;
|
|
137
|
+
const result = await this.dbManager.query(sql, [
|
|
138
|
+
tableName,
|
|
139
|
+
minAccessCount,
|
|
140
|
+
maxAgeDate,
|
|
141
|
+
limit,
|
|
142
|
+
]);
|
|
143
|
+
return result.map((row) => ({
|
|
144
|
+
queryId: row.queryId,
|
|
145
|
+
tableName: row.tableName,
|
|
146
|
+
queryType: row.queryType,
|
|
147
|
+
filters: row.filters,
|
|
148
|
+
accessCount: parseInt(row.accessCount),
|
|
149
|
+
lastAccessedAt: new Date(row.lastAccessedAt),
|
|
150
|
+
avgExecutionTime: parseFloat(row.avgExecutionTime),
|
|
151
|
+
lastWarmingTime: row.lastWarmingTime ? new Date(row.lastWarmingTime) : undefined,
|
|
152
|
+
}));
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get top queries from memory
|
|
156
|
+
*/
|
|
157
|
+
getTopQueriesFromMemory(tableName, limit, minAccessCount) {
|
|
158
|
+
const maxAge = this.config.maxStatsAge || 3600000; // 1 hour
|
|
159
|
+
const maxAgeDate = new Date(Date.now() - maxAge);
|
|
160
|
+
const filtered = Array.from(this.inMemoryStats.values())
|
|
161
|
+
.filter((stat) => stat.tableName === tableName &&
|
|
162
|
+
stat.accessCount >= minAccessCount &&
|
|
163
|
+
stat.lastAccessedAt >= maxAgeDate)
|
|
164
|
+
.sort((a, b) => {
|
|
165
|
+
// Sort by access count (desc), then by avg execution time (asc)
|
|
166
|
+
if (b.accessCount !== a.accessCount) {
|
|
167
|
+
return b.accessCount - a.accessCount;
|
|
168
|
+
}
|
|
169
|
+
return a.avgExecutionTime - b.avgExecutionTime;
|
|
170
|
+
})
|
|
171
|
+
.slice(0, limit);
|
|
172
|
+
return filtered;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Get all tables with tracked queries
|
|
176
|
+
*/
|
|
177
|
+
async getTrackedTables() {
|
|
178
|
+
if (this.config.trackInDatabase) {
|
|
179
|
+
const sql = `
|
|
180
|
+
SELECT DISTINCT table_name
|
|
181
|
+
FROM ${this.statsTableName}
|
|
182
|
+
ORDER BY table_name
|
|
183
|
+
`;
|
|
184
|
+
const result = await this.dbManager.query(sql);
|
|
185
|
+
return result.map((row) => row.table_name);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
const tables = new Set();
|
|
189
|
+
for (const stat of this.inMemoryStats.values()) {
|
|
190
|
+
tables.add(stat.tableName);
|
|
191
|
+
}
|
|
192
|
+
return Array.from(tables).sort();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Update last warming time for a query
|
|
197
|
+
*/
|
|
198
|
+
async updateWarmingTime(queryId) {
|
|
199
|
+
const stat = this.inMemoryStats.get(queryId);
|
|
200
|
+
if (stat) {
|
|
201
|
+
stat.lastWarmingTime = new Date();
|
|
202
|
+
}
|
|
203
|
+
if (this.config.trackInDatabase) {
|
|
204
|
+
const sql = `
|
|
205
|
+
UPDATE ${this.statsTableName}
|
|
206
|
+
SET last_warming_time = NOW()
|
|
207
|
+
WHERE query_id = ?
|
|
208
|
+
`;
|
|
209
|
+
await this.dbManager.query(sql, [queryId]).catch(() => {
|
|
210
|
+
// Ignore errors
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Clean old stats
|
|
216
|
+
*/
|
|
217
|
+
async cleanOldStats(olderThanMs = 86400000) {
|
|
218
|
+
const cutoffDate = new Date(Date.now() - olderThanMs);
|
|
219
|
+
// Clean in-memory stats
|
|
220
|
+
let cleaned = 0;
|
|
221
|
+
for (const [queryId, stat] of this.inMemoryStats.entries()) {
|
|
222
|
+
if (stat.lastAccessedAt < cutoffDate) {
|
|
223
|
+
this.inMemoryStats.delete(queryId);
|
|
224
|
+
cleaned++;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// Clean database stats
|
|
228
|
+
if (this.config.trackInDatabase) {
|
|
229
|
+
const sql = `
|
|
230
|
+
DELETE FROM ${this.statsTableName}
|
|
231
|
+
WHERE last_accessed_at < ?
|
|
232
|
+
`;
|
|
233
|
+
const result = await this.dbManager.query(sql, [cutoffDate]);
|
|
234
|
+
cleaned += result.affectedRows || 0;
|
|
235
|
+
}
|
|
236
|
+
return cleaned;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Get statistics summary
|
|
240
|
+
*/
|
|
241
|
+
async getStatsSummary() {
|
|
242
|
+
if (this.config.trackInDatabase) {
|
|
243
|
+
const sql = `
|
|
244
|
+
SELECT
|
|
245
|
+
COUNT(*) as totalQueries,
|
|
246
|
+
SUM(access_count) as totalAccesses,
|
|
247
|
+
COUNT(DISTINCT table_name) as tableCount,
|
|
248
|
+
AVG(access_count) as avgAccessCount
|
|
249
|
+
FROM ${this.statsTableName}
|
|
250
|
+
`;
|
|
251
|
+
const result = await this.dbManager.query(sql);
|
|
252
|
+
return {
|
|
253
|
+
totalQueries: parseInt(result[0].totalQueries) || 0,
|
|
254
|
+
totalAccesses: parseInt(result[0].totalAccesses) || 0,
|
|
255
|
+
tableCount: parseInt(result[0].tableCount) || 0,
|
|
256
|
+
avgAccessCount: parseFloat(result[0].avgAccessCount) || 0,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
const totalQueries = this.inMemoryStats.size;
|
|
261
|
+
const totalAccesses = Array.from(this.inMemoryStats.values()).reduce((sum, stat) => sum + stat.accessCount, 0);
|
|
262
|
+
const tables = new Set(Array.from(this.inMemoryStats.values()).map((s) => s.tableName));
|
|
263
|
+
return {
|
|
264
|
+
totalQueries,
|
|
265
|
+
totalAccesses,
|
|
266
|
+
tableCount: tables.size,
|
|
267
|
+
avgAccessCount: totalQueries > 0 ? totalAccesses / totalQueries : 0,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
exports.QueryStatsTracker = QueryStatsTracker;
|
|
273
|
+
//# sourceMappingURL=query-stats-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-stats-tracker.js","sourceRoot":"","sources":["../../src/warming/query-stats-tracker.ts"],"names":[],"mappings":"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"}
|