@e22m4u/js-repository-mongodb-adapter 0.0.18 → 0.0.19

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e22m4u/js-repository-mongodb-adapter",
3
- "version": "0.0.18",
3
+ "version": "0.0.19",
4
4
  "description": "MongoDB адаптер для @e22m4u/js-repository",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -38,7 +38,7 @@
38
38
  "peerDependencies": {
39
39
  "@e22m4u/js-format": "*",
40
40
  "@e22m4u/js-service": "*",
41
- "@e22m4u/js-repository": "~0.0.33"
41
+ "@e22m4u/js-repository": "~0.0.34"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@commitlint/cli": "^17.7.1",
@@ -267,14 +267,15 @@ export class MongodbAdapter extends Adapter {
267
267
  * @private
268
268
  */
269
269
  _buildProjection(modelName, fields) {
270
- if (!fields) return;
271
- fields = Array.isArray(fields) ? fields : [fields];
270
+ if (fields == null) return;
271
+ if (Array.isArray(fields) === false) fields = [fields];
272
272
  if (!fields.length) return;
273
273
  if (fields.indexOf('_id') === -1) fields.push('_id');
274
274
  return fields.reduce((acc, field) => {
275
275
  if (!field || typeof field !== 'string')
276
276
  throw new InvalidArgumentError(
277
- 'A field name must be a non-empty String, but %v given.',
277
+ 'The provided option "fields" should be a non-empty String ' +
278
+ 'or an Array of non-empty String, but %v given.',
278
279
  field,
279
280
  );
280
281
  let colName = this._getColName(modelName, field);
@@ -321,24 +322,25 @@ export class MongodbAdapter extends Adapter {
321
322
  * @private
322
323
  */
323
324
  _buildSort(modelName, clause) {
324
- if (!clause) return;
325
- clause = Array.isArray(clause) ? clause : [clause];
325
+ if (clause == null) return;
326
+ if (Array.isArray(clause) === false) clause = [clause];
326
327
  if (!clause.length) return;
327
328
  const utils = this.getService(ModelDefinitionUtils);
328
329
  const idPropName = this._getIdPropName(modelName);
329
330
  return clause.reduce((acc, order) => {
330
331
  if (!order || typeof order !== 'string')
331
332
  throw new InvalidArgumentError(
332
- 'A field order must be a non-empty String, but %v given.',
333
+ 'The provided option "order" should be a non-empty String ' +
334
+ 'or an Array of non-empty String, but %v given.',
333
335
  order,
334
336
  );
335
337
  const direction = order.match(/\s+(A|DE)SC$/);
336
- let key = order.replace(/\s+(A|DE)SC$/, '').trim();
337
- if (key === idPropName) {
338
- key = '_id';
338
+ let field = order.replace(/\s+(A|DE)SC$/, '').trim();
339
+ if (field === idPropName) {
340
+ field = '_id';
339
341
  } else {
340
342
  try {
341
- key = utils.getColumnNameByPropertyName(modelName, key);
343
+ field = utils.getColumnNameByPropertyName(modelName, field);
342
344
  } catch (error) {
343
345
  if (
344
346
  !(error instanceof InvalidArgumentError) ||
@@ -348,7 +350,7 @@ export class MongodbAdapter extends Adapter {
348
350
  }
349
351
  }
350
352
  }
351
- acc[key] = direction && direction[1] === 'DE' ? -1 : 1;
353
+ acc[field] = direction && direction[1] === 'DE' ? -1 : 1;
352
354
  return acc;
353
355
  }, {});
354
356
  }
@@ -41,6 +41,356 @@ describe('MongodbAdapter', function () {
41
41
  await MDB_CLIENT.close(true);
42
42
  });
43
43
 
44
+ describe('_buildProjection', function () {
45
+ describe('single field', function () {
46
+ it('returns undefined if the second argument is undefined', async function () {
47
+ const schema = createSchema();
48
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
49
+ const A = await schema
50
+ .getService(AdapterRegistry)
51
+ .getAdapter('mongodb');
52
+ const res = A._buildProjection('model', undefined);
53
+ expect(res).to.be.undefined;
54
+ });
55
+
56
+ it('returns undefined if the second argument is null', async function () {
57
+ const schema = createSchema();
58
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
59
+ const A = await schema
60
+ .getService(AdapterRegistry)
61
+ .getAdapter('mongodb');
62
+ const res = A._buildProjection('model', null);
63
+ expect(res).to.be.undefined;
64
+ });
65
+
66
+ it('requires the second argument to be a non-empty string', async function () {
67
+ const schema = createSchema();
68
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
69
+ const A = await schema
70
+ .getService(AdapterRegistry)
71
+ .getAdapter('mongodb');
72
+ const throwable = v => () => A._buildProjection('model', v);
73
+ const error = v =>
74
+ format(
75
+ 'The provided option "fields" should be a non-empty String ' +
76
+ 'or an Array of non-empty String, but %s given.',
77
+ v,
78
+ );
79
+ expect(throwable('')).to.throw(error('""'));
80
+ expect(throwable(10)).to.throw(error('10'));
81
+ expect(throwable(0)).to.throw(error('0'));
82
+ expect(throwable(true)).to.throw(error('true'));
83
+ expect(throwable(false)).to.throw(error('false'));
84
+ expect(throwable({})).to.throw(error('Object'));
85
+ expect(throwable('bar')()).to.be.eql({_id: 1, bar: 1});
86
+ expect(throwable(undefined)()).to.be.undefined;
87
+ expect(throwable(null)()).to.be.undefined;
88
+ });
89
+
90
+ it('converts the given property name to the column name', async function () {
91
+ const schema = createSchema();
92
+ schema.defineModel({
93
+ name: 'model',
94
+ datasource: 'mongodb',
95
+ properties: {
96
+ foo: {
97
+ type: DataType.STRING,
98
+ columnName: 'bar',
99
+ },
100
+ },
101
+ });
102
+ const A = await schema
103
+ .getService(AdapterRegistry)
104
+ .getAdapter('mongodb');
105
+ const res = A._buildProjection('model', 'foo');
106
+ expect(res).to.be.eql({_id: 1, bar: 1});
107
+ });
108
+
109
+ it('includes "_id" field to the projection', async function () {
110
+ const schema = createSchema();
111
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
112
+ const A = await schema
113
+ .getService(AdapterRegistry)
114
+ .getAdapter('mongodb');
115
+ const res = A._buildProjection('model', 'foo');
116
+ expect(res).to.be.eql({_id: 1, foo: 1});
117
+ });
118
+
119
+ it('includes "_id" as a column name of the given property', async function () {
120
+ const schema = createSchema();
121
+ schema.defineModel({
122
+ name: 'model',
123
+ datasource: 'mongodb',
124
+ properties: {
125
+ foo: {
126
+ type: DataType.STRING,
127
+ primaryKey: true,
128
+ columnName: '_id',
129
+ },
130
+ },
131
+ });
132
+ const A = await schema
133
+ .getService(AdapterRegistry)
134
+ .getAdapter('mongodb');
135
+ const res = A._buildProjection('model', 'foo');
136
+ expect(res).to.be.eql({_id: 1});
137
+ });
138
+ });
139
+
140
+ describe('multiple fields', function () {
141
+ it('returns undefined if the second argument is an empty array', async function () {
142
+ const schema = createSchema();
143
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
144
+ const A = await schema
145
+ .getService(AdapterRegistry)
146
+ .getAdapter('mongodb');
147
+ const res = A._buildProjection('model', []);
148
+ expect(res).to.be.undefined;
149
+ });
150
+
151
+ it('requires the second argument to be an array of non-empty strings', async function () {
152
+ const schema = createSchema();
153
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
154
+ const A = await schema
155
+ .getService(AdapterRegistry)
156
+ .getAdapter('mongodb');
157
+ const throwable = v => () => A._buildProjection('model', v);
158
+ const error = v =>
159
+ format(
160
+ 'The provided option "fields" should be a non-empty String ' +
161
+ 'or an Array of non-empty String, but %s given.',
162
+ v,
163
+ );
164
+ expect(throwable([''])).to.throw(error('""'));
165
+ expect(throwable([10])).to.throw(error('10'));
166
+ expect(throwable([0])).to.throw(error('0'));
167
+ expect(throwable([true])).to.throw(error('true'));
168
+ expect(throwable([false])).to.throw(error('false'));
169
+ expect(throwable([{}])).to.throw(error('Object'));
170
+ expect(throwable([undefined])).to.throw(error('undefined'));
171
+ expect(throwable([null])).to.throw(error('null'));
172
+ expect(throwable([])()).to.be.undefined;
173
+ expect(throwable(['bar'])()).to.be.eql({_id: 1, bar: 1});
174
+ });
175
+
176
+ it('converts the given property names to column names', async function () {
177
+ const schema = createSchema();
178
+ schema.defineModel({
179
+ name: 'model',
180
+ datasource: 'mongodb',
181
+ properties: {
182
+ foo: {
183
+ type: DataType.STRING,
184
+ columnName: 'bar',
185
+ },
186
+ baz: {
187
+ type: DataType.STRING,
188
+ columnName: 'qux',
189
+ },
190
+ },
191
+ });
192
+ const A = await schema
193
+ .getService(AdapterRegistry)
194
+ .getAdapter('mongodb');
195
+ const res = A._buildProjection('model', ['foo', 'baz']);
196
+ expect(res).to.be.eql({_id: 1, bar: 1, qux: 1});
197
+ });
198
+
199
+ it('includes "_id" field to the projection', async function () {
200
+ const schema = createSchema();
201
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
202
+ const A = await schema
203
+ .getService(AdapterRegistry)
204
+ .getAdapter('mongodb');
205
+ const res = A._buildProjection('model', ['foo', 'bar']);
206
+ expect(res).to.be.eql({_id: 1, foo: 1, bar: 1});
207
+ });
208
+
209
+ it('includes "_id" as a column name of the given property', async function () {
210
+ const schema = createSchema();
211
+ schema.defineModel({
212
+ name: 'model',
213
+ datasource: 'mongodb',
214
+ properties: {
215
+ foo: {
216
+ type: DataType.STRING,
217
+ primaryKey: true,
218
+ columnName: '_id',
219
+ },
220
+ },
221
+ });
222
+ const A = await schema
223
+ .getService(AdapterRegistry)
224
+ .getAdapter('mongodb');
225
+ const res = A._buildProjection('model', ['foo', 'bar']);
226
+ expect(res).to.be.eql({_id: 1, bar: 1});
227
+ });
228
+ });
229
+ });
230
+
231
+ describe('_buildSort', function () {
232
+ describe('single field', function () {
233
+ it('returns undefined if the second argument is undefined', async function () {
234
+ const schema = createSchema();
235
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
236
+ const A = await schema
237
+ .getService(AdapterRegistry)
238
+ .getAdapter('mongodb');
239
+ const res = A._buildSort('model', undefined);
240
+ expect(res).to.be.undefined;
241
+ });
242
+
243
+ it('returns undefined if the second argument is null', async function () {
244
+ const schema = createSchema();
245
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
246
+ const A = await schema
247
+ .getService(AdapterRegistry)
248
+ .getAdapter('mongodb');
249
+ const res = A._buildSort('model', null);
250
+ expect(res).to.be.undefined;
251
+ });
252
+
253
+ it('requires the second argument to be a non-empty string', async function () {
254
+ const schema = createSchema();
255
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
256
+ const A = await schema
257
+ .getService(AdapterRegistry)
258
+ .getAdapter('mongodb');
259
+ const throwable = v => () => A._buildSort('model', v);
260
+ const error = v =>
261
+ format(
262
+ 'The provided option "order" should be a non-empty String ' +
263
+ 'or an Array of non-empty String, but %s given.',
264
+ v,
265
+ );
266
+ expect(throwable('')).to.throw(error('""'));
267
+ expect(throwable(10)).to.throw(error('10'));
268
+ expect(throwable(0)).to.throw(error('0'));
269
+ expect(throwable(true)).to.throw(error('true'));
270
+ expect(throwable(false)).to.throw(error('false'));
271
+ expect(throwable({})).to.throw(error('Object'));
272
+ expect(throwable('bar')()).to.be.eql({bar: 1});
273
+ expect(throwable(undefined)()).to.be.undefined;
274
+ expect(throwable(null)()).to.be.undefined;
275
+ });
276
+
277
+ it('recognizes direction by the given direction flag', async function () {
278
+ const schema = createSchema();
279
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
280
+ const A = await schema
281
+ .getService(AdapterRegistry)
282
+ .getAdapter('mongodb');
283
+ const res1 = A._buildSort('model', 'foo');
284
+ const res2 = A._buildSort('model', 'foo DESC');
285
+ const res3 = A._buildSort('model', 'foo ASC');
286
+ expect(res1).to.be.eql({foo: 1});
287
+ expect(res2).to.be.eql({foo: -1});
288
+ expect(res3).to.be.eql({foo: 1});
289
+ });
290
+
291
+ it('converts the given property name to the column name', async function () {
292
+ const schema = createSchema();
293
+ schema.defineModel({
294
+ name: 'model',
295
+ datasource: 'mongodb',
296
+ properties: {
297
+ foo: {
298
+ type: DataType.STRING,
299
+ columnName: 'bar',
300
+ },
301
+ },
302
+ });
303
+ const A = await schema
304
+ .getService(AdapterRegistry)
305
+ .getAdapter('mongodb');
306
+ const res1 = A._buildSort('model', 'foo');
307
+ const res2 = A._buildSort('model', 'foo DESC');
308
+ const res3 = A._buildSort('model', 'foo ASC');
309
+ expect(res1).to.be.eql({bar: 1});
310
+ expect(res2).to.be.eql({bar: -1});
311
+ expect(res3).to.be.eql({bar: 1});
312
+ });
313
+ });
314
+
315
+ describe('multiple fields', function () {
316
+ it('returns undefined if the second argument is an empty array', async function () {
317
+ const schema = createSchema();
318
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
319
+ const A = await schema
320
+ .getService(AdapterRegistry)
321
+ .getAdapter('mongodb');
322
+ const res = A._buildSort('model', []);
323
+ expect(res).to.be.undefined;
324
+ });
325
+
326
+ it('requires the second argument to be an array of non-empty strings', async function () {
327
+ const schema = createSchema();
328
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
329
+ const A = await schema
330
+ .getService(AdapterRegistry)
331
+ .getAdapter('mongodb');
332
+ const throwable = v => () => A._buildSort('model', v);
333
+ const error = v =>
334
+ format(
335
+ 'The provided option "order" should be a non-empty String ' +
336
+ 'or an Array of non-empty String, but %s given.',
337
+ v,
338
+ );
339
+ expect(throwable([''])).to.throw(error('""'));
340
+ expect(throwable([10])).to.throw(error('10'));
341
+ expect(throwable([0])).to.throw(error('0'));
342
+ expect(throwable([true])).to.throw(error('true'));
343
+ expect(throwable([false])).to.throw(error('false'));
344
+ expect(throwable([{}])).to.throw(error('Object'));
345
+ expect(throwable([undefined])).to.throw(error('undefined'));
346
+ expect(throwable([null])).to.throw(error('null'));
347
+ expect(throwable([])()).to.be.undefined;
348
+ expect(throwable(['bar', 'baz'])()).to.be.eql({bar: 1, baz: 1});
349
+ });
350
+
351
+ it('recognizes direction by the given direction flag', async function () {
352
+ const schema = createSchema();
353
+ schema.defineModel({name: 'model', datasource: 'mongodb'});
354
+ const A = await schema
355
+ .getService(AdapterRegistry)
356
+ .getAdapter('mongodb');
357
+ const res1 = A._buildSort('model', ['foo', 'bar']);
358
+ const res2 = A._buildSort('model', ['foo DESC', 'bar ASC']);
359
+ const res3 = A._buildSort('model', ['foo ASC', 'bar DESC']);
360
+ expect(res1).to.be.eql({foo: 1, bar: 1});
361
+ expect(res2).to.be.eql({foo: -1, bar: 1});
362
+ expect(res3).to.be.eql({foo: 1, bar: -1});
363
+ });
364
+
365
+ it('converts the given property names to column names', async function () {
366
+ const schema = createSchema();
367
+ schema.defineModel({
368
+ name: 'model',
369
+ datasource: 'mongodb',
370
+ properties: {
371
+ foo: {
372
+ type: DataType.STRING,
373
+ columnName: 'bar',
374
+ },
375
+ baz: {
376
+ type: DataType.STRING,
377
+ columnName: 'qux',
378
+ },
379
+ },
380
+ });
381
+ const A = await schema
382
+ .getService(AdapterRegistry)
383
+ .getAdapter('mongodb');
384
+ const res1 = A._buildSort('model', ['foo', 'baz']);
385
+ const res2 = A._buildSort('model', ['foo DESC', 'baz ASC']);
386
+ const res3 = A._buildSort('model', ['foo ASC', 'baz DESC']);
387
+ expect(res1).to.be.eql({bar: 1, qux: 1});
388
+ expect(res2).to.be.eql({bar: -1, qux: 1});
389
+ expect(res3).to.be.eql({bar: 1, qux: -1});
390
+ });
391
+ });
392
+ });
393
+
44
394
  describe('create', function () {
45
395
  it('generates a new identifier when a value of a primary key is not provided', async function () {
46
396
  const schema = createSchema();