@aetherframework/database 1.0.9 → 1.1.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.
Files changed (44) hide show
  1. package/package.json +1 -2
  2. package/src/DatabaseManager.js +0 -565
  3. package/src/core/ConnectionManager.js +0 -351
  4. package/src/core/DatabaseFactory.js +0 -188
  5. package/src/core/MongoQueryBuilder.js +0 -576
  6. package/src/core/PluginManager.js +0 -968
  7. package/src/core/QueryBuilder.js +0 -4398
  8. package/src/core/TransactionManager.js +0 -40
  9. package/src/drivers/clickhouse-driver.js +0 -272
  10. package/src/drivers/index.js +0 -273
  11. package/src/drivers/mongodb-driver.js +0 -87
  12. package/src/drivers/mssql-driver.js +0 -117
  13. package/src/drivers/mysql-driver.js +0 -169
  14. package/src/drivers/oracle-driver.js +0 -101
  15. package/src/drivers/postgres-driver.js +0 -234
  16. package/src/drivers/redis-driver.js +0 -52
  17. package/src/drivers/sqlite-driver.js +0 -67
  18. package/src/middleware/connection-pool.js +0 -455
  19. package/src/middleware/performance-monitor.js +0 -652
  20. package/src/middleware/query-cache.js +0 -500
  21. package/src/middleware/query-logger.js +0 -262
  22. package/src/plugins/AuditPlugin.js +0 -447
  23. package/src/plugins/BasePlugin.js +0 -418
  24. package/src/plugins/BatchOperationPlugin.js +0 -165
  25. package/src/plugins/CachePlugin.js +0 -407
  26. package/src/plugins/CtePlugin.js +0 -523
  27. package/src/plugins/DistributedPlugin.js +0 -543
  28. package/src/plugins/EncryptionPlugin.js +0 -211
  29. package/src/plugins/FullTextSearchPlugin.js +0 -164
  30. package/src/plugins/GeospatialPlugin.js +0 -219
  31. package/src/plugins/GraphQLPlugin.js +0 -162
  32. package/src/plugins/HookPlugin.js +0 -211
  33. package/src/plugins/JsonPlugin.js +0 -366
  34. package/src/plugins/OptimisticLockPlugin.js +0 -374
  35. package/src/plugins/PerformancePlugin.js +0 -175
  36. package/src/plugins/ResiliencePlugin.js +0 -114
  37. package/src/plugins/ShardingPlugin.js +0 -227
  38. package/src/plugins/SoftDeletePlugin.js +0 -258
  39. package/src/plugins/SyncPlugin.js +0 -373
  40. package/src/plugins/VersioningPlugin.js +0 -314
  41. package/src/plugins/WindowFunctionPlugin.js +0 -343
  42. package/src/utils/config-loader.js +0 -632
  43. package/src/utils/error-handler.js +0 -724
  44. package/src/utils/migration-runner.js +0 -1066
