monsqlize 1.0.0

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 (77) hide show
  1. package/CHANGELOG.md +2474 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1368 -0
  4. package/index.d.ts +1052 -0
  5. package/lib/cache.js +491 -0
  6. package/lib/common/cursor.js +58 -0
  7. package/lib/common/docs-urls.js +72 -0
  8. package/lib/common/index-options.js +222 -0
  9. package/lib/common/log.js +60 -0
  10. package/lib/common/namespace.js +21 -0
  11. package/lib/common/normalize.js +33 -0
  12. package/lib/common/page-result.js +42 -0
  13. package/lib/common/runner.js +56 -0
  14. package/lib/common/server-features.js +231 -0
  15. package/lib/common/shape-builders.js +26 -0
  16. package/lib/common/validation.js +49 -0
  17. package/lib/connect.js +76 -0
  18. package/lib/constants.js +54 -0
  19. package/lib/count-queue.js +187 -0
  20. package/lib/distributed-cache-invalidator.js +259 -0
  21. package/lib/errors.js +157 -0
  22. package/lib/index.js +352 -0
  23. package/lib/logger.js +224 -0
  24. package/lib/model/examples/test.js +114 -0
  25. package/lib/mongodb/common/accessor-helpers.js +44 -0
  26. package/lib/mongodb/common/agg-pipeline.js +32 -0
  27. package/lib/mongodb/common/iid.js +27 -0
  28. package/lib/mongodb/common/lexicographic-expr.js +52 -0
  29. package/lib/mongodb/common/shape.js +31 -0
  30. package/lib/mongodb/common/sort.js +38 -0
  31. package/lib/mongodb/common/transaction-aware.js +24 -0
  32. package/lib/mongodb/connect.js +178 -0
  33. package/lib/mongodb/index.js +458 -0
  34. package/lib/mongodb/management/admin-ops.js +199 -0
  35. package/lib/mongodb/management/bookmark-ops.js +166 -0
  36. package/lib/mongodb/management/cache-ops.js +49 -0
  37. package/lib/mongodb/management/collection-ops.js +386 -0
  38. package/lib/mongodb/management/database-ops.js +201 -0
  39. package/lib/mongodb/management/index-ops.js +474 -0
  40. package/lib/mongodb/management/index.js +16 -0
  41. package/lib/mongodb/management/namespace.js +30 -0
  42. package/lib/mongodb/management/validation-ops.js +267 -0
  43. package/lib/mongodb/queries/aggregate.js +133 -0
  44. package/lib/mongodb/queries/chain.js +623 -0
  45. package/lib/mongodb/queries/count.js +88 -0
  46. package/lib/mongodb/queries/distinct.js +68 -0
  47. package/lib/mongodb/queries/find-and-count.js +183 -0
  48. package/lib/mongodb/queries/find-by-ids.js +235 -0
  49. package/lib/mongodb/queries/find-one-by-id.js +170 -0
  50. package/lib/mongodb/queries/find-one.js +61 -0
  51. package/lib/mongodb/queries/find-page.js +565 -0
  52. package/lib/mongodb/queries/find.js +161 -0
  53. package/lib/mongodb/queries/index.js +49 -0
  54. package/lib/mongodb/writes/delete-many.js +181 -0
  55. package/lib/mongodb/writes/delete-one.js +173 -0
  56. package/lib/mongodb/writes/find-one-and-delete.js +193 -0
  57. package/lib/mongodb/writes/find-one-and-replace.js +222 -0
  58. package/lib/mongodb/writes/find-one-and-update.js +223 -0
  59. package/lib/mongodb/writes/increment-one.js +243 -0
  60. package/lib/mongodb/writes/index.js +41 -0
  61. package/lib/mongodb/writes/insert-batch.js +498 -0
  62. package/lib/mongodb/writes/insert-many.js +218 -0
  63. package/lib/mongodb/writes/insert-one.js +171 -0
  64. package/lib/mongodb/writes/replace-one.js +199 -0
  65. package/lib/mongodb/writes/result-handler.js +236 -0
  66. package/lib/mongodb/writes/update-many.js +205 -0
  67. package/lib/mongodb/writes/update-one.js +207 -0
  68. package/lib/mongodb/writes/upsert-one.js +190 -0
  69. package/lib/multi-level-cache.js +189 -0
  70. package/lib/operators.js +330 -0
  71. package/lib/redis-cache-adapter.js +237 -0
  72. package/lib/transaction/CacheLockManager.js +161 -0
  73. package/lib/transaction/DistributedCacheLockManager.js +239 -0
  74. package/lib/transaction/Transaction.js +314 -0
  75. package/lib/transaction/TransactionManager.js +266 -0
  76. package/lib/transaction/index.js +10 -0
  77. package/package.json +111 -0
