@abejarano/ts-mongodb-criteria 1.3.0 → 1.5.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/README.md +31 -2
- package/dist/{AggregateRoot.js → cjs/AggregateRoot.js} +3 -0
- package/dist/cjs/mongo/IRepository.js +2 -0
- package/dist/{mongo → cjs/mongo}/MongoRepository.js +44 -36
- package/dist/{mongo → cjs/mongo}/index.js +1 -0
- package/dist/esm/AggregateRoot.js +5 -0
- package/dist/esm/criteria/Criteria.js +15 -0
- package/dist/esm/criteria/Filter.js +20 -0
- package/dist/esm/criteria/FilterField.js +6 -0
- package/dist/esm/criteria/FilterOperator.js +34 -0
- package/dist/esm/criteria/FilterValue.js +79 -0
- package/dist/esm/criteria/Filters.js +12 -0
- package/dist/esm/criteria/Order.js +26 -0
- package/dist/esm/criteria/OrderBy.js +13 -0
- package/dist/esm/criteria/OrderType.js +30 -0
- package/dist/esm/criteria/Paginate.js +1 -0
- package/dist/esm/exceptions/InvalidArgumentError.exception.js +2 -0
- package/dist/esm/mongo/IRepository.js +1 -0
- package/dist/esm/mongo/MongoClientFactory.js +45 -0
- package/dist/esm/mongo/MongoCriteriaConverter.js +125 -0
- package/dist/esm/mongo/MongoRepository.js +99 -0
- package/dist/esm/mongo/index.js +4 -0
- package/dist/esm/valueObject/EnumValueObject.js +12 -0
- package/dist/esm/valueObject/StringValueObject.js +20 -0
- package/dist/esm/valueObject/ValueObject.js +19 -0
- package/dist/types/AggregateRoot.d.ts +8 -0
- package/dist/types/criteria/index.d.ts +10 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/mongo/IRepository.d.ts +8 -0
- package/dist/types/mongo/MongoRepository.d.ts +22 -0
- package/dist/{mongo → types/mongo}/index.d.ts +1 -0
- package/dist/types/valueObject/index.d.ts +3 -0
- package/package.json +18 -5
- package/dist/AggregateRoot.d.ts +0 -4
- package/dist/mongo/MongoRepository.d.ts +0 -15
- /package/dist/{criteria → cjs/criteria}/Criteria.js +0 -0
- /package/dist/{criteria → cjs/criteria}/Filter.js +0 -0
- /package/dist/{criteria → cjs/criteria}/FilterField.js +0 -0
- /package/dist/{criteria → cjs/criteria}/FilterOperator.js +0 -0
- /package/dist/{criteria → cjs/criteria}/FilterValue.js +0 -0
- /package/dist/{criteria → cjs/criteria}/Filters.js +0 -0
- /package/dist/{criteria → cjs/criteria}/Order.js +0 -0
- /package/dist/{criteria → cjs/criteria}/OrderBy.js +0 -0
- /package/dist/{criteria → cjs/criteria}/OrderType.js +0 -0
- /package/dist/{criteria → cjs/criteria}/Paginate.js +0 -0
- /package/dist/{criteria → cjs/criteria}/index.js +0 -0
- /package/dist/{exceptions → cjs/exceptions}/InvalidArgumentError.exception.js +0 -0
- /package/dist/{index.js → cjs/index.js} +0 -0
- /package/dist/{mongo → cjs/mongo}/MongoClientFactory.js +0 -0
- /package/dist/{mongo → cjs/mongo}/MongoCriteriaConverter.js +0 -0
- /package/dist/{valueObject → cjs/valueObject}/EnumValueObject.js +0 -0
- /package/dist/{valueObject → cjs/valueObject}/StringValueObject.js +0 -0
- /package/dist/{valueObject → cjs/valueObject}/ValueObject.js +0 -0
- /package/dist/{valueObject → cjs/valueObject}/index.js +0 -0
- /package/dist/{criteria/index.d.ts → esm/criteria/index.js} +0 -0
- /package/dist/{index.d.ts → esm/index.js} +0 -0
- /package/dist/{valueObject/index.d.ts → esm/valueObject/index.js} +0 -0
- /package/dist/{criteria → types/criteria}/Criteria.d.ts +0 -0
- /package/dist/{criteria → types/criteria}/Filter.d.ts +0 -0
- /package/dist/{criteria → types/criteria}/FilterField.d.ts +0 -0
- /package/dist/{criteria → types/criteria}/FilterOperator.d.ts +0 -0
- /package/dist/{criteria → types/criteria}/FilterValue.d.ts +0 -0
- /package/dist/{criteria → types/criteria}/Filters.d.ts +0 -0
- /package/dist/{criteria → types/criteria}/Order.d.ts +0 -0
- /package/dist/{criteria → types/criteria}/OrderBy.d.ts +0 -0
- /package/dist/{criteria → types/criteria}/OrderType.d.ts +0 -0
- /package/dist/{criteria → types/criteria}/Paginate.d.ts +0 -0
- /package/dist/{exceptions → types/exceptions}/InvalidArgumentError.exception.d.ts +0 -0
- /package/dist/{mongo → types/mongo}/MongoClientFactory.d.ts +0 -0
- /package/dist/{mongo → types/mongo}/MongoCriteriaConverter.d.ts +0 -0
- /package/dist/{valueObject → types/valueObject}/EnumValueObject.d.ts +0 -0
- /package/dist/{valueObject → types/valueObject}/StringValueObject.d.ts +0 -0
- /package/dist/{valueObject → types/valueObject}/ValueObject.d.ts +0 -0
package/README.md
CHANGED
|
@@ -147,15 +147,40 @@ const criteria = new Criteria(
|
|
|
147
147
|
|
|
148
148
|
// 3. Use with your MongoDB repository
|
|
149
149
|
class UserRepository extends MongoRepository<User> {
|
|
150
|
+
constructor() {
|
|
151
|
+
super(User)
|
|
152
|
+
}
|
|
153
|
+
|
|
150
154
|
collectionName(): string {
|
|
151
155
|
return "users"
|
|
152
156
|
}
|
|
153
157
|
}
|
|
154
158
|
|
|
155
159
|
const userRepo = new UserRepository()
|
|
156
|
-
const
|
|
160
|
+
const { results } = await userRepo.list(criteria)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
MongoRepository provides ready-to-use public methods for repositories that extend it:
|
|
164
|
+
- `list(criteria, fieldsToExclude?)` for paginated queries
|
|
165
|
+
- `one(filter)` to fetch a single entity
|
|
166
|
+
- `upsert(entity)` to persist an aggregate
|
|
167
|
+
Internal helpers are private, so repositories should call these public methods
|
|
168
|
+
directly.
|
|
169
|
+
|
|
170
|
+
If you need a repository interface in your app, extend `IRepository<T>` so your
|
|
171
|
+
custom interfaces stay aligned with the library return types:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import { IRepository } from "@abejarano/ts-mongodb-criteria"
|
|
175
|
+
|
|
176
|
+
export interface IUserRepository extends IRepository<User> {
|
|
177
|
+
// Add domain-specific methods here
|
|
178
|
+
}
|
|
157
179
|
```
|
|
158
180
|
|
|
181
|
+
The goal of `IRepository` is to prevent signature drift (e.g. `upsert` returning
|
|
182
|
+
`void` in your app while the base repository returns `ObjectId | null`).
|
|
183
|
+
|
|
159
184
|
**Your First Query in 30 Seconds:**
|
|
160
185
|
|
|
161
186
|
```typescript
|
|
@@ -178,7 +203,7 @@ const activeAdultUsers = new Criteria(
|
|
|
178
203
|
1 // First page
|
|
179
204
|
)
|
|
180
205
|
|
|
181
|
-
const results = await repository.
|
|
206
|
+
const results = await repository.list(activeAdultUsers)
|
|
182
207
|
```
|
|
183
208
|
|
|
184
209
|
## 📖 Documentation
|
|
@@ -219,6 +244,10 @@ const order = Order.desc("createdAt") // or Order.asc("name")
|
|
|
219
244
|
- `CONTAINS`, `NOT_CONTAINS` - Text search
|
|
220
245
|
- `OR` - Logical OR combinations
|
|
221
246
|
|
|
247
|
+
## ✅ Runtime Compatibility
|
|
248
|
+
|
|
249
|
+
This library ships dual builds (CJS + ESM) and works in both Node.js and Bun.
|
|
250
|
+
|
|
222
251
|
### 🆕 OR Operator Example
|
|
223
252
|
|
|
224
253
|
```typescript
|
|
@@ -2,5 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AggregateRoot = void 0;
|
|
4
4
|
class AggregateRoot {
|
|
5
|
+
static fromPrimitives(_data) {
|
|
6
|
+
throw new Error("fromPrimitives must be implemented in subclasses");
|
|
7
|
+
}
|
|
5
8
|
}
|
|
6
9
|
exports.AggregateRoot = AggregateRoot;
|
|
@@ -5,45 +5,41 @@ const MongoCriteriaConverter_1 = require("./MongoCriteriaConverter");
|
|
|
5
5
|
const MongoClientFactory_1 = require("./MongoClientFactory");
|
|
6
6
|
const mongodb_1 = require("mongodb");
|
|
7
7
|
class MongoRepository {
|
|
8
|
-
constructor() {
|
|
8
|
+
constructor(aggregateRootClass) {
|
|
9
|
+
this.aggregateRootClass = aggregateRootClass;
|
|
9
10
|
this.criteriaConverter = new MongoCriteriaConverter_1.MongoCriteriaConverter();
|
|
10
11
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
// primitiveData: any,
|
|
14
|
-
// ): {} {
|
|
15
|
-
// const response = {};
|
|
16
|
-
//
|
|
17
|
-
// for (const key in primitiveData) {
|
|
18
|
-
// response[`${subDocumentField}.$.${key}`] = primitiveData[key];
|
|
19
|
-
// }
|
|
20
|
-
//
|
|
21
|
-
// return response;
|
|
22
|
-
// }
|
|
23
|
-
async paginate(documents) {
|
|
12
|
+
/** Finds a single entity and hydrates it via the aggregate's fromPrimitives. */
|
|
13
|
+
async one(filter) {
|
|
24
14
|
const collection = await this.collection();
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const hasNextPage = currentPage * limit < count;
|
|
29
|
-
if (documents.length === 0) {
|
|
30
|
-
return {
|
|
31
|
-
nextPag: null,
|
|
32
|
-
count: 0,
|
|
33
|
-
results: [],
|
|
34
|
-
};
|
|
15
|
+
const result = await collection.findOne(filter);
|
|
16
|
+
if (!result) {
|
|
17
|
+
return null;
|
|
35
18
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
19
|
+
const { _id, ...rest } = result;
|
|
20
|
+
return this.aggregateRootClass.fromPrimitives(rest);
|
|
21
|
+
}
|
|
22
|
+
/** Upserts an aggregate by delegating to persist with its id. */
|
|
23
|
+
async upsert(entity) {
|
|
24
|
+
return this.persist(entity.getId(), entity);
|
|
25
|
+
}
|
|
26
|
+
/** Lists entities by criteria and returns a paginated response. */
|
|
27
|
+
async list(criteria, fieldsToExclude = []) {
|
|
28
|
+
const documents = await this.searchByCriteria(criteria, fieldsToExclude);
|
|
29
|
+
return this.paginate(documents);
|
|
41
30
|
}
|
|
42
31
|
async collection() {
|
|
43
32
|
return (await MongoClientFactory_1.MongoClientFactory.createClient())
|
|
44
33
|
.db()
|
|
45
34
|
.collection(this.collectionName());
|
|
46
35
|
}
|
|
36
|
+
async updateOne(filter, update) {
|
|
37
|
+
const collection = await this.collection();
|
|
38
|
+
const result = await collection.updateOne(filter, update, {
|
|
39
|
+
upsert: true,
|
|
40
|
+
});
|
|
41
|
+
return result.upsertedId;
|
|
42
|
+
}
|
|
47
43
|
async persist(id, aggregateRoot) {
|
|
48
44
|
let primitives;
|
|
49
45
|
if (aggregateRoot.toPrimitives() instanceof Promise) {
|
|
@@ -59,13 +55,6 @@ class MongoRepository {
|
|
|
59
55
|
},
|
|
60
56
|
});
|
|
61
57
|
}
|
|
62
|
-
async updateOne(filter, update) {
|
|
63
|
-
const collection = await this.collection();
|
|
64
|
-
const result = await collection.updateOne(filter, update, {
|
|
65
|
-
upsert: true,
|
|
66
|
-
});
|
|
67
|
-
return result.upsertedId;
|
|
68
|
-
}
|
|
69
58
|
async searchByCriteria(criteria, fieldsToExclude = []) {
|
|
70
59
|
this.criteria = criteria;
|
|
71
60
|
this.query = this.criteriaConverter.convert(criteria);
|
|
@@ -91,5 +80,24 @@ class MongoRepository {
|
|
|
91
80
|
.toArray();
|
|
92
81
|
return results.map(({ _id, ...rest }) => rest);
|
|
93
82
|
}
|
|
83
|
+
async paginate(documents) {
|
|
84
|
+
const collection = await this.collection();
|
|
85
|
+
const count = await collection.countDocuments(this.query.filter);
|
|
86
|
+
const limit = this.criteria?.limit || 10;
|
|
87
|
+
const currentPage = this.criteria?.currentPage || 1;
|
|
88
|
+
const hasNextPage = currentPage * limit < count;
|
|
89
|
+
if (documents.length === 0) {
|
|
90
|
+
return {
|
|
91
|
+
nextPag: null,
|
|
92
|
+
count: 0,
|
|
93
|
+
results: [],
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
nextPag: hasNextPage ? Number(this.criteria.currentPage) + 1 : null,
|
|
98
|
+
count: count,
|
|
99
|
+
results: documents,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
94
102
|
}
|
|
95
103
|
exports.MongoRepository = MongoRepository;
|
|
@@ -16,4 +16,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./MongoCriteriaConverter"), exports);
|
|
18
18
|
__exportStar(require("./MongoRepository"), exports);
|
|
19
|
+
__exportStar(require("./IRepository"), exports);
|
|
19
20
|
__exportStar(require("./MongoClientFactory"), exports);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export class Criteria {
|
|
2
|
+
constructor(filters, order, limit, offset) {
|
|
3
|
+
this.filters = filters;
|
|
4
|
+
this.order = order;
|
|
5
|
+
this.limit = limit;
|
|
6
|
+
this.currentPage = offset;
|
|
7
|
+
this.offset =
|
|
8
|
+
offset !== undefined && limit !== undefined
|
|
9
|
+
? (offset - 1) * limit
|
|
10
|
+
: undefined;
|
|
11
|
+
}
|
|
12
|
+
hasFilters() {
|
|
13
|
+
return this.filters.filters.length > 0;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { FilterField } from "./FilterField";
|
|
2
|
+
import { FilterOperator } from "./FilterOperator";
|
|
3
|
+
import { FilterValue } from "./FilterValue";
|
|
4
|
+
import { InvalidArgumentError } from "../exceptions/InvalidArgumentError.exception";
|
|
5
|
+
export class Filter {
|
|
6
|
+
constructor(field, operator, value) {
|
|
7
|
+
this.field = field;
|
|
8
|
+
this.operator = operator;
|
|
9
|
+
this.value = value;
|
|
10
|
+
}
|
|
11
|
+
static fromValues(values) {
|
|
12
|
+
const field = values.get("field");
|
|
13
|
+
const operator = values.get("operator");
|
|
14
|
+
const value = values.get("value");
|
|
15
|
+
if (!field || !operator || value === undefined) {
|
|
16
|
+
throw new InvalidArgumentError(`The filter is invalid`);
|
|
17
|
+
}
|
|
18
|
+
return new Filter(new FilterField(field), FilterOperator.fromValue(operator), new FilterValue(value));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { InvalidArgumentError } from "../exceptions/InvalidArgumentError.exception";
|
|
2
|
+
export var Operator;
|
|
3
|
+
(function (Operator) {
|
|
4
|
+
Operator["EQUAL"] = "=";
|
|
5
|
+
Operator["NOT_EQUAL"] = "!=";
|
|
6
|
+
Operator["GT"] = ">";
|
|
7
|
+
Operator["LT"] = "<";
|
|
8
|
+
Operator["CONTAINS"] = "CONTAINS";
|
|
9
|
+
Operator["NOT_CONTAINS"] = "NOT_CONTAINS";
|
|
10
|
+
Operator["GTE"] = ">=";
|
|
11
|
+
Operator["LTE"] = "<=";
|
|
12
|
+
Operator["BETWEEN"] = "BETWEEN";
|
|
13
|
+
Operator["OR"] = "OR";
|
|
14
|
+
Operator["IN"] = "IN";
|
|
15
|
+
Operator["NOT_IN"] = "NOT_IN";
|
|
16
|
+
})(Operator || (Operator = {}));
|
|
17
|
+
//export class FilterOperator extends EnumValueObject<Operator> {
|
|
18
|
+
export class FilterOperator {
|
|
19
|
+
constructor(value) {
|
|
20
|
+
this.value = value;
|
|
21
|
+
//super(value, Object.values(Operator));
|
|
22
|
+
}
|
|
23
|
+
static fromValue(value) {
|
|
24
|
+
for (const operatorValue of Object.values(Operator)) {
|
|
25
|
+
if (value === operatorValue.toString()) {
|
|
26
|
+
return new FilterOperator(operatorValue);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
throw new InvalidArgumentError(`The filter operator ${value} is invalid`);
|
|
30
|
+
}
|
|
31
|
+
throwErrorForInvalidValue(value) {
|
|
32
|
+
throw new InvalidArgumentError(`The filter operator ${value} is invalid`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { StringValueObject } from "../valueObject";
|
|
2
|
+
const isOrConditionArray = (value) => {
|
|
3
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
4
|
+
return false;
|
|
5
|
+
}
|
|
6
|
+
const candidate = value[0];
|
|
7
|
+
return (typeof candidate === "object" &&
|
|
8
|
+
candidate !== null &&
|
|
9
|
+
"field" in candidate &&
|
|
10
|
+
"operator" in candidate &&
|
|
11
|
+
"value" in candidate);
|
|
12
|
+
};
|
|
13
|
+
const isBetweenObject = (value) => {
|
|
14
|
+
if (value === null || typeof value !== "object") {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
const candidate = value;
|
|
18
|
+
const hasStartEnd = "start" in candidate && "end" in candidate;
|
|
19
|
+
const hasStartDateEndDate = "startDate" in candidate && "endDate" in candidate;
|
|
20
|
+
const hasFromTo = "from" in candidate && "to" in candidate;
|
|
21
|
+
return hasStartEnd || hasStartDateEndDate || hasFromTo;
|
|
22
|
+
};
|
|
23
|
+
const normalizeBetweenValue = (value) => {
|
|
24
|
+
if ("start" in value && "end" in value) {
|
|
25
|
+
return { start: value.start, end: value.end };
|
|
26
|
+
}
|
|
27
|
+
if ("startDate" in value && "endDate" in value) {
|
|
28
|
+
return { start: value.startDate, end: value.endDate };
|
|
29
|
+
}
|
|
30
|
+
return { start: value.from, end: value.to };
|
|
31
|
+
};
|
|
32
|
+
export class FilterValue extends StringValueObject {
|
|
33
|
+
constructor(value) {
|
|
34
|
+
if (Array.isArray(value) && isOrConditionArray(value)) {
|
|
35
|
+
// Handle OrCondition[]
|
|
36
|
+
super(JSON.stringify(value));
|
|
37
|
+
}
|
|
38
|
+
else if (Array.isArray(value)) {
|
|
39
|
+
// Handle primitive arrays (kept for backward compatibility)
|
|
40
|
+
super(value.join(","));
|
|
41
|
+
}
|
|
42
|
+
else if (isBetweenObject(value)) {
|
|
43
|
+
// Store serialized version but keep original reference
|
|
44
|
+
super(JSON.stringify(value));
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// Handle primitive values (string, number, boolean, Date)
|
|
48
|
+
super(value);
|
|
49
|
+
}
|
|
50
|
+
this._originalValue = value;
|
|
51
|
+
}
|
|
52
|
+
get isOrConditions() {
|
|
53
|
+
return isOrConditionArray(this._originalValue);
|
|
54
|
+
}
|
|
55
|
+
get asOrConditions() {
|
|
56
|
+
if (this.isOrConditions) {
|
|
57
|
+
return this._originalValue;
|
|
58
|
+
}
|
|
59
|
+
throw new Error("Value is not an OrCondition array");
|
|
60
|
+
}
|
|
61
|
+
get isBetween() {
|
|
62
|
+
return isBetweenObject(this._originalValue);
|
|
63
|
+
}
|
|
64
|
+
get asBetween() {
|
|
65
|
+
if (this.isBetween) {
|
|
66
|
+
return normalizeBetweenValue(this._originalValue);
|
|
67
|
+
}
|
|
68
|
+
throw new Error("Value is not a BETWEEN structure");
|
|
69
|
+
}
|
|
70
|
+
get isPrimitiveArray() {
|
|
71
|
+
return Array.isArray(this._originalValue) && !this.isOrConditions;
|
|
72
|
+
}
|
|
73
|
+
get asPrimitiveArray() {
|
|
74
|
+
if (this.isPrimitiveArray) {
|
|
75
|
+
return this._originalValue;
|
|
76
|
+
}
|
|
77
|
+
throw new Error("Value is not an array of primitive values");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Filter } from "./Filter";
|
|
2
|
+
export class Filters {
|
|
3
|
+
constructor(filters) {
|
|
4
|
+
this.filters = filters;
|
|
5
|
+
}
|
|
6
|
+
static fromValues(filters) {
|
|
7
|
+
return new Filters(filters.map((values) => Filter.fromValues(values)));
|
|
8
|
+
}
|
|
9
|
+
static none() {
|
|
10
|
+
return new Filters([]);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { OrderBy } from "./OrderBy";
|
|
2
|
+
import { OrderType, OrderTypes } from "./OrderType";
|
|
3
|
+
export class Order {
|
|
4
|
+
constructor(orderBy, orderType) {
|
|
5
|
+
this.orderBy = orderBy;
|
|
6
|
+
this.orderType = orderType;
|
|
7
|
+
}
|
|
8
|
+
static fromValues(orderBy, orderType) {
|
|
9
|
+
if (!orderBy) {
|
|
10
|
+
return Order.none();
|
|
11
|
+
}
|
|
12
|
+
return new Order(new OrderBy(orderBy), OrderType.fromValue(orderType || OrderTypes.ASC));
|
|
13
|
+
}
|
|
14
|
+
static none() {
|
|
15
|
+
return new Order(new OrderBy(""), new OrderType(OrderTypes.NONE));
|
|
16
|
+
}
|
|
17
|
+
static desc(orderBy) {
|
|
18
|
+
return new Order(new OrderBy(orderBy), new OrderType(OrderTypes.DESC));
|
|
19
|
+
}
|
|
20
|
+
static asc(orderBy) {
|
|
21
|
+
return new Order(new OrderBy(orderBy), new OrderType(OrderTypes.ASC));
|
|
22
|
+
}
|
|
23
|
+
hasOrder() {
|
|
24
|
+
return !this.orderType.isNone();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ValueObject } from "../valueObject/ValueObject";
|
|
2
|
+
export class OrderBy extends ValueObject {
|
|
3
|
+
constructor(value) {
|
|
4
|
+
super(value);
|
|
5
|
+
this.value = value;
|
|
6
|
+
}
|
|
7
|
+
static create(value) {
|
|
8
|
+
return new OrderBy(value);
|
|
9
|
+
}
|
|
10
|
+
getValue() {
|
|
11
|
+
return this.value;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { EnumValueObject } from "../valueObject";
|
|
2
|
+
import { InvalidArgumentError } from "../exceptions/InvalidArgumentError.exception";
|
|
3
|
+
export var OrderTypes;
|
|
4
|
+
(function (OrderTypes) {
|
|
5
|
+
OrderTypes["ASC"] = "asc";
|
|
6
|
+
OrderTypes["DESC"] = "desc";
|
|
7
|
+
OrderTypes["NONE"] = "none";
|
|
8
|
+
})(OrderTypes || (OrderTypes = {}));
|
|
9
|
+
export class OrderType extends EnumValueObject {
|
|
10
|
+
constructor(value) {
|
|
11
|
+
super(value, Object.values(OrderTypes));
|
|
12
|
+
}
|
|
13
|
+
static fromValue(value) {
|
|
14
|
+
for (const orderTypeValue of Object.values(OrderTypes)) {
|
|
15
|
+
if (value === orderTypeValue.toString()) {
|
|
16
|
+
return new OrderType(orderTypeValue);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
throw new InvalidArgumentError(`The order type ${value} is invalid`);
|
|
20
|
+
}
|
|
21
|
+
isNone() {
|
|
22
|
+
return this.value === OrderTypes.NONE;
|
|
23
|
+
}
|
|
24
|
+
isAsc() {
|
|
25
|
+
return this.value === OrderTypes.ASC;
|
|
26
|
+
}
|
|
27
|
+
throwErrorForInvalidValue(value) {
|
|
28
|
+
throw new InvalidArgumentError(`The order type ${value} is invalid`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { MongoClient } from "mongodb";
|
|
2
|
+
export class MongoClientFactory {
|
|
3
|
+
/**
|
|
4
|
+
* Obtiene o crea una instancia de MongoClient.
|
|
5
|
+
* Reutiliza la conexión si ya existe.
|
|
6
|
+
*/
|
|
7
|
+
static async createClient() {
|
|
8
|
+
if (!MongoClientFactory.client) {
|
|
9
|
+
MongoClientFactory.client =
|
|
10
|
+
await MongoClientFactory.createAndConnectClient();
|
|
11
|
+
}
|
|
12
|
+
return MongoClientFactory.client;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Cierra la conexión a MongoDB.
|
|
16
|
+
*/
|
|
17
|
+
static async closeClient() {
|
|
18
|
+
if (MongoClientFactory.client) {
|
|
19
|
+
await MongoClientFactory.client.close();
|
|
20
|
+
MongoClientFactory.client = null; // Limpia la instancia
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Crea y conecta una nueva instancia de MongoClient.
|
|
25
|
+
*/
|
|
26
|
+
static async createAndConnectClient() {
|
|
27
|
+
const MONGO_PASS = process.env.MONGO_PASS;
|
|
28
|
+
const MONGO_USER = process.env.MONGO_USER;
|
|
29
|
+
const MONGO_DB = process.env.MONGO_DB;
|
|
30
|
+
const MONGO_SERVER = process.env.MONGO_SERVER;
|
|
31
|
+
if (!MONGO_PASS || !MONGO_USER || !MONGO_DB || !MONGO_SERVER) {
|
|
32
|
+
throw new Error("Missing MongoDB environment variables.");
|
|
33
|
+
}
|
|
34
|
+
const uri = `mongodb+srv://${MONGO_USER}:${MONGO_PASS}@${MONGO_SERVER}/${MONGO_DB}?retryWrites=true&w=majority`;
|
|
35
|
+
const client = new MongoClient(uri, { ignoreUndefined: true });
|
|
36
|
+
try {
|
|
37
|
+
await client.connect();
|
|
38
|
+
return client;
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
MongoClientFactory.client = null;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { Operator } from "../criteria";
|
|
2
|
+
export class MongoCriteriaConverter {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.filterTransformers = new Map([
|
|
5
|
+
[Operator.EQUAL, this.equalFilter],
|
|
6
|
+
[Operator.NOT_EQUAL, this.notEqualFilter],
|
|
7
|
+
[Operator.GT, this.greaterThanFilter],
|
|
8
|
+
[Operator.LT, this.lowerThanFilter],
|
|
9
|
+
[Operator.CONTAINS, this.containsFilter],
|
|
10
|
+
[Operator.NOT_CONTAINS, this.notContainsFilter],
|
|
11
|
+
[Operator.GTE, this.greaterThanOrEqualFilter],
|
|
12
|
+
[Operator.LTE, this.lowerThanOrEqualFilter],
|
|
13
|
+
[Operator.BETWEEN, this.betweenFilter],
|
|
14
|
+
[Operator.OR, this.orFilter],
|
|
15
|
+
[Operator.IN, this.inFilter],
|
|
16
|
+
[Operator.NOT_IN, this.notInFilter],
|
|
17
|
+
]);
|
|
18
|
+
}
|
|
19
|
+
convert(criteria) {
|
|
20
|
+
return {
|
|
21
|
+
filter: criteria.hasFilters()
|
|
22
|
+
? this.generateFilter(criteria.filters)
|
|
23
|
+
: {},
|
|
24
|
+
sort: criteria.order.hasOrder()
|
|
25
|
+
? this.generateSort(criteria.order)
|
|
26
|
+
: { _id: -1 },
|
|
27
|
+
skip: criteria.offset || 0,
|
|
28
|
+
limit: criteria.limit || 0,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
generateFilter(filters) {
|
|
32
|
+
const filter = filters.filters.map((filter) => {
|
|
33
|
+
const transformer = this.filterTransformers.get(filter.operator.value);
|
|
34
|
+
if (!transformer) {
|
|
35
|
+
throw Error(`Unexpected operator value ${filter.operator.value}`);
|
|
36
|
+
}
|
|
37
|
+
return transformer(filter);
|
|
38
|
+
});
|
|
39
|
+
return Object.assign({}, ...filter);
|
|
40
|
+
}
|
|
41
|
+
generateSort(order) {
|
|
42
|
+
return {
|
|
43
|
+
[order.orderBy.value === "id" ? "_id" : order.orderBy.value]: order.orderType.isAsc() ? 1 : -1,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
equalFilter(filter) {
|
|
47
|
+
return { [filter.field.value]: { $eq: filter.value.value } };
|
|
48
|
+
}
|
|
49
|
+
notEqualFilter(filter) {
|
|
50
|
+
return { [filter.field.value]: { $ne: filter.value.value } };
|
|
51
|
+
}
|
|
52
|
+
greaterThanFilter(filter) {
|
|
53
|
+
return { [filter.field.value]: { $gt: filter.value.value } };
|
|
54
|
+
}
|
|
55
|
+
greaterThanOrEqualFilter(filter) {
|
|
56
|
+
return { [filter.field.value]: { $gte: filter.value.value } };
|
|
57
|
+
}
|
|
58
|
+
lowerThanOrEqualFilter(filter) {
|
|
59
|
+
return { [filter.field.value]: { $lte: filter.value.value } };
|
|
60
|
+
}
|
|
61
|
+
lowerThanFilter(filter) {
|
|
62
|
+
return { [filter.field.value]: { $lt: filter.value.value } };
|
|
63
|
+
}
|
|
64
|
+
containsFilter(filter) {
|
|
65
|
+
return { [filter.field.value]: { $regex: filter.value.value } };
|
|
66
|
+
}
|
|
67
|
+
notContainsFilter(filter) {
|
|
68
|
+
return {
|
|
69
|
+
[filter.field.value]: { $not: { $regex: filter.value.value } },
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
inFilter(filter) {
|
|
73
|
+
if (!filter.value.isPrimitiveArray) {
|
|
74
|
+
throw new Error("IN operator requires an array of primitive values");
|
|
75
|
+
}
|
|
76
|
+
return { [filter.field.value]: { $in: filter.value.asPrimitiveArray } };
|
|
77
|
+
}
|
|
78
|
+
notInFilter(filter) {
|
|
79
|
+
if (!filter.value.isPrimitiveArray) {
|
|
80
|
+
throw new Error("NOT_IN operator requires an array of primitive values");
|
|
81
|
+
}
|
|
82
|
+
return { [filter.field.value]: { $nin: filter.value.asPrimitiveArray } };
|
|
83
|
+
}
|
|
84
|
+
orFilter(filter) {
|
|
85
|
+
if (!filter.value.isOrConditions) {
|
|
86
|
+
throw new Error("OR operator requires an array of OrCondition objects");
|
|
87
|
+
}
|
|
88
|
+
const conditions = filter.value.asOrConditions;
|
|
89
|
+
const orConditions = conditions.map((condition) => {
|
|
90
|
+
switch (condition.operator) {
|
|
91
|
+
case Operator.CONTAINS:
|
|
92
|
+
return { [condition.field]: { $regex: condition.value } };
|
|
93
|
+
case Operator.EQUAL:
|
|
94
|
+
return { [condition.field]: { $eq: condition.value } };
|
|
95
|
+
case Operator.NOT_EQUAL:
|
|
96
|
+
return { [condition.field]: { $ne: condition.value } };
|
|
97
|
+
case Operator.GT:
|
|
98
|
+
return { [condition.field]: { $gt: condition.value } };
|
|
99
|
+
case Operator.LT:
|
|
100
|
+
return { [condition.field]: { $lt: condition.value } };
|
|
101
|
+
case Operator.GTE:
|
|
102
|
+
return { [condition.field]: { $gte: condition.value } };
|
|
103
|
+
case Operator.LTE:
|
|
104
|
+
return { [condition.field]: { $lte: condition.value } };
|
|
105
|
+
case Operator.NOT_CONTAINS:
|
|
106
|
+
return { [condition.field]: { $not: { $regex: condition.value } } };
|
|
107
|
+
default:
|
|
108
|
+
throw new Error(`Unsupported operator in OR condition: ${condition.operator}`);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
return { $or: orConditions };
|
|
112
|
+
}
|
|
113
|
+
betweenFilter(filter) {
|
|
114
|
+
if (!filter.value.isBetween) {
|
|
115
|
+
throw new Error("BETWEEN operator requires an object with start and end values.");
|
|
116
|
+
}
|
|
117
|
+
const { start, end } = filter.value.asBetween;
|
|
118
|
+
return {
|
|
119
|
+
[filter.field.value]: {
|
|
120
|
+
$gte: start,
|
|
121
|
+
$lte: end,
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { MongoCriteriaConverter } from "./MongoCriteriaConverter";
|
|
2
|
+
import { MongoClientFactory } from "./MongoClientFactory";
|
|
3
|
+
import { ObjectId } from "mongodb";
|
|
4
|
+
export class MongoRepository {
|
|
5
|
+
constructor(aggregateRootClass) {
|
|
6
|
+
this.aggregateRootClass = aggregateRootClass;
|
|
7
|
+
this.criteriaConverter = new MongoCriteriaConverter();
|
|
8
|
+
}
|
|
9
|
+
/** Finds a single entity and hydrates it via the aggregate's fromPrimitives. */
|
|
10
|
+
async one(filter) {
|
|
11
|
+
const collection = await this.collection();
|
|
12
|
+
const result = await collection.findOne(filter);
|
|
13
|
+
if (!result) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const { _id, ...rest } = result;
|
|
17
|
+
return this.aggregateRootClass.fromPrimitives(rest);
|
|
18
|
+
}
|
|
19
|
+
/** Upserts an aggregate by delegating to persist with its id. */
|
|
20
|
+
async upsert(entity) {
|
|
21
|
+
return this.persist(entity.getId(), entity);
|
|
22
|
+
}
|
|
23
|
+
/** Lists entities by criteria and returns a paginated response. */
|
|
24
|
+
async list(criteria, fieldsToExclude = []) {
|
|
25
|
+
const documents = await this.searchByCriteria(criteria, fieldsToExclude);
|
|
26
|
+
return this.paginate(documents);
|
|
27
|
+
}
|
|
28
|
+
async collection() {
|
|
29
|
+
return (await MongoClientFactory.createClient())
|
|
30
|
+
.db()
|
|
31
|
+
.collection(this.collectionName());
|
|
32
|
+
}
|
|
33
|
+
async updateOne(filter, update) {
|
|
34
|
+
const collection = await this.collection();
|
|
35
|
+
const result = await collection.updateOne(filter, update, {
|
|
36
|
+
upsert: true,
|
|
37
|
+
});
|
|
38
|
+
return result.upsertedId;
|
|
39
|
+
}
|
|
40
|
+
async persist(id, aggregateRoot) {
|
|
41
|
+
let primitives;
|
|
42
|
+
if (aggregateRoot.toPrimitives() instanceof Promise) {
|
|
43
|
+
primitives = await aggregateRoot.toPrimitives();
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
primitives = aggregateRoot.toPrimitives();
|
|
47
|
+
}
|
|
48
|
+
return await this.updateOne({ _id: new ObjectId(id) }, {
|
|
49
|
+
$set: {
|
|
50
|
+
...primitives,
|
|
51
|
+
id: id,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async searchByCriteria(criteria, fieldsToExclude = []) {
|
|
56
|
+
this.criteria = criteria;
|
|
57
|
+
this.query = this.criteriaConverter.convert(criteria);
|
|
58
|
+
const collection = await this.collection();
|
|
59
|
+
if (fieldsToExclude.length === 0) {
|
|
60
|
+
const results = await collection
|
|
61
|
+
.find(this.query.filter, {})
|
|
62
|
+
.sort(this.query.sort)
|
|
63
|
+
.skip(this.query.skip)
|
|
64
|
+
.limit(this.query.limit)
|
|
65
|
+
.toArray();
|
|
66
|
+
return results.map(({ _id, ...rest }) => rest);
|
|
67
|
+
}
|
|
68
|
+
const projection = {};
|
|
69
|
+
fieldsToExclude.forEach((field) => {
|
|
70
|
+
projection[field] = 0;
|
|
71
|
+
});
|
|
72
|
+
const results = await collection
|
|
73
|
+
.find(this.query.filter, { projection })
|
|
74
|
+
.sort(this.query.sort)
|
|
75
|
+
.skip(this.query.skip)
|
|
76
|
+
.limit(this.query.limit)
|
|
77
|
+
.toArray();
|
|
78
|
+
return results.map(({ _id, ...rest }) => rest);
|
|
79
|
+
}
|
|
80
|
+
async paginate(documents) {
|
|
81
|
+
const collection = await this.collection();
|
|
82
|
+
const count = await collection.countDocuments(this.query.filter);
|
|
83
|
+
const limit = this.criteria?.limit || 10;
|
|
84
|
+
const currentPage = this.criteria?.currentPage || 1;
|
|
85
|
+
const hasNextPage = currentPage * limit < count;
|
|
86
|
+
if (documents.length === 0) {
|
|
87
|
+
return {
|
|
88
|
+
nextPag: null,
|
|
89
|
+
count: 0,
|
|
90
|
+
results: [],
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
nextPag: hasNextPage ? Number(this.criteria.currentPage) + 1 : null,
|
|
95
|
+
count: count,
|
|
96
|
+
results: documents,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export class EnumValueObject {
|
|
2
|
+
constructor(value, validValues) {
|
|
3
|
+
this.validValues = validValues;
|
|
4
|
+
this.value = value;
|
|
5
|
+
this.checkValueIsValid(value);
|
|
6
|
+
}
|
|
7
|
+
checkValueIsValid(value) {
|
|
8
|
+
if (!this.validValues.includes(value)) {
|
|
9
|
+
this.throwErrorForInvalidValue(value);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ValueObject } from "./ValueObject";
|
|
2
|
+
import { InvalidArgumentError } from "../exceptions/InvalidArgumentError.exception";
|
|
3
|
+
export class StringValueObject extends ValueObject {
|
|
4
|
+
constructor(value) {
|
|
5
|
+
super(value);
|
|
6
|
+
this.value = value;
|
|
7
|
+
this.ensureStringIsNotEmpty();
|
|
8
|
+
}
|
|
9
|
+
static create(value) {
|
|
10
|
+
return new StringValueObject(value);
|
|
11
|
+
}
|
|
12
|
+
getValue() {
|
|
13
|
+
return String(this.value);
|
|
14
|
+
}
|
|
15
|
+
ensureStringIsNotEmpty() {
|
|
16
|
+
if (typeof this.value !== "object" && this.value.length < 1) {
|
|
17
|
+
throw new InvalidArgumentError("String should have a length");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { InvalidArgumentError } from "../exceptions/InvalidArgumentError.exception";
|
|
2
|
+
export class ValueObject {
|
|
3
|
+
constructor(value) {
|
|
4
|
+
this.value = value;
|
|
5
|
+
this.ensureValueIsDefined(value);
|
|
6
|
+
}
|
|
7
|
+
equals(other) {
|
|
8
|
+
return (other.constructor.name === this.constructor.name &&
|
|
9
|
+
other.value === this.value);
|
|
10
|
+
}
|
|
11
|
+
toString() {
|
|
12
|
+
return this.value.toString();
|
|
13
|
+
}
|
|
14
|
+
ensureValueIsDefined(value) {
|
|
15
|
+
if (value === undefined) {
|
|
16
|
+
throw new InvalidArgumentError("Value must be defined");
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from "./FilterField";
|
|
2
|
+
export * from "./FilterOperator";
|
|
3
|
+
export * from "./FilterValue";
|
|
4
|
+
export * from "./OrderBy";
|
|
5
|
+
export * from "./Filter";
|
|
6
|
+
export * from "./Criteria";
|
|
7
|
+
export * from "./Filters";
|
|
8
|
+
export * from "./Order";
|
|
9
|
+
export * from "./Paginate";
|
|
10
|
+
export * from "./OrderType";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ObjectId } from "mongodb";
|
|
2
|
+
import { Criteria, Paginate } from "../criteria";
|
|
3
|
+
import { AggregateRoot } from "../AggregateRoot";
|
|
4
|
+
export interface IRepository<T extends AggregateRoot> {
|
|
5
|
+
one(filter: object): Promise<T | null>;
|
|
6
|
+
list<D>(criteria: Criteria, fieldsToExclude?: string[]): Promise<Paginate<D>>;
|
|
7
|
+
upsert(entity: T): Promise<ObjectId | null>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Criteria, Paginate } from "../criteria";
|
|
2
|
+
import { AggregateRoot, AggregateRootClass } from "../AggregateRoot";
|
|
3
|
+
import { Collection, ObjectId, UpdateFilter } from "mongodb";
|
|
4
|
+
export declare abstract class MongoRepository<T extends AggregateRoot> {
|
|
5
|
+
private readonly aggregateRootClass;
|
|
6
|
+
private criteriaConverter;
|
|
7
|
+
private query;
|
|
8
|
+
private criteria;
|
|
9
|
+
protected constructor(aggregateRootClass: AggregateRootClass<T>);
|
|
10
|
+
abstract collectionName(): string;
|
|
11
|
+
/** Finds a single entity and hydrates it via the aggregate's fromPrimitives. */
|
|
12
|
+
one(filter: object): Promise<T | null>;
|
|
13
|
+
/** Upserts an aggregate by delegating to persist with its id. */
|
|
14
|
+
upsert(entity: T): Promise<ObjectId | null>;
|
|
15
|
+
/** Lists entities by criteria and returns a paginated response. */
|
|
16
|
+
list<D>(criteria: Criteria, fieldsToExclude?: string[]): Promise<Paginate<D>>;
|
|
17
|
+
protected collection<T extends Document>(): Promise<Collection<T>>;
|
|
18
|
+
protected updateOne(filter: object, update: Document[] | UpdateFilter<any>): Promise<ObjectId | null>;
|
|
19
|
+
private persist;
|
|
20
|
+
private searchByCriteria;
|
|
21
|
+
private paginate;
|
|
22
|
+
}
|
package/package.json
CHANGED
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abejarano/ts-mongodb-criteria",
|
|
3
3
|
"author": "angel bejarano / angel.bejarano@jaspesoft.com",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.5.0",
|
|
5
5
|
"description": "Patrón Criteria para consultas MongoDB en TypeScript",
|
|
6
|
-
"main": "dist/index.js",
|
|
7
|
-
"
|
|
6
|
+
"main": "dist/cjs/index.js",
|
|
7
|
+
"module": "dist/esm/index.js",
|
|
8
|
+
"types": "dist/types/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/types/index.d.ts",
|
|
12
|
+
"import": "./dist/esm/index.js",
|
|
13
|
+
"require": "./dist/cjs/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
8
17
|
"files": [
|
|
9
18
|
"dist"
|
|
10
19
|
],
|
|
11
20
|
"scripts": {
|
|
12
|
-
"build": "
|
|
21
|
+
"build": "yarn build:cjs && yarn build:esm && yarn build:types",
|
|
22
|
+
"build:cjs": "tsc -p tsconfig.cjs.json",
|
|
23
|
+
"build:esm": "tsc -p tsconfig.esm.json",
|
|
24
|
+
"build:types": "tsc -p tsconfig.types.json",
|
|
13
25
|
"clean": "rimraf dist",
|
|
14
26
|
"prepare": "yarn build",
|
|
15
27
|
"prebuild": "yarn clean",
|
|
@@ -22,7 +34,8 @@
|
|
|
22
34
|
"version:major": "npm version major",
|
|
23
35
|
"test": "jest",
|
|
24
36
|
"test:watch": "jest --watch",
|
|
25
|
-
"test:coverage": "jest --coverage"
|
|
37
|
+
"test:coverage": "jest --coverage",
|
|
38
|
+
"test:bun": "bun test tests/bun"
|
|
26
39
|
},
|
|
27
40
|
"keywords": [
|
|
28
41
|
"mongodb",
|
package/dist/AggregateRoot.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Criteria, Paginate } from "../criteria";
|
|
2
|
-
import { AggregateRoot } from "../AggregateRoot";
|
|
3
|
-
import { Collection, ObjectId, UpdateFilter } from "mongodb";
|
|
4
|
-
export declare abstract class MongoRepository<T extends AggregateRoot> {
|
|
5
|
-
private criteriaConverter;
|
|
6
|
-
private query;
|
|
7
|
-
private criteria;
|
|
8
|
-
protected constructor();
|
|
9
|
-
abstract collectionName(): string;
|
|
10
|
-
paginate<T>(documents: T[]): Promise<Paginate<T>>;
|
|
11
|
-
protected collection<T extends Document>(): Promise<Collection<T>>;
|
|
12
|
-
protected persist(id: string, aggregateRoot: T): Promise<ObjectId | null>;
|
|
13
|
-
protected updateOne(filter: object, update: Document[] | UpdateFilter<any>): Promise<ObjectId | null>;
|
|
14
|
-
protected searchByCriteria<D>(criteria: Criteria, fieldsToExclude?: string[]): Promise<D[]>;
|
|
15
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|