@koishijs/plugin-database-mongo 3.0.0-beta.7 → 3.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/lib/index.d.ts CHANGED
@@ -7,9 +7,6 @@ declare module 'koishi' {
7
7
  interface Database {
8
8
  mongo: MongoDatabase;
9
9
  }
10
- interface Modules {
11
- 'database-mongo': typeof import('.');
12
- }
13
10
  }
14
11
  declare type TableType = keyof Tables;
15
12
  declare class MongoDatabase extends Database {
@@ -18,7 +15,8 @@ declare class MongoDatabase extends Database {
18
15
  client: MongoClient;
19
16
  db: Db;
20
17
  mongo: this;
21
- private tasks;
18
+ private _tableTasks;
19
+ private _evalTasks;
22
20
  constructor(ctx: Context, config: MongoDatabase.Config);
23
21
  private connectionStringFromConfig;
24
22
  start(): Promise<void>;
@@ -43,7 +41,8 @@ declare class MongoDatabase extends Database {
43
41
  private queue;
44
42
  create(name: TableType, data: any): Promise<any>;
45
43
  upsert(name: TableType, data: any[], keys: string | string[]): Promise<void>;
46
- aggregate(name: TableType, fields: {}, query: Query): Promise<any>;
44
+ eval(table: TableType, expr: any, query: Query): Promise<any>;
45
+ private _flushEvalTasks;
47
46
  }
48
47
  declare namespace MongoDatabase {
49
48
  const name = "database-mongo";
package/lib/index.js CHANGED
@@ -48,62 +48,123 @@ var import_orm_utils = __toModule(require("@koishijs/orm-utils"));
48
48
 
49
49
  // plugins/database/mongo/src/utils.ts
50
50
  var import_koishi = __toModule(require("koishi"));
51
- function transformFieldQuery(query, key) {
51
+ function createFieldFilter(query, key) {
52
+ const filters = [];
53
+ const result = {};
54
+ const child = transformFieldQuery(query, key, filters);
55
+ if (child === false)
56
+ return false;
57
+ if (child !== true)
58
+ result[key] = child;
59
+ if (filters.length)
60
+ result.$and = filters;
61
+ if (Object.keys(result).length)
62
+ return result;
63
+ return true;
64
+ }
65
+ __name(createFieldFilter, "createFieldFilter");
66
+ function transformFieldQuery(query, key, filters) {
52
67
  if (typeof query === "string" || typeof query === "number" || query instanceof Date) {
53
68
  return { $eq: query };
54
69
  } else if (Array.isArray(query)) {
55
70
  if (!query.length)
56
- return;
71
+ return false;
57
72
  return { $in: query };
58
73
  } else if (query instanceof RegExp) {
59
74
  return { $regex: query };
60
75
  }
61
76
  const result = {};
62
77
  for (const prop in query) {
63
- if (prop === "$el") {
64
- result.$elemMatch = transformFieldQuery(query[prop], key);
78
+ if (prop === "$and") {
79
+ for (const item of query[prop]) {
80
+ const child = createFieldFilter(item, key);
81
+ if (child === false)
82
+ return false;
83
+ if (child !== true)
84
+ filters.push(child);
85
+ }
86
+ } else if (prop === "$or") {
87
+ const $or = [];
88
+ if (!query[prop].length)
89
+ return false;
90
+ const always = query[prop].some((item) => {
91
+ const child = createFieldFilter(item, key);
92
+ if (typeof child === "boolean")
93
+ return child;
94
+ $or.push(child);
95
+ });
96
+ if (!always)
97
+ filters.push({ $or });
98
+ } else if (prop === "$not") {
99
+ const child = createFieldFilter(query[prop], key);
100
+ if (child === true)
101
+ return false;
102
+ if (child !== false)
103
+ filters.push({ $nor: [child] });
104
+ } else if (prop === "$el") {
105
+ const child = transformFieldQuery(query[prop], key, filters);
106
+ if (child === false)
107
+ return false;
108
+ if (child !== true)
109
+ result.$elemMatch = child;
65
110
  } else if (prop === "$regexFor") {
66
- result.$expr = {
67
- body(data, value) {
68
- return new RegExp(data, "i").test(value);
69
- },
70
- args: ["$" + key, query],
71
- lang: "js"
72
- };
111
+ filters.push({
112
+ $expr: {
113
+ $function: {
114
+ body: function(data, value) {
115
+ return new RegExp(data, "i").test(value);
116
+ }.toString(),
117
+ args: ["$" + key, query.$regexFor],
118
+ lang: "js"
119
+ }
120
+ }
121
+ });
73
122
  } else {
74
123
  result[prop] = query[prop];
75
124
  }
76
125
  }
126
+ if (!Object.keys(result).length)
127
+ return true;
77
128
  return result;
78
129
  }
79
130
  __name(transformFieldQuery, "transformFieldQuery");
80
131
  function transformQuery(query) {
81
132
  const filter = {};
133
+ const additional = [];
82
134
  for (const key in query) {
83
135
  const value = query[key];
84
136
  if (key === "$and" || key === "$or") {
85
137
  if (value.length) {
86
138
  filter[key] = value.map(transformQuery);
87
139
  } else if (key === "$or") {
88
- return { $nor: [{}] };
140
+ return;
89
141
  }
90
142
  } else if (key === "$not") {
91
- filter.$nor = [transformQuery(value)];
143
+ const query2 = transformQuery(value);
144
+ if (query2)
145
+ filter.$nor = [query2];
92
146
  } else if (key === "$expr") {
93
- filter[key] = transformEval(value);
147
+ additional.push({ $expr: transformEval(value) });
94
148
  } else {
95
- filter[key] = transformFieldQuery(value, key);
149
+ const query2 = transformFieldQuery(value, key, additional);
150
+ if (query2 === false)
151
+ return;
152
+ if (query2 !== true)
153
+ filter[key] = query2;
96
154
  }
97
155
  }
156
+ if (additional.length) {
157
+ (filter.$and || (filter.$and = [])).push(...additional);
158
+ }
98
159
  return filter;
99
160
  }
100
161
  __name(transformQuery, "transformQuery");
101
- function transformEvalExpr(expr, aggrs) {
102
- return (0, import_koishi.valueMap)(expr, (value, key) => {
162
+ function transformEvalExpr(expr, onAggr) {
163
+ return (0, import_koishi.valueMap)(expr, (value) => {
103
164
  if (Array.isArray(value)) {
104
- return value.map((val) => transformEval(val, aggrs));
165
+ return value.map((val) => transformEval(val, onAggr));
105
166
  } else {
106
- return transformEval(value, aggrs);
167
+ return transformEval(value, onAggr);
107
168
  }
108
169
  });
109
170
  }
@@ -116,7 +177,7 @@ function transformAggr(expr) {
116
177
  }
117
178
  __name(transformAggr, "transformAggr");
118
179
  var aggrKeys = ["$sum", "$avg", "$min", "$max", "$count"];
119
- function transformEval(expr, aggrs) {
180
+ function transformEval(expr, onAggr) {
120
181
  if (typeof expr === "number" || typeof expr === "string" || typeof expr === "boolean") {
121
182
  return expr;
122
183
  } else if (expr.$) {
@@ -126,18 +187,18 @@ function transformEval(expr, aggrs) {
126
187
  if (!expr[key])
127
188
  continue;
128
189
  const value = transformAggr(expr[key]);
129
- const $ = "temp" + aggrs.length;
190
+ const $ = import_koishi.Random.id();
130
191
  if (key === "$count") {
131
- aggrs.push([
192
+ onAggr([
132
193
  { $group: { _id: value } },
133
194
  { $group: { _id: null, [$]: { $count: {} } } }
134
195
  ]);
135
196
  } else {
136
- aggrs.push([{ $group: { _id: null, [$]: { [key]: value } } }]);
197
+ onAggr([{ $group: { _id: null, [$]: { [key]: value } } }]);
137
198
  }
138
199
  return { $ };
139
200
  }
140
- return transformEvalExpr(expr, aggrs);
201
+ return transformEvalExpr(expr, onAggr);
141
202
  }
142
203
  __name(transformEval, "transformEval");
143
204
 
@@ -148,7 +209,8 @@ var MongoDatabase = class extends import_koishi2.Database {
148
209
  this.ctx = ctx;
149
210
  this.config = config;
150
211
  this.mongo = this;
151
- this.tasks = {};
212
+ this._tableTasks = {};
213
+ this._evalTasks = [];
152
214
  }
153
215
  connectionStringFromConfig() {
154
216
  const { authDatabase, connectOptions, host, database: name, password, port, protocol, username } = this.config;
@@ -167,17 +229,17 @@ var MongoDatabase = class extends import_koishi2.Database {
167
229
  this.client = await import_mongodb.MongoClient.connect(mongourl);
168
230
  this.db = this.client.db(this.config.database);
169
231
  for (const name in this.ctx.model.config) {
170
- this.tasks[name] = this._syncTable(name);
232
+ this._tableTasks[name] = this._syncTable(name);
171
233
  }
172
234
  this.ctx.on("model", (name) => {
173
- this.tasks[name] = this._syncTable(name);
235
+ this._tableTasks[name] = this._syncTable(name);
174
236
  });
175
237
  }
176
238
  stop() {
177
239
  return this.client.close();
178
240
  }
179
241
  async _syncTable(name) {
180
- await this.tasks[name];
242
+ await this._tableTasks[name];
181
243
  const coll = await this.db.createCollection(name).catch(() => this.db.collection(name));
182
244
  const { primary, unique } = this.ctx.model.config[name];
183
245
  const newSpecs = [];
@@ -218,6 +280,8 @@ var MongoDatabase = class extends import_koishi2.Database {
218
280
  }
219
281
  async get(name, query, modifier) {
220
282
  const filter = this._createFilter(name, query);
283
+ if (!filter)
284
+ return [];
221
285
  let cursor = this.db.collection(name).find(filter);
222
286
  const { fields, limit, offset = 0, sort } = import_koishi2.Query.resolveModifier(modifier);
223
287
  cursor = cursor.project(__spreadValues({ _id: 0 }, Object.fromEntries((fields != null ? fields : []).map((key) => [key, 1]))));
@@ -230,11 +294,13 @@ var MongoDatabase = class extends import_koishi2.Database {
230
294
  return await cursor.toArray();
231
295
  }
232
296
  async set(name, query, update) {
233
- await this.tasks[name];
297
+ const filter = this._createFilter(name, query);
298
+ if (!filter)
299
+ return;
300
+ await this._tableTasks[name];
234
301
  const { primary } = this.ctx.model.config[name];
235
302
  const indexFields = (0, import_koishi2.makeArray)(primary);
236
303
  const updateFields = new Set(Object.keys(update).map((key) => key.split(".", 1)[0]));
237
- const filter = this._createFilter(name, query);
238
304
  const coll = this.db.collection(name);
239
305
  const original = await coll.find(filter).toArray();
240
306
  if (!original.length)
@@ -247,10 +313,12 @@ var MongoDatabase = class extends import_koishi2.Database {
247
313
  }
248
314
  async remove(name, query) {
249
315
  const filter = this._createFilter(name, query);
316
+ if (!filter)
317
+ return;
250
318
  await this.db.collection(name).deleteMany(filter);
251
319
  }
252
320
  queue(name, callback) {
253
- return this.tasks[name] = Promise.resolve(this.tasks[name]).catch(import_koishi2.noop).then(callback);
321
+ return this._tableTasks[name] = Promise.resolve(this._tableTasks[name]).catch(import_koishi2.noop).then(callback);
254
322
  }
255
323
  async create(name, data) {
256
324
  const coll = this.db.collection(name);
@@ -261,6 +329,7 @@ var MongoDatabase = class extends import_koishi2.Database {
261
329
  data[primary] = latest ? +latest[primary] + 1 : 1;
262
330
  if (import_koishi2.Model.Field.string.includes(fields[primary].type)) {
263
331
  data[primary] += "";
332
+ data[primary] = data[primary].padStart(8, "0");
264
333
  }
265
334
  }
266
335
  const copy = __spreadValues(__spreadValues({}, this.ctx.model.create(name)), data);
@@ -282,7 +351,7 @@ var MongoDatabase = class extends import_koishi2.Database {
282
351
  if (!keys)
283
352
  keys = this.ctx.model.config[name].primary;
284
353
  const indexFields = (0, import_koishi2.makeArray)(keys);
285
- await this.tasks[name];
354
+ await this._tableTasks[name];
286
355
  const coll = this.db.collection(name);
287
356
  const original = await coll.find({ $or: data.map((item) => (0, import_koishi2.pick)(item, indexFields)) }).toArray();
288
357
  const bulk = coll.initializeUnorderedBulkOp();
@@ -298,20 +367,41 @@ var MongoDatabase = class extends import_koishi2.Database {
298
367
  }
299
368
  await bulk.execute();
300
369
  }
301
- async aggregate(name, fields, query) {
302
- if (!Object.keys(fields).length)
303
- return {};
304
- const $match = this._createFilter(name, query);
305
- const aggrs = [];
306
- fields = (0, import_koishi2.valueMap)(fields, (value) => transformEval(value, aggrs));
307
- const stages = aggrs.map((pipeline) => {
308
- pipeline.unshift({ $match });
309
- return { $unionWith: { coll: name, pipeline } };
370
+ eval(table, expr, query) {
371
+ return new Promise((resolve, reject) => {
372
+ this._evalTasks.push({ expr, table, query, resolve, reject });
373
+ process.nextTick(() => this._flushEvalTasks());
310
374
  });
311
- stages.unshift({ $match: { _id: null } });
312
- const results = await this.db.collection(name).aggregate(stages).toArray();
313
- const data = Object.assign({}, ...results);
314
- return (0, import_koishi2.valueMap)(fields, (value) => (0, import_orm_utils.executeEval)(data, value));
375
+ }
376
+ async _flushEvalTasks() {
377
+ const tasks = this._evalTasks;
378
+ if (!tasks.length)
379
+ return;
380
+ this._evalTasks = [];
381
+ const stages = [{ $match: { _id: null } }];
382
+ for (const task of tasks) {
383
+ const { expr, table, query } = task;
384
+ task.expr = transformEval(expr, (pipeline) => {
385
+ const filter = this._createFilter(table, query) || { _id: null };
386
+ pipeline.unshift({ $match: filter });
387
+ stages.push({ $unionWith: { coll: table, pipeline } });
388
+ });
389
+ }
390
+ let data;
391
+ try {
392
+ const results = await this.db.collection("user").aggregate(stages).toArray();
393
+ data = Object.assign({}, ...results);
394
+ } catch (error) {
395
+ tasks.forEach((task) => task.reject(error));
396
+ return;
397
+ }
398
+ for (const { expr, resolve, reject } of tasks) {
399
+ try {
400
+ resolve((0, import_orm_utils.executeEval)(data, expr));
401
+ } catch (error) {
402
+ reject(error);
403
+ }
404
+ }
315
405
  }
316
406
  };
317
407
  __name(MongoDatabase, "MongoDatabase");
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 { MongoClient, Db, MongoError, IndexDescription } from 'mongodb'\nimport { Context, Database, Tables, makeArray, Schema, pick, omit, Query, Model, Dict, noop, KoishiError, valueMap } from 'koishi'\nimport { URLSearchParams } from 'url'\nimport { executeUpdate, executeEval } from '@koishijs/orm-utils'\nimport { transformQuery, transformEval } from './utils'\n\ndeclare module 'koishi' {\n interface Database {\n mongo: MongoDatabase\n }\n\n interface Modules {\n 'database-mongo': typeof import('.')\n }\n}\n\ntype TableType = keyof Tables\n\nclass MongoDatabase extends Database {\n public client: MongoClient\n public db: Db\n public mongo = this\n private tasks: Dict<Promise<any>> = {}\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.tasks[name] = this._syncTable(name)\n }\n\n this.ctx.on('model', (name) => {\n this.tasks[name] = this._syncTable(name)\n })\n }\n\n stop() {\n return this.client.close()\n }\n\n /** synchronize table schema */\n private async _syncTable(name: string) {\n await this.tasks[name]\n const coll = await this.db.createCollection(name).catch(() => this.db.collection(name))\n const { primary, unique } = this.ctx.model.config[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 const key = Object.fromEntries(keys.map(key => [key, 1]))\n newSpecs.push({ name, key, unique: true })\n })\n if (!newSpecs.length) return\n await coll.createIndexes(newSpecs)\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 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 await this.tasks[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 filter = this._createFilter(name, query)\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 await this.db.collection(name).deleteMany(filter)\n }\n\n private queue(name: TableType, callback: () => Promise<any>) {\n return this.tasks[name] = Promise.resolve(this.tasks[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 }\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.tasks[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 async aggregate(name: TableType, fields: {}, query: Query) {\n if (!Object.keys(fields).length) return {}\n const $match = this._createFilter(name, query)\n const aggrs: any[][] = []\n fields = valueMap(fields, value => transformEval(value, aggrs))\n const stages = aggrs.map<any>((pipeline) => {\n pipeline.unshift({ $match })\n return { $unionWith: { coll: name, pipeline } }\n })\n stages.unshift({ $match: { _id: null } })\n const results = await this.db.collection(name).aggregate(stages).toArray()\n const data = Object.assign({}, ...results)\n return valueMap(fields, value => executeEval(data, value)) as any\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.number().description('要连接到的端口号。'),\n username: Schema.string().description('要使用的用户名。'),\n password: Schema.string().description('要使用的密码。'),\n database: Schema.string().description('要访问的数据库名。').default('koishi'),\n })\n}\n\nexport default MongoDatabase\n", "import { Query, valueMap } from 'koishi'\nimport { Filter, FilterOperators } from 'mongodb'\n\nfunction transformFieldQuery(query: Query.FieldQuery, key: string) {\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\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 === '$el') {\n result.$elemMatch = transformFieldQuery(query[prop], key)\n } else if (prop === '$regexFor') {\n result.$expr = {\n body(data: string, value: string) {\n return new RegExp(data, 'i').test(value)\n },\n args: ['$' + key, query],\n lang: 'js',\n }\n } else {\n result[prop] = query[prop]\n }\n }\n return result\n}\n\nexport function transformQuery(query: Query.Expr) {\n const filter: 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 if (value.length) {\n filter[key] = value.map(transformQuery)\n } else if (key === '$or') {\n return { $nor: [{}] }\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 filter.$nor = [transformQuery(value)]\n } else if (key === '$expr') {\n filter[key] = transformEval(value)\n } else {\n filter[key] = transformFieldQuery(value, key)\n }\n }\n return filter\n}\n\nfunction transformEvalExpr(expr: any, aggrs?: any[][]) {\n return valueMap(expr as any, (value, key) => {\n if (Array.isArray(value)) {\n return value.map(val => transformEval(val, aggrs))\n } else {\n return transformEval(value, aggrs)\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, aggrs?: any[][]) {\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 $ = 'temp' + aggrs.length\n if (key === '$count') {\n aggrs.push([\n { $group: { _id: value } },\n { $group: { _id: null, [$]: { $count: {} } } }\n ])\n } else {\n aggrs.push([{ $group: { _id: null, [$]: { [key]: value } } }])\n }\n return { $ }\n }\n\n return transformEvalExpr(expr, aggrs)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { MongoClient, Db, MongoError, IndexDescription } from 'mongodb'\nimport { Context, Database, Tables, makeArray, Schema, pick, omit, Query, Model, Dict, noop, KoishiError } from 'koishi'\nimport { URLSearchParams } from 'url'\nimport { executeUpdate, executeEval } from '@koishijs/orm-utils'\nimport { transformQuery, transformEval } 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 /** synchronize table schema */\n private async _syncTable(name: string) {\n await this._tableTasks[name]\n const coll = await this.db.createCollection(name).catch(() => this.db.collection(name))\n const { primary, unique } = this.ctx.model.config[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 const key = Object.fromEntries(keys.map(key => [key, 1]))\n newSpecs.push({ name, key, unique: true })\n })\n if (!newSpecs.length) return\n await coll.createIndexes(newSpecs)\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 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.number().description('要连接到的端口号。'),\n username: Schema.string().description('要使用的用户名。'),\n password: Schema.string().description('要使用的密码。'),\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": "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",
6
6
  "names": []
7
7
  }
package/lib/utils.d.ts CHANGED
@@ -2,4 +2,4 @@
2
2
  import { Query } from 'koishi';
3
3
  import { Filter } from 'mongodb';
4
4
  export declare function transformQuery(query: Query.Expr): Filter<any>;
5
- export declare function transformEval(expr: any, aggrs?: any[][]): any;
5
+ 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.0-beta.7",
4
+ "version": "3.0.1",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -32,14 +32,14 @@
32
32
  "mysql"
33
33
  ],
34
34
  "devDependencies": {
35
- "@koishijs/plugin-mock": "^1.0.0-beta.2",
36
- "@koishijs/test-utils": "^8.0.0-beta.6"
35
+ "@koishijs/database-tests": "^1.0.0",
36
+ "@koishijs/plugin-mock": "^1.0.0"
37
37
  },
38
38
  "peerDependencies": {
39
- "koishi": "^4.0.0-beta.7"
39
+ "koishi": "^4.0.1"
40
40
  },
41
41
  "dependencies": {
42
- "@koishijs/orm-utils": "^1.0.0-beta.5",
43
- "mongodb": "^4.2.2"
42
+ "@koishijs/orm-utils": "^1.0.0",
43
+ "mongodb": "^4.3.0"
44
44
  }
45
45
  }