@opra/mongodb 0.33.13 → 1.0.0-alpha.2

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.
@@ -1,14 +1,14 @@
1
1
  import { ObjectId } from 'mongodb';
2
- import { InternalServerError, ResourceNotAvailableError } from '@opra/common';
2
+ import { ResourceNotAvailableError } from '@opra/common';
3
3
  import { MongoAdapter } from './mongo-adapter.js';
4
- import { MongoService } from './mongo-service.js';
4
+ import { MongoEntityService } from './mongo-entity-service.js';
5
5
  /**
6
6
  * A class that provides access to a MongoDB collection, with support for singleton document operations.
7
7
  * @class MongoSingletonService
8
8
  * @extends MongoService
9
9
  * @template T - The type of document stored in the collection
10
10
  */
11
- export class MongoSingletonService extends MongoService {
11
+ export class MongoSingletonService extends MongoEntityService {
12
12
  /**
13
13
  * Constructs a new instance
14
14
  *
@@ -18,14 +18,12 @@ export class MongoSingletonService extends MongoService {
18
18
  */
19
19
  constructor(dataType, options) {
20
20
  super(dataType, options);
21
- this.collectionKey = this.collectionKey || options?.collectionKey || '_id';
22
21
  this._id = this._id || options?._id || new ObjectId('655608925cad472b75fc6485');
23
- this.$documentFilter = this.$documentFilter || options?.documentFilter;
24
- this.$interceptor = this.$interceptor || options?.interceptor;
25
22
  }
26
23
  /**
27
24
  * Asserts the existence of a resource based on the given options.
28
25
  *
26
+ * @param {MongoSingletonService.ExistsOptions<T>} [options]
29
27
  * @returns {Promise<void>} A Promise that resolves when the resource exists.
30
28
  * @throws {ResourceNotAvailableError} If the resource does not exist.
31
29
  */
@@ -36,37 +34,23 @@ export class MongoSingletonService extends MongoService {
36
34
  /**
37
35
  * Creates the document in the database.
38
36
  *
39
- * @param {DTO<T>} input - The partial input to create the document with.
37
+ * @param {PartialDTO<T>} input - The partial input to create the document with.
40
38
  * @param {MongoSingletonService.CreateOptions} [options] - The options for creating the document.
41
39
  * @return {Promise<PartialDTO<T>>} A promise that resolves to the partial output of the created document.
42
40
  * @throws {Error} Throws an error if an unknown error occurs while creating the document.
43
41
  */
44
42
  async create(input, options) {
43
+ input._id = this._id;
45
44
  const info = {
46
45
  crud: 'create',
47
46
  method: 'create',
47
+ byId: false,
48
+ documentId: this._id,
48
49
  input,
49
50
  options,
50
51
  };
51
52
  return this._intercept(() => this._create(input, options), info);
52
53
  }
53
- async _create(input, options) {
54
- const encode = this.getEncoder('create');
55
- const doc = encode(input);
56
- doc._id = this._id;
57
- const r = await this.__insertOne(doc, options);
58
- if (r.insertedId) {
59
- if (!options)
60
- return doc;
61
- const out = await this._findOne(options);
62
- if (out)
63
- return out;
64
- if (!out)
65
- throw new ResourceNotAvailableError(this.getResourceName());
66
- }
67
- /* istanbul ignore next */
68
- throw new InternalServerError(`Unknown error while creating document for "${this.getResourceName()}"`);
69
- }
70
54
  /**
71
55
  * Deletes a record from the database
72
56
  *
@@ -77,77 +61,51 @@ export class MongoSingletonService extends MongoService {
77
61
  const info = {
78
62
  crud: 'delete',
79
63
  method: 'delete',
64
+ byId: true,
65
+ documentId: this._id,
80
66
  options,
81
67
  };
82
68
  return this._intercept(async () => {
83
- const filter = MongoAdapter.prepareFilter([
84
- await this._getDocumentFilter(info),
85
- options?.filter
86
- ]);
87
- return this._delete({ ...options, filter });
69
+ const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
70
+ return this._delete(this._id, { ...options, filter });
88
71
  }, info);
89
72
  }
90
- async _delete(options) {
91
- const filter = MongoAdapter.prepareFilter([
92
- { _id: this._id },
93
- options?.filter
94
- ]);
95
- const r = await this.__deleteOne(filter, options);
96
- return r.deletedCount;
97
- }
98
73
  /**
99
74
  * Checks if the document exists in the database.
100
75
  *
101
76
  * @return {Promise<boolean>} - A promise that resolves to a boolean value indicating if the document exists.
102
77
  */
103
78
  async exists(options) {
104
- return !!(await this.findOne({ ...options, pick: ['_id'], omit: undefined, include: undefined }));
79
+ return !!(await this.find({ ...options, projection: ['_id'], skip: undefined }));
105
80
  }
106
81
  /**
107
82
  * Fetches the document if it exists. Returns undefined if not found.
108
83
  *
109
- * @param {MongoSingletonService.FindOptions<T>} [options] - The options for finding the document.
84
+ * @param {MongoSingletonService.FindOneOptions<T>} [options] - The options for finding the document.
110
85
  * @returns {Promise<PartialDTO<T> | undefined>} - A promise that resolves to the found document or undefined if not found.
111
86
  */
112
- async findOne(options) {
87
+ async find(options) {
113
88
  const info = {
114
89
  crud: 'read',
115
90
  method: 'findOne',
91
+ byId: true,
92
+ documentId: this._id,
116
93
  options,
117
94
  };
118
95
  return this._intercept(async () => {
119
- const filter = MongoAdapter.prepareFilter([
120
- await this._getDocumentFilter(info),
121
- options?.filter
122
- ]);
123
- return this._findOne({ ...options, filter });
96
+ const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
97
+ return this._findById(this._id, { ...options, filter });
124
98
  }, info);
125
99
  }
126
- async _findOne(options) {
127
- const filter = MongoAdapter.prepareFilter([
128
- { _id: this._id },
129
- options?.filter
130
- ]);
131
- const mongoOptions = {
132
- ...options,
133
- projection: MongoAdapter.prepareProjection(this.getDataType(), options),
134
- sort: undefined,
135
- skip: undefined,
136
- limit: undefined
137
- };
138
- const decoder = this.getDecoder();
139
- const out = await this.__findOne(filter, mongoOptions);
140
- return out ? decoder(out) : undefined;
141
- }
142
100
  /**
143
101
  * Fetches the document from the Mongo collection service. Throws error if not found.
144
102
  *
145
- * @param {MongoCollectionService.FindOneOptions} options - The options to customize the query.
103
+ * @param {MongoSingletonService.FindOneOptions<T>} options - The options to customize the query.
146
104
  * @return {Promise<PartialDTO<T>>} - A promise that resolves to the fetched document.
147
105
  * @throws {ResourceNotAvailableError} - If the document is not found in the collection.
148
106
  */
149
107
  async get(options) {
150
- const out = await this.findOne(options);
108
+ const out = await this.find(options);
151
109
  if (!out)
152
110
  throw new ResourceNotAvailableError(this.getResourceName());
153
111
  return out;
@@ -164,34 +122,16 @@ export class MongoSingletonService extends MongoService {
164
122
  const info = {
165
123
  crud: 'update',
166
124
  method: 'update',
125
+ byId: true,
126
+ documentId: this._id,
167
127
  input,
168
128
  options,
169
129
  };
170
130
  return this._intercept(async () => {
171
- const filter = MongoAdapter.prepareFilter([
172
- await this._getDocumentFilter(info),
173
- options?.filter
174
- ]);
175
- return this._updateOnly(input, { ...options, filter });
131
+ const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
132
+ return this._updateOnly(this._id, input, { ...options, filter });
176
133
  }, info);
177
134
  }
178
- async _updateOnly(input, options) {
179
- const encode = this.getEncoder('update');
180
- const doc = encode(input);
181
- const patch = MongoAdapter.preparePatch(doc);
182
- const mongoOptions = {
183
- ...options,
184
- includeResultMetadata: false,
185
- upsert: undefined,
186
- projection: MongoAdapter.prepareProjection(this.getDataType(), options),
187
- };
188
- const filter = MongoAdapter.prepareFilter([
189
- { _id: this._id },
190
- options?.filter
191
- ]);
192
- const r = await this.__updateOne(filter, patch, mongoOptions);
193
- return r.modifiedCount;
194
- }
195
135
  /**
196
136
  * Updates a document in the MongoDB collection.
197
137
  *
@@ -204,50 +144,14 @@ export class MongoSingletonService extends MongoService {
204
144
  const info = {
205
145
  crud: 'update',
206
146
  method: 'update',
147
+ byId: true,
148
+ documentId: this._id,
207
149
  input,
208
150
  options,
209
151
  };
210
152
  return this._intercept(async () => {
211
- const filter = MongoAdapter.prepareFilter([
212
- await this._getDocumentFilter(info),
213
- options?.filter
214
- ]);
215
- return this._update(input, { ...options, filter });
153
+ const filter = MongoAdapter.prepareFilter([await this._getDocumentFilter(info), options?.filter]);
154
+ return this._update(this._id, input, { ...options, filter });
216
155
  }, info);
217
156
  }
218
- async _update(input, options) {
219
- const encode = this.getEncoder('update');
220
- const doc = encode(input);
221
- const patch = MongoAdapter.preparePatch(doc);
222
- const mongoOptions = {
223
- ...options,
224
- includeResultMetadata: false,
225
- upsert: undefined,
226
- projection: MongoAdapter.prepareProjection(this.getDataType(), options),
227
- };
228
- const filter = MongoAdapter.prepareFilter([
229
- { _id: this._id },
230
- options?.filter
231
- ]);
232
- const decoder = this.getDecoder();
233
- const out = await this.__findOneAndUpdate(filter, patch, mongoOptions);
234
- return out ? decoder(out) : undefined;
235
- }
236
- /**
237
- * Retrieves the common filter used for querying the document.
238
- * This method is mostly used for security issues like securing multi-tenant applications.
239
- *
240
- * @protected
241
- * @returns {FilterInput | Promise<FilterInput> | undefined} The common filter or a Promise
242
- * that resolves to the common filter, or undefined if not available.
243
- */
244
- _getDocumentFilter(args) {
245
- return typeof this.$documentFilter === 'function' ?
246
- this.$documentFilter(args, this) : this.$documentFilter;
247
- }
248
- async _intercept(callback, args) {
249
- if (this.$interceptor)
250
- return this.$interceptor(callback, args, this);
251
- return callback();
252
- }
253
157
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opra/mongodb",
3
- "version": "0.33.13",
3
+ "version": "1.0.0-alpha.2",
4
4
  "description": "Opra MongoDB adapter package",
5
5
  "author": "Panates",
6
6
  "license": "MIT",
@@ -17,6 +17,7 @@
17
17
  "build:esm": "tsc -b tsconfig-build-esm.json",
18
18
  "postbuild": "cp README.md package.json ../../LICENSE ../../build/mongodb && cp ../../package.cjs.json ../../build/mongodb/cjs/package.json",
19
19
  "lint": "eslint . --max-warnings=0",
20
+ "format": "prettier . --write --log-level=warn",
20
21
  "test": "jest",
21
22
  "cover": "jest --collect-coverage",
22
23
  "clean": "npm run clean:src && npm run clean:dist && npm run clean:cover",
@@ -25,14 +26,14 @@
25
26
  "clean:cover": "rimraf ../../coverage/mongodb"
26
27
  },
27
28
  "devDependencies": {
28
- "@faker-js/faker": "^8.4.0",
29
- "mongodb": "^6.3.0",
30
- "ts-gems": "^3.1.1"
29
+ "@faker-js/faker": "^8.4.1",
30
+ "mongodb": "^6.7.0",
31
+ "ts-gems": "^3.4.0"
31
32
  },
32
33
  "peerDependencies": {
33
- "@opra/common": "^0.33.13",
34
- "@opra/core": "^0.33.13",
35
- "mongodb": ">=6.x.x"
34
+ "@opra/common": "^1.0.0-alpha.2",
35
+ "@opra/core": "^1.0.0-alpha.2",
36
+ "mongodb": ">= 6.0.0"
36
37
  },
37
38
  "type": "module",
38
39
  "module": "./esm/index.js",
@@ -55,4 +56,4 @@
55
56
  "mongodb",
56
57
  "adapter"
57
58
  ]
58
- }
59
+ }
@@ -1,6 +1,5 @@
1
1
  import mongodb from 'mongodb';
2
- import { OpraFilter } from '@opra/common';
3
- export type FilterInput = (OpraFilter.Expression | mongodb.Filter<any> | string | undefined);
2
+ import type { MongoAdapter } from '../mongo-adapter.js';
4
3
  /**
5
4
  * Prepare the MongoDB filter based on the provided filters and options.
6
5
  *
@@ -10,6 +9,6 @@ export type FilterInput = (OpraFilter.Expression | mongodb.Filter<any> | string
10
9
  *
11
10
  * @returns {mongodb.Filter<any>} - The prepared MongoDB filter.
12
11
  */
13
- export default function prepareFilter(filters: FilterInput | FilterInput[], options?: {
12
+ export default function prepareFilter(filters: MongoAdapter.FilterInput | MongoAdapter.FilterInput[], options?: {
14
13
  fieldPrefix?: string;
15
14
  }): mongodb.Filter<any>;
@@ -1,13 +1,4 @@
1
- import mongodb from 'mongodb';
2
- import { ComplexType } from '@opra/common';
3
- export default function prepareProjection(dataType: ComplexType, options?: {
4
- pick?: string[];
5
- omit?: string[];
6
- include?: string[];
7
- }): mongodb.Document | undefined;
8
- export declare function _prepareProjection(dataType: ComplexType, target: mongodb.Document, options: {
9
- pickActivated: boolean;
10
- include?: any;
11
- pick?: any;
12
- omit?: any;
13
- }): void;
1
+ import mongodb, { Document } from 'mongodb';
2
+ import { ComplexType, FieldsProjection } from '@opra/common';
3
+ export default function prepareProjection(dataType: ComplexType, projection?: string | string[] | Document): mongodb.Document | undefined;
4
+ export declare function prepare(dataType: ComplexType, target: mongodb.Document, projection?: FieldsProjection): void;
package/types/index.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  export * from './mongo-adapter.js';
2
- export * from './mongo-array-service.js';
2
+ export * from './mongo-nested-service.js';
3
3
  export * from './mongo-collection-service.js';
4
4
  export * from './mongo-service.js';
5
5
  export * from './mongo-singleton-service.js';
6
- export * from './types.js';
@@ -1,12 +1,25 @@
1
+ import mongodb, { ClientSession, ObjectId } from 'mongodb';
2
+ import { OpraFilter } from '@opra/common';
3
+ import { HttpContext } from '@opra/core';
1
4
  import _prepareFilter from './adapter-utils/prepare-filter.js';
2
5
  import _prepareKeyValues from './adapter-utils/prepare-key-values.js';
3
6
  import _preparePatch from './adapter-utils/prepare-patch.js';
4
7
  import _prepareProjection from './adapter-utils/prepare-projection.js';
5
8
  import _prepareSort from './adapter-utils/prepare-sort.js';
6
9
  export declare namespace MongoAdapter {
7
- const prepareKeyValues: typeof _prepareKeyValues;
10
+ type AnyId = string | number | ObjectId;
11
+ type FilterInput = OpraFilter.Expression | mongodb.Filter<any> | string | undefined;
12
+ type WithTransactionCallback = (session: ClientSession) => any;
8
13
  const prepareFilter: typeof _prepareFilter;
14
+ const prepareKeyValues: typeof _prepareKeyValues;
9
15
  const preparePatch: typeof _preparePatch;
10
16
  const prepareProjection: typeof _prepareProjection;
11
17
  const prepareSort: typeof _prepareSort;
18
+ interface TransformedRequest {
19
+ method: 'create' | 'delete' | 'deleteMany' | 'get' | 'findMany' | 'update' | 'updateMany';
20
+ key?: any;
21
+ data?: any;
22
+ options: any;
23
+ }
24
+ function parseRequest(context: HttpContext): Promise<TransformedRequest>;
12
25
  }