@koishijs/plugin-database-mongo 3.0.5 → 3.1.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.
- package/lib/index.d.ts +8 -8
- package/lib/index.js +25 -36
- package/lib/index.js.map +2 -2
- package/lib/utils.d.ts +1 -2
- package/package.json +3 -3
package/lib/index.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/// <reference types="koishi/lib" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
import { Db, MongoClient } from 'mongodb';
|
|
4
|
-
import { Context, Database,
|
|
4
|
+
import { Context, Database, Schema, Tables } from 'koishi';
|
|
5
|
+
import { Modifier, Query } from '@koishijs/orm';
|
|
5
6
|
import { URLSearchParams } from 'url';
|
|
6
7
|
declare module 'koishi' {
|
|
7
8
|
interface Database {
|
|
8
9
|
mongo: MongoDatabase;
|
|
9
10
|
}
|
|
10
11
|
}
|
|
11
|
-
declare type TableType = keyof Tables;
|
|
12
12
|
declare class MongoDatabase extends Database {
|
|
13
13
|
ctx: Context;
|
|
14
14
|
private config;
|
|
@@ -37,13 +37,13 @@ declare class MongoDatabase extends Database {
|
|
|
37
37
|
};
|
|
38
38
|
};
|
|
39
39
|
}>;
|
|
40
|
-
get(name:
|
|
41
|
-
set(name:
|
|
42
|
-
remove(name:
|
|
40
|
+
get(name: keyof Tables, query: Query, modifier: Modifier): Promise<any>;
|
|
41
|
+
set(name: keyof Tables, query: Query, update: {}): Promise<void>;
|
|
42
|
+
remove(name: keyof Tables, query: Query): Promise<void>;
|
|
43
43
|
private queue;
|
|
44
|
-
create(name:
|
|
45
|
-
upsert(name:
|
|
46
|
-
eval(table:
|
|
44
|
+
create<T extends keyof Tables>(name: T, data: any): Promise<any>;
|
|
45
|
+
upsert(name: keyof Tables, data: any[], keys: string | string[]): Promise<void>;
|
|
46
|
+
eval(table: keyof Tables, expr: any, query: Query): Promise<any>;
|
|
47
47
|
private _flushEvalTasks;
|
|
48
48
|
}
|
|
49
49
|
declare namespace MongoDatabase {
|
package/lib/index.js
CHANGED
|
@@ -2,22 +2,8 @@ var __create = Object.create;
|
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
6
5
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
9
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
10
|
-
var __spreadValues = (a, b) => {
|
|
11
|
-
for (var prop in b || (b = {}))
|
|
12
|
-
if (__hasOwnProp.call(b, prop))
|
|
13
|
-
__defNormalProp(a, prop, b[prop]);
|
|
14
|
-
if (__getOwnPropSymbols)
|
|
15
|
-
for (var prop of __getOwnPropSymbols(b)) {
|
|
16
|
-
if (__propIsEnum.call(b, prop))
|
|
17
|
-
__defNormalProp(a, prop, b[prop]);
|
|
18
|
-
}
|
|
19
|
-
return a;
|
|
20
|
-
};
|
|
21
7
|
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
|
|
22
8
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
23
9
|
var __export = (target, all) => {
|
|
@@ -43,8 +29,8 @@ __export(exports, {
|
|
|
43
29
|
});
|
|
44
30
|
var import_mongodb = __toModule(require("mongodb"));
|
|
45
31
|
var import_koishi2 = __toModule(require("koishi"));
|
|
32
|
+
var import_orm = __toModule(require("@koishijs/orm"));
|
|
46
33
|
var import_url = __toModule(require("url"));
|
|
47
|
-
var import_orm_utils = __toModule(require("@koishijs/orm-utils"));
|
|
48
34
|
|
|
49
35
|
// plugins/database/mongo/src/utils.ts
|
|
50
36
|
var import_koishi = __toModule(require("koishi"));
|
|
@@ -228,7 +214,7 @@ var MongoDatabase = class extends import_koishi2.Database {
|
|
|
228
214
|
const mongourl = this.config.uri || this.connectionStringFromConfig();
|
|
229
215
|
this.client = await import_mongodb.MongoClient.connect(mongourl);
|
|
230
216
|
this.db = this.client.db(this.config.database);
|
|
231
|
-
for (const name in this.
|
|
217
|
+
for (const name in this.model.config) {
|
|
232
218
|
this._tableTasks[name] = this._syncTable(name);
|
|
233
219
|
}
|
|
234
220
|
this.ctx.on("model", (name) => {
|
|
@@ -239,7 +225,7 @@ var MongoDatabase = class extends import_koishi2.Database {
|
|
|
239
225
|
return this.client.close();
|
|
240
226
|
}
|
|
241
227
|
async _createIndexes(name) {
|
|
242
|
-
const { primary, unique } = this.
|
|
228
|
+
const { primary, unique } = this.model.config[name];
|
|
243
229
|
const coll = this.db.collection(name);
|
|
244
230
|
const newSpecs = [];
|
|
245
231
|
const oldSpecs = await coll.indexes();
|
|
@@ -260,7 +246,7 @@ var MongoDatabase = class extends import_koishi2.Database {
|
|
|
260
246
|
await coll.createIndexes(newSpecs);
|
|
261
247
|
}
|
|
262
248
|
async _createFields(name) {
|
|
263
|
-
const { fields } = this.
|
|
249
|
+
const { fields } = this.model.config[name];
|
|
264
250
|
const coll = this.db.collection(name);
|
|
265
251
|
await Promise.all(Object.keys(fields).map((key) => {
|
|
266
252
|
if ((0, import_koishi2.isNullable)(fields[key].initial))
|
|
@@ -277,13 +263,13 @@ var MongoDatabase = class extends import_koishi2.Database {
|
|
|
277
263
|
]);
|
|
278
264
|
}
|
|
279
265
|
_createFilter(name, query) {
|
|
280
|
-
return transformQuery(this.
|
|
266
|
+
return transformQuery(this.resolveQuery(name, query));
|
|
281
267
|
}
|
|
282
268
|
async drop() {
|
|
283
|
-
await Promise.all(Object.keys(this.
|
|
269
|
+
await Promise.all(Object.keys(this.model.config).map((name) => this.db.dropCollection(name)));
|
|
284
270
|
}
|
|
285
271
|
async _collStats() {
|
|
286
|
-
const tables = Object.keys(this.
|
|
272
|
+
const tables = Object.keys(this.model.config);
|
|
287
273
|
const entries = await Promise.all(tables.map(async (name) => {
|
|
288
274
|
const coll = this.db.collection(name);
|
|
289
275
|
const { count, size } = await coll.stats();
|
|
@@ -304,31 +290,33 @@ var MongoDatabase = class extends import_koishi2.Database {
|
|
|
304
290
|
return [];
|
|
305
291
|
await this._tableTasks[name];
|
|
306
292
|
let cursor = this.db.collection(name).find(filter);
|
|
307
|
-
const { fields, limit, offset = 0, sort } =
|
|
308
|
-
cursor = cursor.project(__spreadValues({ _id: 0 }, Object.fromEntries((fields != null ? fields : []).map((key) => [key, 1]))));
|
|
293
|
+
const { fields, limit, offset = 0, sort } = this.resolveModifier(name, modifier);
|
|
309
294
|
if (offset)
|
|
310
295
|
cursor = cursor.skip(offset);
|
|
311
296
|
if (limit)
|
|
312
297
|
cursor = cursor.limit(offset + limit);
|
|
313
298
|
if (sort)
|
|
314
299
|
cursor = cursor.sort(sort);
|
|
315
|
-
return await cursor.toArray();
|
|
300
|
+
return (await cursor.toArray()).map((row) => this.resolveData(name, row, fields));
|
|
316
301
|
}
|
|
317
302
|
async set(name, query, update) {
|
|
318
303
|
const filter = this._createFilter(name, query);
|
|
319
304
|
if (!filter)
|
|
320
305
|
return;
|
|
321
306
|
await this._tableTasks[name];
|
|
322
|
-
const { primary } = this.
|
|
307
|
+
const { primary } = this.model.config[name];
|
|
323
308
|
const indexFields = (0, import_koishi2.makeArray)(primary);
|
|
324
|
-
const updateFields = new Set(Object.keys(update).map((key) => key.split(".", 1)[0]));
|
|
325
309
|
const coll = this.db.collection(name);
|
|
326
310
|
const original = await coll.find(filter).toArray();
|
|
327
311
|
if (!original.length)
|
|
328
312
|
return;
|
|
313
|
+
update = this.model.format(name, update);
|
|
314
|
+
const updateFields = new Set(Object.keys(update).map((key) => key.split(".", 1)[0]));
|
|
329
315
|
const bulk = coll.initializeUnorderedBulkOp();
|
|
330
316
|
for (const item of original) {
|
|
331
|
-
bulk.find((0, import_koishi2.pick)(item, indexFields)).updateOne({
|
|
317
|
+
bulk.find((0, import_koishi2.pick)(item, indexFields)).updateOne({
|
|
318
|
+
$set: (0, import_koishi2.pick)((0, import_orm.executeUpdate)(item, update), updateFields)
|
|
319
|
+
});
|
|
332
320
|
}
|
|
333
321
|
await bulk.execute();
|
|
334
322
|
}
|
|
@@ -344,7 +332,7 @@ var MongoDatabase = class extends import_koishi2.Database {
|
|
|
344
332
|
async create(name, data) {
|
|
345
333
|
const coll = this.db.collection(name);
|
|
346
334
|
return this.queue(name, async () => {
|
|
347
|
-
const { primary, fields, autoInc } = this.
|
|
335
|
+
const { primary, fields, autoInc } = this.model.config[name];
|
|
348
336
|
if (autoInc && !Array.isArray(primary) && !(primary in data)) {
|
|
349
337
|
const [latest] = await coll.find().sort(primary, -1).limit(1).toArray();
|
|
350
338
|
data[primary] = latest ? +latest[primary] + 1 : 1;
|
|
@@ -353,14 +341,14 @@ var MongoDatabase = class extends import_koishi2.Database {
|
|
|
353
341
|
data[primary] = data[primary].padStart(8, "0");
|
|
354
342
|
}
|
|
355
343
|
}
|
|
356
|
-
const copy =
|
|
344
|
+
const copy = this.model.create(name, data);
|
|
357
345
|
try {
|
|
358
346
|
await coll.insertOne(copy);
|
|
359
|
-
delete copy
|
|
347
|
+
delete copy["_id"];
|
|
360
348
|
return copy;
|
|
361
349
|
} catch (err) {
|
|
362
350
|
if (err instanceof import_mongodb.MongoError && err.code === 11e3) {
|
|
363
|
-
throw new import_koishi2.
|
|
351
|
+
throw new import_koishi2.DriverError("duplicate-entry", err.message);
|
|
364
352
|
}
|
|
365
353
|
throw err;
|
|
366
354
|
}
|
|
@@ -370,20 +358,21 @@ var MongoDatabase = class extends import_koishi2.Database {
|
|
|
370
358
|
if (!data.length)
|
|
371
359
|
return;
|
|
372
360
|
if (!keys)
|
|
373
|
-
keys = this.
|
|
361
|
+
keys = this.model.config[name].primary;
|
|
374
362
|
const indexFields = (0, import_koishi2.makeArray)(keys);
|
|
375
363
|
await this._tableTasks[name];
|
|
376
364
|
const coll = this.db.collection(name);
|
|
377
365
|
const original = await coll.find({ $or: data.map((item) => (0, import_koishi2.pick)(item, indexFields)) }).toArray();
|
|
378
366
|
const bulk = coll.initializeUnorderedBulkOp();
|
|
379
|
-
for (const
|
|
367
|
+
for (const _item of data) {
|
|
368
|
+
const update = this.model.format(name, _item);
|
|
380
369
|
const item = original.find((item2) => indexFields.every((key) => item2[key].valueOf() === update[key].valueOf()));
|
|
381
370
|
if (item) {
|
|
382
371
|
const updateFields = new Set(Object.keys(update).map((key) => key.split(".", 1)[0]));
|
|
383
|
-
const override = (0, import_koishi2.omit)((0, import_koishi2.pick)((0,
|
|
372
|
+
const override = (0, import_koishi2.omit)((0, import_koishi2.pick)((0, import_orm.executeUpdate)(item, update), updateFields), indexFields);
|
|
384
373
|
bulk.find((0, import_koishi2.pick)(item, indexFields)).updateOne({ $set: override });
|
|
385
374
|
} else {
|
|
386
|
-
bulk.insert((0,
|
|
375
|
+
bulk.insert((0, import_orm.executeUpdate)(this.model.create(name), update));
|
|
387
376
|
}
|
|
388
377
|
}
|
|
389
378
|
await bulk.execute();
|
|
@@ -418,7 +407,7 @@ var MongoDatabase = class extends import_koishi2.Database {
|
|
|
418
407
|
}
|
|
419
408
|
for (const { expr, resolve, reject } of tasks) {
|
|
420
409
|
try {
|
|
421
|
-
resolve((0,
|
|
410
|
+
resolve((0, import_orm.executeEval)(data, expr));
|
|
422
411
|
} catch (error) {
|
|
423
412
|
reject(error);
|
|
424
413
|
}
|
package/lib/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts", "../src/utils.ts"],
|
|
4
|
-
"sourcesContent": ["import { Db, IndexDescription, MongoClient, MongoError } from 'mongodb'\nimport { Context, Database, Dict, isNullable, KoishiError, makeArray, Model, noop, omit, pick, Query, Schema, Tables } from 'koishi'\nimport { URLSearchParams } from 'url'\nimport { executeEval, executeUpdate } from '@koishijs/orm-utils'\nimport { transformEval, transformQuery } from './utils'\n\ndeclare module 'koishi' {\n interface Database {\n mongo: MongoDatabase\n }\n}\n\ntype TableType = keyof Tables\n\ninterface EvalTask {\n expr: any\n table: TableType\n query: Query\n resolve: (value: any) => void\n reject: (error: Error) => void\n}\n\nclass MongoDatabase extends Database {\n public client: MongoClient\n public db: Db\n public mongo = this\n private _tableTasks: Dict<Promise<any>> = {}\n private _evalTasks: EvalTask[] = []\n\n constructor(public ctx: Context, private config: MongoDatabase.Config) {\n super(ctx)\n }\n\n private connectionStringFromConfig() {\n const { authDatabase, connectOptions, host, database: name, password, port, protocol, username } = this.config\n let mongourl = `${protocol}://`\n if (username) mongourl += `${encodeURIComponent(username)}${password ? `:${encodeURIComponent(password)}` : ''}@`\n mongourl += `${host}${port ? `:${port}` : ''}/${authDatabase || name}`\n if (connectOptions) {\n const params = new URLSearchParams(connectOptions)\n mongourl += `?${params}`\n }\n return mongourl\n }\n\n async start() {\n const mongourl = this.config.uri || this.connectionStringFromConfig()\n this.client = await MongoClient.connect(mongourl)\n this.db = this.client.db(this.config.database)\n\n for (const name in this.ctx.model.config) {\n this._tableTasks[name] = this._syncTable(name)\n }\n\n this.ctx.on('model', (name) => {\n this._tableTasks[name] = this._syncTable(name)\n })\n }\n\n stop() {\n return this.client.close()\n }\n\n private async _createIndexes(name: string) {\n const { primary, unique } = this.ctx.model.config[name]\n const coll = this.db.collection(name)\n const newSpecs: IndexDescription[] = []\n const oldSpecs = await coll.indexes()\n ;[primary, ...unique].forEach((keys, index) => {\n keys = makeArray(keys)\n const name = (index ? 'unique:' : 'primary:') + keys.join('+')\n if (oldSpecs.find(spec => spec.name === name)) return\n newSpecs.push({\n name,\n key: Object.fromEntries(keys.map(key => [key, 1])),\n unique: true,\n // https://docs.mongodb.com/manual/core/index-partial/#std-label-partial-index-with-unique-constraints\n partialFilterExpression: Object.fromEntries(keys.map(key => [key, { $exists: true }])),\n })\n })\n if (!newSpecs.length) return\n await coll.createIndexes(newSpecs)\n }\n\n private async _createFields(name: string) {\n const { fields } = this.ctx.model.config[name]\n const coll = this.db.collection(name)\n await Promise.all(Object.keys(fields).map((key) => {\n if (isNullable(fields[key].initial)) return\n return coll.updateMany({ [key]: { $exists: false } }, { $set: { [key]: fields[key].initial } })\n }))\n }\n\n /** synchronize table schema */\n private async _syncTable(name: string) {\n await this._tableTasks[name]\n await this.db.createCollection(name).catch(noop)\n await Promise.all([\n this._createIndexes(name),\n this._createFields(name),\n ])\n }\n\n private _createFilter(name: string, query: Query) {\n return transformQuery(this.ctx.model.resolveQuery(name, query))\n }\n\n async drop() {\n await Promise.all(Object.keys(this.ctx.model.config).map(name => this.db.dropCollection(name)))\n }\n\n private async _collStats() {\n const tables = Object.keys(this.ctx.model.config)\n const entries = await Promise.all(tables.map(async (name) => {\n const coll = this.db.collection(name)\n const { count, size } = await coll.stats()\n return [coll.collectionName, { count, size }] as const\n }))\n return Object.fromEntries(entries)\n }\n\n async stats() {\n // https://docs.mongodb.com/manual/reference/command/dbStats/#std-label-dbstats-output\n const [{ totalSize }, tables] = await Promise.all([\n this.db.stats(),\n this._collStats(),\n ])\n return { size: totalSize, tables }\n }\n\n async get(name: TableType, query: Query, modifier: Query.Modifier) {\n const filter = this._createFilter(name, query)\n if (!filter) return []\n await this._tableTasks[name]\n let cursor = this.db.collection(name).find(filter)\n const { fields, limit, offset = 0, sort } = Query.resolveModifier(modifier)\n cursor = cursor.project({ _id: 0, ...Object.fromEntries((fields ?? []).map(key => [key, 1])) })\n if (offset) cursor = cursor.skip(offset)\n if (limit) cursor = cursor.limit(offset + limit)\n if (sort) cursor = cursor.sort(sort)\n return await cursor.toArray() as any\n }\n\n async set(name: TableType, query: Query, update: {}) {\n const filter = this._createFilter(name, query)\n if (!filter) return\n await this._tableTasks[name]\n const { primary } = this.ctx.model.config[name]\n const indexFields = makeArray(primary)\n const updateFields = new Set(Object.keys(update).map(key => key.split('.', 1)[0]))\n const coll = this.db.collection(name)\n const original = await coll.find(filter).toArray()\n if (!original.length) return\n const bulk = coll.initializeUnorderedBulkOp()\n for (const item of original) {\n bulk.find(pick(item, indexFields)).updateOne({ $set: pick(executeUpdate(item, update), updateFields) })\n }\n await bulk.execute()\n }\n\n async remove(name: TableType, query: Query) {\n const filter = this._createFilter(name, query)\n if (!filter) return\n await this.db.collection(name).deleteMany(filter)\n }\n\n private queue(name: TableType, callback: () => Promise<any>) {\n return this._tableTasks[name] = Promise.resolve(this._tableTasks[name]).catch(noop).then(callback)\n }\n\n async create(name: TableType, data: any) {\n const coll = this.db.collection(name)\n return this.queue(name, async () => {\n const { primary, fields, autoInc } = this.ctx.model.config[name]\n if (autoInc && !Array.isArray(primary) && !(primary in data)) {\n const [latest] = await coll.find().sort(primary, -1).limit(1).toArray()\n data[primary] = latest ? +latest[primary] + 1 : 1\n if (Model.Field.string.includes(fields[primary].type)) {\n data[primary] += ''\n data[primary] = data[primary].padStart(8, '0')\n }\n }\n const copy = { ...this.ctx.model.create(name), ...data }\n try {\n await coll.insertOne(copy)\n delete copy._id\n return copy\n } catch (err) {\n if (err instanceof MongoError && err.code === 11000) {\n throw new KoishiError(err.message, 'database.duplicate-entry')\n }\n throw err\n }\n })\n }\n\n async upsert(name: TableType, data: any[], keys: string | string[]) {\n if (!data.length) return\n if (!keys) keys = this.ctx.model.config[name].primary\n const indexFields = makeArray(keys)\n await this._tableTasks[name]\n const coll = this.db.collection(name)\n const original = await coll.find({ $or: data.map(item => pick(item, indexFields)) }).toArray()\n const bulk = coll.initializeUnorderedBulkOp()\n for (const update of data) {\n const item = original.find(item => indexFields.every(key => item[key].valueOf() === update[key].valueOf()))\n if (item) {\n const updateFields = new Set(Object.keys(update).map(key => key.split('.', 1)[0]))\n const override = omit(pick(executeUpdate(item, update), updateFields), indexFields)\n bulk.find(pick(item, indexFields)).updateOne({ $set: override })\n } else {\n bulk.insert(executeUpdate(this.ctx.model.create(name), update))\n }\n }\n await bulk.execute()\n }\n\n eval(table: TableType, expr: any, query: Query) {\n return new Promise<any>((resolve, reject) => {\n this._evalTasks.push({ expr, table, query, resolve, reject })\n process.nextTick(() => this._flushEvalTasks())\n })\n }\n\n private async _flushEvalTasks() {\n const tasks = this._evalTasks\n if (!tasks.length) return\n this._evalTasks = []\n\n const stages: any[] = [{ $match: { _id: null } }]\n for (const task of tasks) {\n const { expr, table, query } = task\n task.expr = transformEval(expr, (pipeline) => {\n const filter = this._createFilter(table, query) || { _id: null }\n pipeline.unshift({ $match: filter })\n stages.push({ $unionWith: { coll: table, pipeline } })\n })\n }\n\n let data: any\n try {\n const results = await this.db.collection('user').aggregate(stages).toArray()\n data = Object.assign({}, ...results)\n } catch (error) {\n tasks.forEach(task => task.reject(error))\n return\n }\n\n for (const { expr, resolve, reject } of tasks) {\n try {\n resolve(executeEval(data, expr))\n } catch (error) {\n reject(error)\n }\n }\n }\n}\n\nnamespace MongoDatabase {\n export const name = 'database-mongo'\n\n export interface Config {\n username?: string\n password?: string\n protocol?: string\n host?: string\n port?: number\n /** database name */\n database?: string\n /** default auth database */\n authDatabase?: string\n connectOptions?: ConstructorParameters<typeof URLSearchParams>[0]\n /** connection string (will overwrite all configs except 'name') */\n uri?: string\n }\n\n export const Config = Schema.object({\n protocol: Schema.string().description('要使用的协议名。').default('mongodb'),\n host: Schema.string().description('要连接到的主机名。').default('localhost'),\n port: Schema.natural().max(65535).description('要连接到的端口号。'),\n username: Schema.string().description('要使用的用户名。'),\n password: Schema.string().description('要使用的密码。').role('secret'),\n database: Schema.string().description('要访问的数据库名。').default('koishi'),\n })\n}\n\nexport default MongoDatabase\n", "import { Query, Random, valueMap } from 'koishi'\nimport { Filter, FilterOperators } from 'mongodb'\n\nfunction createFieldFilter(query: Query.FieldQuery, key: string) {\n const filters: Filter<any>[] = []\n const result: Filter<any> = {}\n const child = transformFieldQuery(query, key, filters)\n if (child === false) return false\n if (child !== true) result[key] = child\n if (filters.length) result.$and = filters\n if (Object.keys(result).length) return result\n return true\n}\n\nfunction transformFieldQuery(query: Query.FieldQuery, key: string, filters: Filter<any>[]) {\n // shorthand syntax\n if (typeof query === 'string' || typeof query === 'number' || query instanceof Date) {\n return { $eq: query }\n } else if (Array.isArray(query)) {\n if (!query.length) return false\n return { $in: query }\n } else if (query instanceof RegExp) {\n return { $regex: query }\n }\n\n // query operators\n const result: FilterOperators<any> = {}\n for (const prop in query) {\n if (prop === '$and') {\n for (const item of query[prop]) {\n const child = createFieldFilter(item, key)\n if (child === false) return false\n if (child !== true) filters.push(child)\n }\n } else if (prop === '$or') {\n const $or: Filter<any>[] = []\n if (!query[prop].length) return false\n const always = query[prop].some((item) => {\n const child = createFieldFilter(item, key)\n if (typeof child === 'boolean') return child\n $or.push(child)\n })\n if (!always) filters.push({ $or })\n } else if (prop === '$not') {\n const child = createFieldFilter(query[prop], key)\n if (child === true) return false\n if (child !== false) filters.push({ $nor: [child] })\n } else if (prop === '$el') {\n const child = transformFieldQuery(query[prop], key, filters)\n if (child === false) return false\n if (child !== true) result.$elemMatch = child\n } else if (prop === '$regexFor') {\n filters.push({\n $expr: {\n $function: {\n body: function (data: string, value: string) {\n return new RegExp(data, 'i').test(value)\n }.toString(),\n args: ['$' + key, query.$regexFor],\n lang: 'js',\n },\n },\n })\n } else {\n result[prop] = query[prop]\n }\n }\n if (!Object.keys(result).length) return true\n return result\n}\n\nexport function transformQuery(query: Query.Expr) {\n const filter: Filter<any> = {}\n const additional: Filter<any>[] = []\n for (const key in query) {\n const value = query[key]\n if (key === '$and' || key === '$or') {\n // MongoError: $and/$or/$nor must be a nonempty array\n // { $and: [] } matches everything\n // { $or: [] } matches nothing\n if (value.length) {\n filter[key] = value.map(transformQuery)\n } else if (key === '$or') {\n return\n }\n } else if (key === '$not') {\n // MongoError: unknown top level operator: $not\n // https://stackoverflow.com/questions/25270396/mongodb-how-to-invert-query-with-not\n // this may solve this problem but lead to performance degradation\n const query = transformQuery(value)\n if (query) filter.$nor = [query]\n } else if (key === '$expr') {\n additional.push({ $expr: transformEval(value) })\n } else {\n const query = transformFieldQuery(value, key, additional)\n if (query === false) return\n if (query !== true) filter[key] = query\n }\n }\n if (additional.length) {\n (filter.$and ||= []).push(...additional)\n }\n return filter\n}\n\nfunction transformEvalExpr(expr: any, onAggr?: (pipeline: any[]) => void) {\n return valueMap(expr as any, (value) => {\n if (Array.isArray(value)) {\n return value.map(val => transformEval(val, onAggr))\n } else {\n return transformEval(value, onAggr)\n }\n })\n}\n\nfunction transformAggr(expr: any) {\n if (typeof expr === 'string') {\n return '$' + expr\n }\n return transformEvalExpr(expr)\n}\n\nconst aggrKeys = ['$sum', '$avg', '$min', '$max', '$count']\n\nexport function transformEval(expr: any, onAggr?: (pipeline: any[]) => void) {\n if (typeof expr === 'number' || typeof expr === 'string' || typeof expr === 'boolean') {\n return expr\n } else if (expr.$) {\n return '$' + expr.$\n }\n\n for (const key of aggrKeys) {\n if (!expr[key]) continue\n const value = transformAggr(expr[key])\n const $ = Random.id()\n if (key === '$count') {\n onAggr([\n { $group: { _id: value } },\n { $group: { _id: null, [$]: { $count: {} } } },\n ])\n } else {\n onAggr([{ $group: { _id: null, [$]: { [key]: value } } }])\n }\n return { $ }\n }\n\n return transformEvalExpr(expr, onAggr)\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import { Db, IndexDescription, MongoClient, MongoError } from 'mongodb'\nimport { Context, Database, Dict, DriverError, isNullable, makeArray, Model, noop, omit, pick, Schema, Tables } from 'koishi'\nimport { executeEval, executeUpdate, Modifier, Query } from '@koishijs/orm'\nimport { URLSearchParams } from 'url'\nimport { transformEval, transformQuery } from './utils'\n\ndeclare module 'koishi' {\n interface Database {\n mongo: MongoDatabase\n }\n}\n\ninterface EvalTask {\n expr: any\n table: keyof Tables\n query: Query\n resolve: (value: any) => void\n reject: (error: Error) => void\n}\n\nclass MongoDatabase extends Database {\n public client: MongoClient\n public db: Db\n public mongo = this\n private _tableTasks: Dict<Promise<any>> = {}\n private _evalTasks: EvalTask[] = []\n\n constructor(public ctx: Context, private config: MongoDatabase.Config) {\n super(ctx)\n }\n\n private connectionStringFromConfig() {\n const { authDatabase, connectOptions, host, database: name, password, port, protocol, username } = this.config\n let mongourl = `${protocol}://`\n if (username) mongourl += `${encodeURIComponent(username)}${password ? `:${encodeURIComponent(password)}` : ''}@`\n mongourl += `${host}${port ? `:${port}` : ''}/${authDatabase || name}`\n if (connectOptions) {\n const params = new URLSearchParams(connectOptions)\n mongourl += `?${params}`\n }\n return mongourl\n }\n\n async start() {\n const mongourl = this.config.uri || this.connectionStringFromConfig()\n this.client = await MongoClient.connect(mongourl)\n this.db = this.client.db(this.config.database)\n\n for (const name in this.model.config) {\n this._tableTasks[name] = this._syncTable(name)\n }\n\n this.ctx.on('model', (name) => {\n this._tableTasks[name] = this._syncTable(name)\n })\n }\n\n stop() {\n return this.client.close()\n }\n\n private async _createIndexes(name: string) {\n const { primary, unique } = this.model.config[name]\n const coll = this.db.collection(name)\n const newSpecs: IndexDescription[] = []\n const oldSpecs = await coll.indexes()\n ;[primary, ...unique].forEach((keys, index) => {\n keys = makeArray(keys)\n const name = (index ? 'unique:' : 'primary:') + keys.join('+')\n if (oldSpecs.find(spec => spec.name === name)) return\n newSpecs.push({\n name,\n key: Object.fromEntries(keys.map(key => [key, 1])),\n unique: true,\n // https://docs.mongodb.com/manual/core/index-partial/#std-label-partial-index-with-unique-constraints\n partialFilterExpression: Object.fromEntries(keys.map(key => [key, { $exists: true }])),\n })\n })\n if (!newSpecs.length) return\n await coll.createIndexes(newSpecs)\n }\n\n private async _createFields(name: string) {\n const { fields } = this.model.config[name]\n const coll = this.db.collection(name)\n await Promise.all(Object.keys(fields).map((key) => {\n if (isNullable(fields[key].initial)) return\n return coll.updateMany({ [key]: { $exists: false } }, { $set: { [key]: fields[key].initial } })\n }))\n }\n\n /** synchronize table schema */\n private async _syncTable(name: string) {\n await this._tableTasks[name]\n await this.db.createCollection(name).catch(noop)\n await Promise.all([\n this._createIndexes(name),\n this._createFields(name),\n ])\n }\n\n private _createFilter(name: keyof Tables, query: Query) {\n return transformQuery(this.resolveQuery(name, query))\n }\n\n async drop() {\n await Promise.all(Object.keys(this.model.config).map(name => this.db.dropCollection(name)))\n }\n\n private async _collStats() {\n const tables = Object.keys(this.model.config)\n const entries = await Promise.all(tables.map(async (name) => {\n const coll = this.db.collection(name)\n const { count, size } = await coll.stats()\n return [coll.collectionName, { count, size }] as const\n }))\n return Object.fromEntries(entries)\n }\n\n async stats() {\n // https://docs.mongodb.com/manual/reference/command/dbStats/#std-label-dbstats-output\n const [{ totalSize }, tables] = await Promise.all([\n this.db.stats(),\n this._collStats(),\n ])\n return { size: totalSize, tables }\n }\n\n async get(name: keyof Tables, query: Query, modifier: Modifier) {\n const filter = this._createFilter(name, query)\n if (!filter) return []\n await this._tableTasks[name]\n let cursor = this.db.collection(name).find(filter)\n const { fields, limit, offset = 0, sort } = this.resolveModifier(name, modifier)\n if (offset) cursor = cursor.skip(offset)\n if (limit) cursor = cursor.limit(offset + limit)\n if (sort) cursor = cursor.sort(sort)\n return (await cursor.toArray()).map(row => this.resolveData(name, row, fields)) as any\n }\n\n async set(name: keyof Tables, query: Query, update: {}) {\n const filter = this._createFilter(name, query)\n if (!filter) return\n await this._tableTasks[name]\n const { primary } = this.model.config[name]\n const indexFields = makeArray(primary)\n const coll = this.db.collection(name)\n const original = await coll.find(filter).toArray()\n if (!original.length) return\n update = this.model.format(name, update)\n const updateFields = new Set(Object.keys(update).map(key => key.split('.', 1)[0]))\n const bulk = coll.initializeUnorderedBulkOp()\n for (const item of original) {\n bulk.find(pick(item, indexFields)).updateOne({\n $set: pick(executeUpdate(item, update), updateFields),\n })\n }\n await bulk.execute()\n }\n\n async remove(name: keyof Tables, query: Query) {\n const filter = this._createFilter(name, query)\n if (!filter) return\n await this.db.collection(name).deleteMany(filter)\n }\n\n private queue(name: keyof Tables, callback: () => Promise<any>) {\n return this._tableTasks[name] = Promise.resolve(this._tableTasks[name]).catch(noop).then(callback)\n }\n\n async create<T extends keyof Tables>(name: T, data: any) {\n const coll = this.db.collection(name)\n return this.queue(name, async () => {\n const { primary, fields, autoInc } = this.model.config[name]\n if (autoInc && !Array.isArray(primary) && !(primary in data)) {\n const [latest] = await coll.find().sort(primary, -1).limit(1).toArray()\n data[primary] = latest ? +latest[primary] + 1 : 1\n if (Model.Field.string.includes(fields[primary].type)) {\n data[primary] += ''\n data[primary] = data[primary].padStart(8, '0')\n }\n }\n const copy = this.model.create(name, data)\n try {\n await coll.insertOne(copy)\n delete copy['_id']\n return copy\n } catch (err) {\n if (err instanceof MongoError && err.code === 11000) {\n throw new DriverError('duplicate-entry', err.message)\n }\n throw err\n }\n })\n }\n\n async upsert(name: keyof Tables, data: any[], keys: string | string[]) {\n if (!data.length) return\n if (!keys) keys = this.model.config[name].primary\n const indexFields = makeArray(keys)\n await this._tableTasks[name]\n const coll = this.db.collection(name)\n const original = await coll.find({ $or: data.map(item => pick(item, indexFields)) }).toArray()\n const bulk = coll.initializeUnorderedBulkOp()\n for (const _item of data) {\n const update = this.model.format(name, _item)\n const item = original.find(item => indexFields.every(key => item[key].valueOf() === update[key].valueOf()))\n if (item) {\n const updateFields = new Set(Object.keys(update).map(key => key.split('.', 1)[0]))\n const override = omit(pick(executeUpdate(item, update), updateFields), indexFields)\n bulk.find(pick(item, indexFields)).updateOne({ $set: override })\n } else {\n bulk.insert(executeUpdate(this.model.create(name), update))\n }\n }\n await bulk.execute()\n }\n\n eval(table: keyof Tables, expr: any, query: Query) {\n return new Promise<any>((resolve, reject) => {\n this._evalTasks.push({ expr, table, query, resolve, reject })\n process.nextTick(() => this._flushEvalTasks())\n })\n }\n\n private async _flushEvalTasks() {\n const tasks = this._evalTasks\n if (!tasks.length) return\n this._evalTasks = []\n\n const stages: any[] = [{ $match: { _id: null } }]\n for (const task of tasks) {\n const { expr, table, query } = task\n task.expr = transformEval(expr, (pipeline) => {\n const filter = this._createFilter(table, query) || { _id: null }\n pipeline.unshift({ $match: filter })\n stages.push({ $unionWith: { coll: table, pipeline } })\n })\n }\n\n let data: any\n try {\n const results = await this.db.collection('user').aggregate(stages).toArray()\n data = Object.assign({}, ...results)\n } catch (error) {\n tasks.forEach(task => task.reject(error))\n return\n }\n\n for (const { expr, resolve, reject } of tasks) {\n try {\n resolve(executeEval(data, expr))\n } catch (error) {\n reject(error)\n }\n }\n }\n}\n\nnamespace MongoDatabase {\n export const name = 'database-mongo'\n\n export interface Config {\n username?: string\n password?: string\n protocol?: string\n host?: string\n port?: number\n /** database name */\n database?: string\n /** default auth database */\n authDatabase?: string\n connectOptions?: ConstructorParameters<typeof URLSearchParams>[0]\n /** connection string (will overwrite all configs except 'name') */\n uri?: string\n }\n\n export const Config = Schema.object({\n protocol: Schema.string().description('要使用的协议名。').default('mongodb'),\n host: Schema.string().description('要连接到的主机名。').default('localhost'),\n port: Schema.natural().max(65535).description('要连接到的端口号。'),\n username: Schema.string().description('要使用的用户名。'),\n password: Schema.string().description('要使用的密码。').role('secret'),\n database: Schema.string().description('要访问的数据库名。').default('koishi'),\n })\n}\n\nexport default MongoDatabase\n", "import { Random, valueMap } from 'koishi'\nimport { Query } from '@koishijs/orm'\nimport { Filter, FilterOperators } from 'mongodb'\n\nfunction createFieldFilter(query: Query.FieldQuery, key: string) {\n const filters: Filter<any>[] = []\n const result: Filter<any> = {}\n const child = transformFieldQuery(query, key, filters)\n if (child === false) return false\n if (child !== true) result[key] = child\n if (filters.length) result.$and = filters\n if (Object.keys(result).length) return result\n return true\n}\n\nfunction transformFieldQuery(query: Query.FieldQuery, key: string, filters: Filter<any>[]) {\n // shorthand syntax\n if (typeof query === 'string' || typeof query === 'number' || query instanceof Date) {\n return { $eq: query }\n } else if (Array.isArray(query)) {\n if (!query.length) return false\n return { $in: query }\n } else if (query instanceof RegExp) {\n return { $regex: query }\n }\n\n // query operators\n const result: FilterOperators<any> = {}\n for (const prop in query) {\n if (prop === '$and') {\n for (const item of query[prop]) {\n const child = createFieldFilter(item, key)\n if (child === false) return false\n if (child !== true) filters.push(child)\n }\n } else if (prop === '$or') {\n const $or: Filter<any>[] = []\n if (!query[prop].length) return false\n const always = query[prop].some((item) => {\n const child = createFieldFilter(item, key)\n if (typeof child === 'boolean') return child\n $or.push(child)\n })\n if (!always) filters.push({ $or })\n } else if (prop === '$not') {\n const child = createFieldFilter(query[prop], key)\n if (child === true) return false\n if (child !== false) filters.push({ $nor: [child] })\n } else if (prop === '$el') {\n const child = transformFieldQuery(query[prop], key, filters)\n if (child === false) return false\n if (child !== true) result.$elemMatch = child\n } else if (prop === '$regexFor') {\n filters.push({\n $expr: {\n $function: {\n body: function (data: string, value: string) {\n return new RegExp(data, 'i').test(value)\n }.toString(),\n args: ['$' + key, query.$regexFor],\n lang: 'js',\n },\n },\n })\n } else {\n result[prop] = query[prop]\n }\n }\n if (!Object.keys(result).length) return true\n return result\n}\n\nexport function transformQuery(query: Query.Expr) {\n const filter: Filter<any> = {}\n const additional: Filter<any>[] = []\n for (const key in query) {\n const value = query[key]\n if (key === '$and' || key === '$or') {\n // MongoError: $and/$or/$nor must be a nonempty array\n // { $and: [] } matches everything\n // { $or: [] } matches nothing\n if (value.length) {\n filter[key] = value.map(transformQuery)\n } else if (key === '$or') {\n return\n }\n } else if (key === '$not') {\n // MongoError: unknown top level operator: $not\n // https://stackoverflow.com/questions/25270396/mongodb-how-to-invert-query-with-not\n // this may solve this problem but lead to performance degradation\n const query = transformQuery(value)\n if (query) filter.$nor = [query]\n } else if (key === '$expr') {\n additional.push({ $expr: transformEval(value) })\n } else {\n const query = transformFieldQuery(value, key, additional)\n if (query === false) return\n if (query !== true) filter[key] = query\n }\n }\n if (additional.length) {\n (filter.$and ||= []).push(...additional)\n }\n return filter\n}\n\nfunction transformEvalExpr(expr: any, onAggr?: (pipeline: any[]) => void) {\n return valueMap(expr as any, (value) => {\n if (Array.isArray(value)) {\n return value.map(val => transformEval(val, onAggr))\n } else {\n return transformEval(value, onAggr)\n }\n })\n}\n\nfunction transformAggr(expr: any) {\n if (typeof expr === 'string') {\n return '$' + expr\n }\n return transformEvalExpr(expr)\n}\n\nconst aggrKeys = ['$sum', '$avg', '$min', '$max', '$count']\n\nexport function transformEval(expr: any, onAggr?: (pipeline: any[]) => void) {\n if (typeof expr === 'number' || typeof expr === 'string' || typeof expr === 'boolean') {\n return expr\n } else if (expr.$) {\n return '$' + expr.$\n }\n\n for (const key of aggrKeys) {\n if (!expr[key]) continue\n const value = transformAggr(expr[key])\n const $ = Random.id()\n if (key === '$count') {\n onAggr([\n { $group: { _id: value } },\n { $group: { _id: null, [$]: { $count: {} } } },\n ])\n } else {\n onAggr([{ $group: { _id: null, [$]: { [key]: value } } }])\n }\n return { $ }\n }\n\n return transformEvalExpr(expr, onAggr)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/lib/utils.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
import { Query } from 'koishi';
|
|
1
|
+
import { Query } from '@koishijs/orm';
|
|
3
2
|
import { Filter } from 'mongodb';
|
|
4
3
|
export declare function transformQuery(query: Query.Expr): Filter<any>;
|
|
5
4
|
export declare function transformEval(expr: any, onAggr?: (pipeline: any[]) => void): any;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@koishijs/plugin-database-mongo",
|
|
3
3
|
"description": "MongoDB support for Koishi",
|
|
4
|
-
"version": "3.0
|
|
4
|
+
"version": "3.1.0",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"@koishijs/plugin-mock": "^1.0.3"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"koishi": "^4.
|
|
37
|
+
"koishi": "^4.5.0"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@koishijs/orm
|
|
40
|
+
"@koishijs/orm": "^1.0.0",
|
|
41
41
|
"mongodb": "^4.4.1"
|
|
42
42
|
}
|
|
43
43
|
}
|