@@ -0,0 +1,386 @@
1
+ /**
2
+ * 集合管理操作模块
3
+ * @module management/collection-ops
4
+ */
5
+
6
+ const { createValidationError } = require('../../errors');
7
+
8
+ /**
9
+ * 创建集合管理操作方法
10
+ * @param {Object} context - 上下文对象
11
+ * @param {Object} context.db - MongoDB 数据库实例
12
+ * @param {Object} context.collection - MongoDB 集合实例
13
+ * @param {Object} context.logger - 日志记录器
14
+ * @returns {Object} 集合管理操作方法
15
+ */
16
+ module.exports = function createCollectionOps(context) {
17
+ const { db, collection, logger } = context;
18
+
19
+ return {
20
+ /**
21
+ * 删除集合
22
+ * @returns {Promise<boolean>} 删除操作的结果
23
+ */
24
+ dropCollection: async () => {
25
+ return await collection.drop();
26
+ },
27
+
28
+ /**
29
+ * 创建集合
30
+ * @param {string} [name] - 集合名称;省略则使用当前绑定的集合名
31
+ * @param {Object} [options={}] - 创建集合的配置选项
32
+ * @param {boolean} [options.capped] - 是否创建固定大小集合
33
+ * @param {number} [options.size] - 固定大小集合的字节数
34
+ * @param {number} [options.max] - 固定大小集合的最大文档数
35
+ * @param {Object} [options.timeseries] - 时间序列集合配置
36
+ * @param {Object} [options.validator] - 文档验证规则
37
+ * @returns {Promise<boolean>} 创建成功返回true
38
+ * @example
39
+ * // 创建普通集合
40
+ * await db.createCollection('users');
41
+ *
42
+ * // 创建固定大小集合
43
+ * await db.createCollection('logs', {
44
+ * capped: true,
45
+ * size: 10485760, // 10MB
46
+ * max: 5000
47
+ * });
48
+ *
49
+ * // 创建时间序列集合
50
+ * await db.createCollection('measurements', {
51
+ * timeseries: {
52
+ * timeField: 'timestamp',
53
+ * metaField: 'sensor',
54
+ * granularity: 'seconds'
55
+ * }
56
+ * });
57
+ */
58
+ createCollection: async (name, options = {}) => {
59
+ const collName = name || collection.collectionName;
60
+ await db.createCollection(collName, options);
61
+ return true;
62
+ },
63
+
64
+ /**
65
+ * 创建视图集合
66
+ * @param {string} name - 视图名称
67
+ * @param {string} source - 源集合名称
68
+ * @param {Array} [pipeline=[]] - 聚合管道数组
69
+ * @returns {Promise<boolean>} 创建成功返回true
70
+ */
71
+ createView: async (name, source, pipeline = []) => {
72
+ await db.createCollection(name, {
73
+ viewOn: source,
74
+ pipeline: pipeline || []
75
+ });
76
+ return true;
77
+ },
78
+
79
+ /**
80
+ * 获取集合统计信息
81
+ * @param {Object} [options] - 选项
82
+ * @param {number} [options.scale=1] - 缩放因子(1=字节, 1024=KB, 1048576=MB)
83
+ * @returns {Promise<Object>} 集合统计对象
84
+ * @property {string} ns - 命名空间(数据库.集合)
85
+ * @property {number} count - 文档数量
86
+ * @property {number} size - 数据大小
87
+ * @property {number} storageSize - 存储大小
88
+ * @property {number} totalIndexSize - 索引总大小
89
+ * @property {number} avgObjSize - 平均文档大小
90
+ * @property {Object} indexSizes - 各索引大小
91
+ * @example
92
+ * const stats = await collection.stats();
93
+ * console.log('Documents:', stats.count);
94
+ * console.log('Data size:', stats.size, 'bytes');
95
+ * console.log('Index size:', stats.totalIndexSize, 'bytes');
96
+ *
97
+ * // 使用 MB 为单位
98
+ * const statsMB = await collection.stats({ scale: 1048576 });
99
+ * console.log('Data size:', statsMB.size, 'MB');
100
+ */
101
+ stats: async (options = {}) => {
102
+ try {
103
+ const scale = options.scale || 1;
104
+ // 使用 MongoDB 原生命令获取集合统计
105
+ const result = await db.command({
106
+ collStats: collection.collectionName,
107
+ scale: scale
108
+ });
109
+
110
+ return {
111
+ ns: result.ns,
112
+ count: result.count,
113
+ size: result.size,
114
+ storageSize: result.storageSize,
115
+ totalIndexSize: result.totalIndexSize,
116
+ avgObjSize: result.avgObjSize,
117
+ indexSizes: result.indexSizes,
118
+ nindexes: result.nindexes,
119
+ scaleFactor: result.scaleFactor
120
+ };
121
+ } catch (error) {
122
+ if (logger) {
123
+ logger.error('Collection stats failed', { error: error.message });
124
+ }
125
+ throw createValidationError(
126
+ `Failed to get collection stats: ${error.message}`,
127
+ { code: 'COLLECTION_STATS_ERROR' }
128
+ );
129
+ }
130
+ },
131
+
132
+ /**
133
+ * 列出数据库中的所有集合
134
+ * @param {Object} [options] - 选项
135
+ * @param {boolean} [options.nameOnly=false] - 仅返回集合名称
136
+ * @returns {Promise<Array<Object>|Array<string>>} 集合列表
137
+ * @example
138
+ * // 获取详细信息
139
+ * const collections = await db.listCollections();
140
+ * console.log(collections);
141
+ * // [
142
+ * // { name: 'users', type: 'collection' },
143
+ * // { name: 'orders', type: 'collection' }
144
+ * // ]
145
+ *
146
+ * // 仅获取名称
147
+ * const names = await db.listCollections({ nameOnly: true });
148
+ * console.log(names); // ['users', 'orders']
149
+ */
150
+ listCollections: async (options = {}) => {
151
+ try {
152
+ const collections = await db.listCollections().toArray();
153
+
154
+ if (options.nameOnly) {
155
+ return collections.map(c => c.name);
156
+ }
157
+
158
+ return collections.map(c => ({
159
+ name: c.name,
160
+ type: c.type,
161
+ options: c.options,
162
+ info: c.info
163
+ }));
164
+ } catch (error) {
165
+ if (logger) {
166
+ logger.error('listCollections failed', { error: error.message });
167
+ }
168
+ throw createValidationError(
169
+ `Failed to list collections: ${error.message}`,
170
+ 'LIST_COLLECTIONS_ERROR'
171
+ );
172
+ }
173
+ },
174
+
175
+ /**
176
+ * 重命名集合
177
+ * @param {string} newName - 新集合名称
178
+ * @param {Object} [options] - 选项
179
+ * @param {boolean} [options.dropTarget=false] - 如果目标集合存在,是否删除
180
+ * @returns {Promise<Object>} 重命名结果
181
+ * @example
182
+ * await collection.rename('users_new');
183
+ *
184
+ * // 如果目标已存在,删除并替换
185
+ * await collection.rename('users_backup', { dropTarget: true });
186
+ */
187
+ renameCollection: async (newName, options = {}) => {
188
+ try {
189
+ if (!newName || typeof newName !== 'string') {
190
+ throw createValidationError(
191
+ 'New collection name is required and must be a string',
192
+ 'INVALID_COLLECTION_NAME'
193
+ );
194
+ }
195
+
196
+ const result = await collection.rename(newName, {
197
+ dropTarget: options.dropTarget || false
198
+ });
199
+
200
+ if (logger) {
201
+ logger.info('Collection renamed', {
202
+ from: collection.collectionName,
203
+ to: newName
204
+ });
205
+ }
206
+
207
+ return {
208
+ renamed: true,
209
+ from: collection.collectionName,
210
+ to: newName
211
+ };
212
+ } catch (error) {
213
+ if (logger) {
214
+ logger.error('renameCollection failed', { error: error.message });
215
+ }
216
+ throw createValidationError(
217
+ `Failed to rename collection: ${error.message}`,
218
+ 'RENAME_COLLECTION_ERROR'
219
+ );
220
+ }
221
+ },
222
+
223
+ /**
224
+ * 修改集合属性
225
+ * @param {Object} modifications - 修改选项
226
+ * @param {Object} [modifications.validator] - 新的验证规则
227
+ * @param {string} [modifications.validationLevel] - 验证级别
228
+ * @param {string} [modifications.validationAction] - 验证行为
229
+ * @param {Object} [modifications.index] - 索引修改
230
+ * @returns {Promise<Object>} 修改结果
231
+ * @example
232
+ * // 修改验证级别
233
+ * await collection.collMod({
234
+ * validationLevel: 'moderate'
235
+ * });
236
+ *
237
+ * // 修改 TTL 索引过期时间
238
+ * await collection.collMod({
239
+ * index: {
240
+ * keyPattern: { createdAt: 1 },
241
+ * expireAfterSeconds: 7200
242
+ * }
243
+ * });
244
+ */
245
+ collMod: async (modifications) => {
246
+ try {
247
+ if (!modifications || typeof modifications !== 'object') {
248
+ throw createValidationError(
249
+ 'Modifications object is required',
250
+ 'INVALID_MODIFICATIONS'
251
+ );
252
+ }
253
+
254
+ const result = await db.command({
255
+ collMod: collection.collectionName,
256
+ ...modifications
257
+ });
258
+
259
+ if (logger) {
260
+ logger.info('Collection modified', {
261
+ collection: collection.collectionName,
262
+ modifications: Object.keys(modifications)
263
+ });
264
+ }
265
+
266
+ return {
267
+ ok: result.ok,
268
+ collection: collection.collectionName
269
+ };
270
+ } catch (error) {
271
+ if (logger) {
272
+ logger.error('collMod failed', { error: error.message });
273
+ }
274
+ throw createValidationError(
275
+ `Failed to modify collection: ${error.message}`,
276
+ 'COLLMOD_ERROR'
277
+ );
278
+ }
279
+ },
280
+
281
+ /**
282
+ * 转换为固定大小集合
283
+ * @param {number} size - 集合大小(字节)
284
+ * @param {Object} [options] - 选项
285
+ * @param {number} [options.max] - 最大文档数
286
+ * @returns {Promise<Object>} 转换结果
287
+ * @example
288
+ * // 转换为 10MB 固定大小集合
289
+ * await collection.convertToCapped(10485760);
290
+ *
291
+ * // 限制最大文档数
292
+ * await collection.convertToCapped(10485760, { max: 5000 });
293
+ */
294
+ convertToCapped: async (size, options = {}) => {
295
+ try {
296
+ if (!size || typeof size !== 'number' || size <= 0) {
297
+ throw createValidationError(
298
+ 'Size must be a positive number',
299
+ 'INVALID_SIZE'
300
+ );
301
+ }
302
+
303
+ const command = {
304
+ convertToCapped: collection.collectionName,
305
+ size: size
306
+ };
307
+
308
+ if (options.max) {
309
+ command.max = options.max;
310
+ }
311
+
312
+ const result = await db.command(command);
313
+
314
+ if (logger) {
315
+ logger.info('Collection converted to capped', {
316
+ collection: collection.collectionName,
317
+ size: size,
318
+ max: options.max
319
+ });
320
+ }
321
+
322
+ return {
323
+ ok: result.ok,
324
+ collection: collection.collectionName,
325
+ capped: true,
326
+ size: size
327
+ };
328
+ } catch (error) {
329
+ if (logger) {
330
+ logger.error('convertToCapped failed', { error: error.message });
331
+ }
332
+ throw createValidationError(
333
+ `Failed to convert to capped collection: ${error.message}`,
334
+ 'CONVERT_CAPPED_ERROR'
335
+ );
336
+ }
337
+ },
338
+
339
+ /**
340
+ * 执行任意 MongoDB 命令
341
+ * @param {Object} command - MongoDB 命令对象
342
+ * @param {Object} [options] - 选项
343
+ * @returns {Promise<Object>} 命令执行结果
344
+ * @example
345
+ * // 执行 collStats 命令
346
+ * const result = await db.runCommand({
347
+ * collStats: 'users',
348
+ * scale: 1024
349
+ * });
350
+ *
351
+ * // 执行 ping 命令
352
+ * const ping = await db.runCommand({ ping: 1 });
353
+ */
354
+ runCommand: async (command, options = {}) => {
355
+ try {
356
+ if (!command || typeof command !== 'object') {
357
+ throw createValidationError(
358
+ 'Command must be an object',
359
+ 'INVALID_COMMAND'
360
+ );
361
+ }
362
+
363
+ const result = await db.command(command, options);
364
+
365
+ if (logger) {
366
+ logger.debug('Command executed', {
367
+ command: Object.keys(command)[0]
368
+ });
369
+ }
370
+
371
+ return result;
372
+ } catch (error) {
373
+ if (logger) {
374
+ logger.error('runCommand failed', {
375
+ command: Object.keys(command)[0],
376
+ error: error.message
377
+ });
378
+ }
379
+ throw createValidationError(
380
+ `Failed to execute command: ${error.message}`,
381
+ 'COMMAND_ERROR'
382
+ );
383
+ }
384
+ }
385
+ };
386
+ };
@@ -0,0 +1,201 @@
1
+ /**
2
+ * 数据库级别操作方法工厂函数
3
+ * 提供数据库列表和删除等方法
4
+ * @module mongodb/management/database-ops
5
+ */
6
+
7
+ const { createValidationError } = require('../../errors');
8
+
9
+ /**
10
+ * 创建数据库操作方法
11
+ * @param {Object} context - 上下文对象
12
+ * @param {Object} context.adapter - MongoDB 适配器
13
+ * @param {Object} context.logger - 日志记录器
14
+ * @returns {Object} 数据库操作方法集合
15
+ */
16
+ function createDatabaseOps(context) {
17
+ const { adapter, logger } = context;
18
+
19
+ return {
20
+ /**
21
+ * 列出所有数据库
22
+ * @param {Object} [options] - 选项
23
+ * @param {boolean} [options.nameOnly=false] - 仅返回数据库名称数组
24
+ * @returns {Promise<Array<Object>|Array<string>>} 数据库列表
25
+ * @property {string} name - 数据库名称
26
+ * @property {number} sizeOnDisk - 磁盘占用大小(字节)
27
+ * @property {boolean} empty - 是否为空数据库
28
+ * @example
29
+ * // 获取详细信息
30
+ * const databases = await monSQLize.listDatabases();
31
+ * console.log(databases);
32
+ * // [
33
+ * // { name: 'mydb', sizeOnDisk: 83886080, empty: false },
34
+ * // { name: 'test', sizeOnDisk: 0, empty: true }
35
+ * // ]
36
+ *
37
+ * // 仅获取名称
38
+ * const dbNames = await monSQLize.listDatabases({ nameOnly: true });
39
+ * console.log(dbNames); // ['mydb', 'test', 'admin']
40
+ */
41
+ async listDatabases(options = {}) {
42
+ try {
43
+ const admin = adapter.db.admin();
44
+ const result = await admin.listDatabases();
45
+
46
+ if (options.nameOnly) {
47
+ return result.databases.map(db => db.name);
48
+ }
49
+
50
+ return result.databases.map(db => ({
51
+ name: db.name,
52
+ sizeOnDisk: db.sizeOnDisk,
53
+ empty: db.empty
54
+ }));
55
+ } catch (error) {
56
+ logger.error('listDatabases failed', { error: error.message });
57
+ throw createValidationError(
58
+ `Failed to list databases: ${error.message}`,
59
+ 'LIST_DATABASES_ERROR'
60
+ );
61
+ }
62
+ },
63
+
64
+ /**
65
+ * 删除整个数据库(危险操作)
66
+ *
67
+ * ⚠️ 警告:此操作将永久删除数据库中的所有数据,无法恢复!
68
+ *
69
+ * 安全机制:
70
+ * 1. 必须显式传入 { confirm: true } 才能执行
71
+ * 2. 生产环境默认禁止,需要额外传入 { allowProduction: true }
72
+ * 3. 所有删除操作都会记录审计日志
73
+ *
74
+ * @param {string} databaseName - 数据库名称
75
+ * @param {Object} options - 选项
76
+ * @param {boolean} options.confirm - 必须为 true 才能执行
77
+ * @param {boolean} [options.allowProduction=false] - 是否允许在生产环境执行
78
+ * @param {string} [options.user] - 操作用户(用于审计日志)
79
+ * @returns {Promise<Object>} 删除结果
80
+ * @property {boolean} dropped - 是否删除成功
81
+ * @property {string} database - 被删除的数据库名称
82
+ * @throws {ValidationError} 如果未确认或在生产环境禁止执行
83
+ *
84
+ * @example
85
+ * // ❌ 错误:未提供确认
86
+ * try {
87
+ * await monSQLize.dropDatabase('mydb');
88
+ * } catch (error) {
89
+ * console.error(error.message);
90
+ * // "dropDatabase requires explicit confirmation..."
91
+ * }
92
+ *
93
+ * // ✅ 正确:提供确认
94
+ * const result = await monSQLize.dropDatabase('test_db', {
95
+ * confirm: true,
96
+ * user: 'admin@example.com'
97
+ * });
98
+ * console.log('Database dropped:', result.database);
99
+ *
100
+ * // ⚠️ 生产环境:需要额外确认
101
+ * const result = await monSQLize.dropDatabase('prod_db', {
102
+ * confirm: true,
103
+ * allowProduction: true,
104
+ * user: 'admin@example.com'
105
+ * });
106
+ */
107
+ async dropDatabase(databaseName, options = {}) {
108
+ // 1. 参数验证
109
+ if (!databaseName || typeof databaseName !== 'string') {
110
+ throw createValidationError(
111
+ 'Database name is required and must be a string',
112
+ 'INVALID_DATABASE_NAME'
113
+ );
114
+ }
115
+
116
+ // 2. 强制确认机制
117
+ if (!options.confirm) {
118
+ const error = new Error(
119
+ 'dropDatabase requires explicit confirmation. ' +
120
+ 'Pass { confirm: true } to proceed.\n\n' +
121
+ '⚠️ WARNING: This will DELETE ALL DATA in the database!\n' +
122
+ '⚠️ This operation CANNOT BE UNDONE!\n\n' +
123
+ 'Example:\n' +
124
+ ` await db.dropDatabase('${databaseName}', { confirm: true })`
125
+ );
126
+ error.code = 'CONFIRMATION_REQUIRED';
127
+ throw error;
128
+ }
129
+
130
+ // 3. 生产环境保护
131
+ const isProduction = process.env.NODE_ENV === 'production';
132
+ if (isProduction && !options.allowProduction) {
133
+ const error = new Error(
134
+ 'dropDatabase is blocked in production environment.\n\n' +
135
+ '⚠️ You are in PRODUCTION mode!\n\n' +
136
+ 'If you really want to proceed, pass { allowProduction: true }.\n' +
137
+ 'Make sure you have:\n' +
138
+ ' 1. Created a backup\n' +
139
+ ' 2. Verified this is the correct database\n' +
140
+ ' 3. Obtained necessary approvals\n\n' +
141
+ 'Example:\n' +
142
+ ` await db.dropDatabase('${databaseName}', {\n` +
143
+ ' confirm: true,\n' +
144
+ ' allowProduction: true,\n' +
145
+ " user: 'your-email@example.com'\n" +
146
+ ' })'
147
+ );
148
+ error.code = 'PRODUCTION_BLOCKED';
149
+ throw error;
150
+ }
151
+
152
+ // 4. 审计日志(记录所有删除尝试)
153
+ logger.warn('dropDatabase called', {
154
+ event: 'DROP_DATABASE',
155
+ database: databaseName,
156
+ user: options.user || 'unknown',
157
+ timestamp: new Date().toISOString(),
158
+ environment: process.env.NODE_ENV || 'development',
159
+ confirmed: true
160
+ });
161
+
162
+ try {
163
+ // 5. 执行删除 - 使用 admin 数据库执行 dropDatabase 命令
164
+ const client = adapter.client;
165
+ const targetDb = client.db(databaseName);
166
+ await targetDb.dropDatabase();
167
+
168
+ // 6. 成功日志
169
+ logger.info('dropDatabase successful', {
170
+ event: 'DROP_DATABASE_SUCCESS',
171
+ database: databaseName,
172
+ user: options.user || 'unknown',
173
+ timestamp: new Date().toISOString()
174
+ });
175
+
176
+ return {
177
+ dropped: true,
178
+ database: databaseName,
179
+ timestamp: new Date()
180
+ };
181
+ } catch (error) {
182
+ // 7. 失败日志
183
+ logger.error('dropDatabase failed', {
184
+ event: 'DROP_DATABASE_FAILED',
185
+ database: databaseName,
186
+ user: options.user || 'unknown',
187
+ error: error.message,
188
+ timestamp: new Date().toISOString()
189
+ });
190
+
191
+ throw createValidationError(
192
+ `Failed to drop database '${databaseName}': ${error.message}`,
193
+ 'DROP_DATABASE_ERROR'
194
+ );
195
+ }
196
+ }
197
+ };
198
+ }
199
+
200
+ module.exports = { createDatabaseOps };
201
+