@@ -1,262 +0,0 @@
1
- /**
2
- * @license MIT
3
- * Copyright (c) 2026-present AetherFramework Contributors.
4
- * SPDX-License-Identifier: MIT
5
- * @module @aetherframework/database/middleware/query-logger
6
- */
7
- import { EventEmitter } from 'events';
8
-
9
- class QueryLogger extends EventEmitter {
10
- constructor(options = {}) {
11
- super();
12
- this.options = {
13
- enabled: options.enabled !== false,
14
- logLevel: options.logLevel || 'info',
15
- slowQueryThreshold: options.slowQueryThreshold || 1000, // ms
16
- logToConsole: options.logToConsole !== false,
17
- logToFile: options.logToFile || false,
18
- logFile: options.logFile || 'query.log',
19
- ...options
20
- };
21
- this.queries = [];
22
- this.slowQueries = [];
23
- }
24
-
25
- /**
26
- * Middleware function to log queries
27
- * @param {Object} query - Query object
28
- * @param {Function} next - Next middleware function
29
- * @returns {Promise<Object>} Query result
30
- */
31
- async log(query, next) {
32
- const startTime = Date.now();
33
-
34
- try {
35
- const result = await next(query);
36
- const duration = Date.now() - startTime;
37
-
38
- const logEntry = {
39
- timestamp: new Date().toISOString(),
40
- sql: query.sql,
41
- params: query.params,
42
- duration,
43
- success: true,
44
- connection: query.connectionName,
45
- type: query.type || 'query'
46
- };
47
-
48
- this.queries.push(logEntry);
49
-
50
- // Check for slow queries
51
- if (duration > this.options.slowQueryThreshold) {
52
- this.slowQueries.push(logEntry);
53
- this.emit('slow-query', logEntry);
54
- }
55
-
56
- // Log to console if enabled
57
- if (this.options.logToConsole) {
58
- this.logToConsole(logEntry);
59
- }
60
-
61
- // Log to file if enabled
62
- if (this.options.logToFile) {
63
- this.logToFile(logEntry);
64
- }
65
-
66
- this.emit('query-logged', logEntry);
67
- return result;
68
- } catch (error) {
69
- const duration = Date.now() - startTime;
70
- const logEntry = {
71
- timestamp: new Date().toISOString(),
72
- sql: query.sql,
73
- params: query.params,
74
- duration,
75
- success: false,
76
- error: error.message,
77
- connection: query.connectionName,
78
- type: query.type || 'query'
79
- };
80
-
81
- this.queries.push(logEntry);
82
-
83
- // Log error to console if enabled
84
- if (this.options.logToConsole) {
85
- this.logErrorToConsole(logEntry);
86
- }
87
-
88
- // Log error to file if enabled
89
- if (this.options.logToFile) {
90
- this.logErrorToFile(logEntry);
91
- }
92
-
93
- this.emit('query-error', logEntry);
94
- throw error;
95
- }
96
- }
97
-
98
- /**
99
- * Log query to console
100
- * @param {Object} logEntry - Log entry
101
- */
102
- logToConsole(logEntry) {
103
- const { timestamp, sql, duration, success, connection, type } = logEntry;
104
- const status = success ? '✅' : '❌';
105
- const message = `[${timestamp}] ${status} ${type.toUpperCase()} on ${connection} - ${duration}ms`;
106
-
107
- switch (this.options.logLevel) {
108
- case 'debug':
109
- console.debug(message, { sql: sql.substring(0, 200) + (sql.length > 200 ? '...' : '') });
110
- break;
111
- case 'warn':
112
- if (!success || duration > this.options.slowQueryThreshold) {
113
- console.warn(message);
114
- }
115
- break;
116
- case 'error':
117
- if (!success) {
118
- console.error(message, logEntry.error);
119
- }
120
- break;
121
- default: // info
122
- }
123
- }
124
-
125
- /**
126
- * Log error to console
127
- * @param {Object} logEntry - Log entry
128
- */
129
- logErrorToConsole(logEntry) {
130
- const { timestamp, sql, duration, error, connection, type } = logEntry;
131
- console.error(`[${timestamp}] ❌ ${type.toUpperCase()} ERROR on ${connection} - ${duration}ms`);
132
- console.error(` SQL: ${sql.substring(0, 200)}${sql.length > 200 ? '...' : ''}`);
133
- console.error(` Error: ${error}`);
134
- }
135
-
136
- /**
137
- * Log query to file
138
- * @param {Object} logEntry - Log entry
139
- */
140
- async logToFile(logEntry) {
141
- try {
142
- const fs = await import('fs');
143
- const path = await import('path');
144
-
145
- const logDir = path.dirname(this.options.logFile);
146
- if (!fs.existsSync(logDir)) {
147
- fs.mkdirSync(logDir, { recursive: true });
148
- }
149
-
150
- const logLine = JSON.stringify(logEntry) + '\n';
151
- fs.appendFileSync(this.options.logFile, logLine, 'utf8');
152
- } catch (error) {
153
- console.error('Failed to write query log to file:', error.message);
154
- }
155
- }
156
-
157
- /**
158
- * Log error to file
159
- * @param {Object} logEntry - Log entry
160
- */
161
- async logErrorToFile(logEntry) {
162
- await this.logToFile(logEntry);
163
- }
164
-
165
- /**
166
- * Get query statistics
167
- * @returns {Object} Query statistics
168
- */
169
- getStats() {
170
- const totalQueries = this.queries.length;
171
- const successfulQueries = this.queries.filter(q => q.success).length;
172
- const failedQueries = totalQueries - successfulQueries;
173
- const slowQueries = this.slowQueries.length;
174
-
175
- const avgDuration = totalQueries > 0
176
- ? this.queries.reduce((sum, q) => sum + q.duration, 0) / totalQueries
177
- : 0;
178
-
179
- const maxDuration = totalQueries > 0
180
- ? Math.max(...this.queries.map(q => q.duration))
181
- : 0;
182
-
183
- const minDuration = totalQueries > 0
184
- ? Math.min(...this.queries.filter(q => q.success).map(q => q.duration))
185
- : 0;
186
-
187
- return {
188
- totalQueries,
189
- successfulQueries,
190
- failedQueries,
191
- slowQueries,
192
- avgDuration: avgDuration.toFixed(2),
193
- maxDuration,
194
- minDuration,
195
- successRate: totalQueries > 0 ? (successfulQueries / totalQueries * 100).toFixed(2) + '%' : '0%'
196
- };
197
- }
198
-
199
- /**
200
- * Get recent queries
201
- * @param {number} limit - Number of queries to return
202
- * @returns {Array} Recent queries
203
- */
204
- getRecentQueries(limit = 100) {
205
- return this.queries.slice(-limit);
206
- }
207
-
208
- /**
209
- * Get slow queries
210
- * @param {number} threshold - Slow query threshold in ms
211
- * @returns {Array} Slow queries
212
- */
213
- getSlowQueries(threshold = null) {
214
- const actualThreshold = threshold || this.options.slowQueryThreshold;
215
- return this.queries.filter(q => q.duration > actualThreshold);
216
- }
217
-
218
- /**
219
- * Clear query log
220
- */
221
- clear() {
222
- this.queries = [];
223
- this.slowQueries = [];
224
- this.emit('log-cleared');
225
- }
226
-
227
- /**
228
- * Export query log
229
- * @param {string} format - Export format (json, csv)
230
- * @returns {string} Exported data
231
- */
232
- export(format = 'json') {
233
- switch (format.toLowerCase()) {
234
- case 'csv':
235
- return this.exportToCSV();
236
- case 'json':
237
- default:
238
- return JSON.stringify(this.queries, null, 2);
239
- }
240
- }
241
-
242
- /**
243
- * Export to CSV
244
- * @returns {string} CSV data
245
- */
246
- exportToCSV() {
247
- if (this.queries.length === 0) {
248
- return '';
249
- }
250
-
251
- const headers = Object.keys(this.queries).join(',');
252
- const rows = this.queries.map(q =>
253
- Object.values(q).map(v =>
254
- typeof v === 'string' ? `"${v.replace(/"/g, '""')}"` : v
255
- ).join(',')
256
- );
257
-
258
- return [headers, ...rows].join('\n');
259
- }
260
- }
261
-
262
- export default QueryLogger;
@@ -1,447 +0,0 @@
1
- /**
2
- * @license MIT
3
- * Copyright (c) 2026-present AetherFramework Contributors.
4
- * SPDX-License-Identifier: MIT
5
- * @module @aetherframework/database/plugin/AuditPlugin
6
- */
7
- import { BasePlugin } from './BasePlugin.js';
8
-
9
- /**
10
- * Audit Plugin - Provides comprehensive audit logging functionality
11
- * Tracks all database operations with user context and metadata
12
- */
13
- export class AuditPlugin extends BasePlugin {
14
- constructor(queryBuilder) {
15
- super(queryBuilder);
16
- this.auditEnabled = false;
17
- this.auditOptions = {
18
- userId: null,
19
- action: 'unknown',
20
- metadata: {},
21
- auditTable: 'system_audit_logs'
22
- };
23
- this.auditHooks = new Map();
24
- this.logQueue = []; // 添加日志队列
25
- this.isProcessingQueue = false;
26
- this.queueProcessingInterval = null;
27
- }
28
-
29
- _registerMethods() {
30
- // Register audit methods to QueryBuilder
31
- this.queryBuilder.enableAuditLog = this.enableAuditLog.bind(this);
32
- this.queryBuilder.disableAuditLog = this.disableAuditLog.bind(this);
33
- this.queryBuilder.logAudit = this.logAudit.bind(this);
34
- this.queryBuilder.setAuditUser = this.setAuditUser.bind(this);
35
- this.queryBuilder.setAuditAction = this.setAuditAction.bind(this);
36
- this.queryBuilder.setAuditMetadata = this.setAuditMetadata.bind(this);
37
- this.queryBuilder.setAuditTable = this.setAuditTable.bind(this);
38
- }
39
-
40
- /**
41
- * Enable audit logging
42
- * @param {Object} options - Audit logging options
43
- * @returns {QueryBuilder} Query builder instance
44
- */
45
- enableAuditLog(options = {}) {
46
- this.auditEnabled = true;
47
- this.auditOptions = {
48
- ...this.auditOptions,
49
- ...options
50
- };
51
-
52
- // Add audit hooks
53
- this._addAuditHooks();
54
-
55
- // Create audit table if not exists
56
- this._ensureAuditTable();
57
-
58
- // Start background queue processor
59
- this._startQueueProcessor();
60
-
61
- return this.queryBuilder;
62
- }
63
-
64
- /**
65
- * Disable audit logging
66
- * @returns {QueryBuilder} Query builder instance
67
- */
68
- disableAuditLog() {
69
- this.auditEnabled = false;
70
-
71
- // Remove audit hooks
72
- this._removeAuditHooks();
73
-
74
- // Stop queue processor
75
- this._stopQueueProcessor();
76
-
77
- return this.queryBuilder;
78
- }
79
-
80
- /**
81
- * Set audit user ID
82
- * @param {string|number} userId - User identifier
83
- * @returns {QueryBuilder} Query builder instance
84
- */
85
- setAuditUser(userId) {
86
- this.auditOptions.userId = userId;
87
- return this.queryBuilder;
88
- }
89
-
90
- /**
91
- * Set audit action
92
- * @param {string} action - Action name (create, update, delete, etc.)
93
- * @returns {QueryBuilder} Query builder instance
94
- */
95
- setAuditAction(action) {
96
- this.auditOptions.action = action;
97
- return this.queryBuilder;
98
- }
99
-
100
- /**
101
- * Set audit metadata
102
- * @param {Object} metadata - Additional metadata
103
- * @returns {QueryBuilder} Query builder instance
104
- */
105
- setAuditMetadata(metadata) {
106
- this.auditOptions.metadata = {
107
- ...this.auditOptions.metadata,
108
- ...metadata
109
- };
110
- return this.queryBuilder;
111
- }
112
-
113
- /**
114
- * Set audit table name
115
- * @param {string} tableName - Audit table name
116
- * @returns {QueryBuilder} Query builder instance
117
- */
118
- setAuditTable(tableName) {
119
- this.auditOptions.auditTable = tableName;
120
- return this.queryBuilder;
121
- }
122
-
123
- /**
124
- * Start background queue processor
125
- * @private
126
- */
127
- _startQueueProcessor() {
128
- if (this.queueProcessingInterval) {
129
- clearInterval(this.queueProcessingInterval);
130
- }
131
-
132
- // Process queue every 100ms instead of immediate write
133
- this.queueProcessingInterval = setInterval(() => {
134
- this._processLogQueue();
135
- }, 100);
136
- }
137
-
138
- /**
139
- * Stop background queue processor
140
- * @private
141
- */
142
- _stopQueueProcessor() {
143
- if (this.queueProcessingInterval) {
144
- clearInterval(this.queueProcessingInterval);
145
- this.queueProcessingInterval = null;
146
- }
147
-
148
- // Process remaining logs
149
- this._processLogQueue();
150
- }
151
-
152
- /**
153
- * Process log queue asynchronously
154
- * @private
155
- */
156
- async _processLogQueue() {
157
- if (this.isProcessingQueue || this.logQueue.length === 0) {
158
- return;
159
- }
160
-
161
- this.isProcessingQueue = true;
162
-
163
- try {
164
- // Take up to 100 logs at a time
165
- const logsToProcess = this.logQueue.splice(0, Math.min(100, this.logQueue.length));
166
-
167
- if (logsToProcess.length > 0) {
168
- // Batch insert logs
169
- await this._batchInsertAuditLogs(logsToProcess);
170
- }
171
- } catch (error) {
172
- console.error('Failed to process audit log queue:', error.message);
173
- // Requeue failed logs
174
- // In production, you might want to implement retry logic
175
- } finally {
176
- this.isProcessingQueue = false;
177
- }
178
- }
179
-
180
- /**
181
- * Batch insert audit logs
182
- * @param {Array} logs - Array of audit log entries
183
- * @private
184
- */
185
- async _batchInsertAuditLogs(logs) {
186
- if (logs.length === 0) return;
187
-
188
- const values = [];
189
- const placeholders = [];
190
-
191
- for (const log of logs) {
192
- values.push(
193
- log.userId,
194
- log.action,
195
- log.table_name,
196
- log.sql_query,
197
- log.bindings,
198
- log.query_type,
199
- log.affectedRows || 0,
200
- log.ip_address,
201
- log.user_agent,
202
- log.session_id,
203
- log.request_id,
204
- JSON.stringify(log.metadata),
205
- log.timestamp
206
- );
207
-
208
- placeholders.push('(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
209
- }
210
-
211
- const sql = `
212
- INSERT INTO ${this.auditOptions.auditTable}
213
- (user_id, action, table_name, sql_query, bindings, query_type,
214
- affected_rows, ip_address, user_agent, session_id, request_id,
215
- metadata, created_at)
216
- VALUES ${placeholders.join(', ')}
217
- `;
218
-
219
- try {
220
- await this.queryBuilder.connection.query(sql, values);
221
- } catch (error) {
222
- console.error('Failed to batch insert audit logs:', error.message);
223
- throw error;
224
- }
225
- }
226
-
227
- /**
228
- * Log audit entry (async version)
229
- * @param {Object} data - Additional audit data
230
- * @returns {Promise<void>}
231
- */
232
- async logAudit(data) {
233
- if (!this.auditEnabled) {
234
- return;
235
- }
236
-
237
- const { sql, bindings } = this.queryBuilder.toSQL();
238
- const auditData = {
239
- ...this.auditOptions,
240
- ...data,
241
- table_name: this.queryBuilder.tableName,
242
- sql_query: sql,
243
- bindings: JSON.stringify(bindings),
244
- query_type: this.queryBuilder.query.type,
245
- timestamp: new Date(),
246
- ip_address: data.ipAddress || null,
247
- user_agent: data.userAgent || null,
248
- session_id: data.sessionId || null,
249
- request_id: data.requestId || null
250
- };
251
-
252
- // Queue the log instead of immediate insert
253
- this.logQueue.push(auditData);
254
-
255
- // If queue is getting large, trigger immediate processing
256
- if (this.logQueue.length > 1000) {
257
- this._processLogQueue();
258
- }
259
- }
260
-
261
- /**
262
- * Add audit hooks to QueryBuilder
263
- * @private
264
- */
265
- _addAuditHooks() {
266
- // Hook for insert operations
267
- const insertHook = async (data) => {
268
- await this.logAudit({
269
- action: 'create',
270
- affectedRows: data?.insertedCount || 1,
271
- metadata: { data }
272
- });
273
- };
274
- this.queryBuilder.addHook('afterInsert', insertHook);
275
- this.auditHooks.set('afterInsert', insertHook);
276
-
277
- // Hook for update operations
278
- const updateHook = async (result) => {
279
- await this.logAudit({
280
- action: 'update',
281
- affectedRows: result?.affectedRows || 0,
282
- metadata: { result }
283
- });
284
- };
285
- this.queryBuilder.addHook('afterUpdate', updateHook);
286
- this.auditHooks.set('afterUpdate', updateHook);
287
-
288
- // Hook for delete operations
289
- const deleteHook = async (result) => {
290
- await this.logAudit({
291
- action: 'delete',
292
- affectedRows: result?.affectedRows || 0,
293
- metadata: { result }
294
- });
295
- };
296
- this.queryBuilder.addHook('afterDelete', deleteHook);
297
- this.auditHooks.set('afterDelete', deleteHook);
298
-
299
- // Hook for select operations (optional, can be heavy)
300
- const selectHook = async (result) => {
301
- await this.logAudit({
302
- action: 'read',
303
- affectedRows: result?.length || 0,
304
- metadata: { rowCount: result?.length || 0 }
305
- });
306
- };
307
- this.queryBuilder.addHook('afterSelect', selectHook);
308
- this.auditHooks.set('afterSelect', selectHook);
309
- }
310
-
311
- /**
312
- * Remove audit hooks from QueryBuilder
313
- * @private
314
- */
315
- _removeAuditHooks() {
316
- for (const [event, hook] of this.auditHooks) {
317
- const hooks = this.queryBuilder.hooks[event];
318
- if (hooks) {
319
- const index = hooks.indexOf(hook);
320
- if (index > -1) {
321
- hooks.splice(index, 1);
322
- }
323
- }
324
- }
325
- this.auditHooks.clear();
326
- }
327
-
328
- /**
329
- * Ensure audit table exists
330
- * @private
331
- */
332
- async _ensureAuditTable() {
333
- try {
334
- await this.queryBuilder.connection.query(`
335
- CREATE TABLE IF NOT EXISTS ${this.auditOptions.auditTable} (
336
- id BIGINT AUTO_INCREMENT PRIMARY KEY,
337
- user_id VARCHAR(255),
338
- action VARCHAR(50) NOT NULL,
339
- table_name VARCHAR(255) NOT NULL,
340
- sql_query TEXT NOT NULL,
341
- bindings TEXT,
342
- query_type VARCHAR(20),
343
- affected_rows INT DEFAULT 0,
344
- ip_address VARCHAR(45),
345
- user_agent TEXT,
346
- session_id VARCHAR(255),
347
- request_id VARCHAR(255),
348
- metadata JSON,
349
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
350
- INDEX idx_user_id (user_id),
351
- INDEX idx_action (action),
352
- INDEX idx_table_name (table_name),
353
- INDEX idx_created_at (created_at),
354
- INDEX idx_request_id (request_id)
355
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
356
- `);
357
- } catch (error) {
358
- console.warn('Failed to create audit table:', error.message);
359
- }
360
- }
361
-
362
- /**
363
- * Get audit logs
364
- * @param {Object} filters - Filter criteria
365
- * @param {Object} options - Query options
366
- * @returns {Promise<Array>} Audit logs
367
- */
368
- async getAuditLogs(filters = {}, options = {}) {
369
- const {
370
- page = 1,
371
- perPage = 50,
372
- orderBy = 'created_at',
373
- orderDir = 'desc'
374
- } = options;
375
-
376
- const auditQuery = new this.queryBuilder.constructor(
377
- this.auditOptions.auditTable,
378
- this.queryBuilder.connection,
379
- this.queryBuilder.dialect
380
- );
381
-
382
- // Apply filters
383
- if (filters.userId) {
384
- auditQuery.where('user_id', '=', filters.userId);
385
- }
386
- if (filters.action) {
387
- auditQuery.where('action', '=', filters.action);
388
- }
389
- if (filters.tableName) {
390
- auditQuery.where('table_name', '=', filters.tableName);
391
- }
392
- if (filters.startDate) {
393
- auditQuery.where('created_at', '>=', filters.startDate);
394
- }
395
- if (filters.endDate) {
396
- auditQuery.where('created_at', '<=', filters.endDate);
397
- }
398
- if (filters.requestId) {
399
- auditQuery.where('request_id', '=', filters.requestId);
400
- }
401
-
402
- // Apply ordering and pagination
403
- auditQuery.orderBy(orderBy, orderDir);
404
-
405
- return auditQuery.paginate(page, perPage).get();
406
- }
407
-
408
- /**
409
- * Clean old audit logs
410
- * @param {number} days - Keep logs for this many days
411
- * @returns {Promise<Object>} Cleanup result
412
- */
413
- async cleanAuditLogs(days = 90) {
414
- const cutoffDate = new Date();
415
- cutoffDate.setDate(cutoffDate.getDate() - days);
416
-
417
- const result = await this.queryBuilder.connection.query(
418
- `DELETE FROM ${this.auditOptions.auditTable} WHERE created_at < ?`,
419
- [cutoffDate]
420
- );
421
-
422
- return {
423
- deletedRows: result.affectedRows,
424
- cutoffDate: cutoffDate.toISOString()
425
- };
426
- }
427
-
428
- /**
429
- * Get plugin metadata
430
- * @returns {Object} Plugin metadata
431
- */
432
- getMetadata() {
433
- return {
434
- name: 'AuditPlugin',
435
- version: '1.0.0',
436
- description: 'Comprehensive audit logging for database operations',
437
- features: [
438
- 'Automatic operation tracking',
439
- 'User context logging',
440
- 'Metadata support',
441
- 'Audit log querying',
442
- 'Automatic cleanup'
443
- ],
444
- tables: [this.auditOptions.auditTable]
445
- };
446
- }
447
- }