@abejarano/ts-mongodb-criteria 1.2.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/README.md +329 -0
- package/dist/AggregateRoot.d.ts +4 -0
- package/dist/AggregateRoot.js +6 -0
- package/dist/criteria/Criteria.d.ts +11 -0
- package/dist/criteria/Criteria.js +19 -0
- package/dist/criteria/Filter.d.ts +10 -0
- package/dist/criteria/Filter.js +24 -0
- package/dist/criteria/FilterField.d.ts +4 -0
- package/dist/criteria/FilterField.js +10 -0
- package/dist/criteria/FilterOperator.d.ts +18 -0
- package/dist/criteria/FilterOperator.js +36 -0
- package/dist/criteria/FilterValue.d.ts +30 -0
- package/dist/criteria/FilterValue.js +74 -0
- package/dist/criteria/Filters.d.ts +8 -0
- package/dist/criteria/Filters.js +16 -0
- package/dist/criteria/Order.d.ts +12 -0
- package/dist/criteria/Order.js +30 -0
- package/dist/criteria/OrderBy.d.ts +7 -0
- package/dist/criteria/OrderBy.js +17 -0
- package/dist/criteria/OrderType.d.ts +13 -0
- package/dist/criteria/OrderType.js +34 -0
- package/dist/criteria/Paginate.d.ts +5 -0
- package/dist/criteria/Paginate.js +2 -0
- package/dist/criteria/index.d.ts +10 -0
- package/dist/criteria/index.js +26 -0
- package/dist/exceptions/InvalidArgumentError.exception.d.ts +2 -0
- package/dist/exceptions/InvalidArgumentError.exception.js +6 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +19 -0
- package/dist/mongo/MongoClientFactory.d.ts +17 -0
- package/dist/mongo/MongoClientFactory.js +49 -0
- package/dist/mongo/MongoCriteriaConverter.d.ts +43 -0
- package/dist/mongo/MongoCriteriaConverter.js +115 -0
- package/dist/mongo/MongoRepository.d.ts +15 -0
- package/dist/mongo/MongoRepository.js +95 -0
- package/dist/mongo/index.d.ts +3 -0
- package/dist/mongo/index.js +19 -0
- package/dist/valueObject/EnumValueObject.d.ts +7 -0
- package/dist/valueObject/EnumValueObject.js +16 -0
- package/dist/valueObject/StringValueObject.d.ts +8 -0
- package/dist/valueObject/StringValueObject.js +24 -0
- package/dist/valueObject/ValueObject.d.ts +8 -0
- package/dist/valueObject/ValueObject.js +23 -0
- package/dist/valueObject/index.d.ts +3 -0
- package/dist/valueObject/index.js +19 -0
- package/package.json +62 -0
package/README.md
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
# ๐ TypeScript MongoDB Criteria Pattern
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@abejarano/ts-mongodb-criteria)
|
|
4
|
+
[](https://github.com/abejarano/ts-mongo-criteria/packages)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
[](https://www.mongodb.com/)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
[](https://nodejs.org/)
|
|
9
|
+
[](#testing)
|
|
10
|
+
|
|
11
|
+
> A robust, type-safe implementation of the **Criteria Pattern** for MongoDB queries in TypeScript. Build complex database queries dynamically with a fluent, composable API designed following Domain-Driven Design (DDD) and Clean Architecture principles.
|
|
12
|
+
|
|
13
|
+
## ๐ Table of Contents
|
|
14
|
+
|
|
15
|
+
- [๐ฏ Overview](#-overview)
|
|
16
|
+
- [โจ Key Features](#-key-features)
|
|
17
|
+
- [๐ฆ Installation](#-installation)
|
|
18
|
+
- [๐ Quick Start](#-quick-start)
|
|
19
|
+
- [๐ Documentation](#-documentation)
|
|
20
|
+
- [๐งช Testing](#-testing)
|
|
21
|
+
- [๐ค Contributing](#-contributing)
|
|
22
|
+
- [๐ License](#-license)
|
|
23
|
+
|
|
24
|
+
## ๐ฏ Overview
|
|
25
|
+
|
|
26
|
+
The **Criteria Pattern** is a powerful design pattern that enables dynamic query construction without writing raw database queries. This library provides a type-safe, MongoDB-specific implementation that helps you:
|
|
27
|
+
|
|
28
|
+
- **Build queries dynamically** based on runtime conditions
|
|
29
|
+
- **Maintain type safety** throughout your query construction
|
|
30
|
+
- **Compose and reuse** query components across your application
|
|
31
|
+
- **Separate concerns** between query logic and data models
|
|
32
|
+
- **Test queries easily** with a mockable interface
|
|
33
|
+
|
|
34
|
+
### What is the Criteria Pattern?
|
|
35
|
+
|
|
36
|
+
The Criteria pattern encapsulates query logic in a structured, object-oriented way. Instead of building query strings or objects directly, you compose `Criteria` objects that represent your search intentions. This approach provides flexibility, reusability, testability, and type safety.
|
|
37
|
+
|
|
38
|
+
## โจ Key Features
|
|
39
|
+
|
|
40
|
+
### ๐ **Type Safety First**
|
|
41
|
+
|
|
42
|
+
- Full TypeScript support with strict typing
|
|
43
|
+
- Compile-time validation of query structure
|
|
44
|
+
- IntelliSense support for all operations
|
|
45
|
+
|
|
46
|
+
### ๐งฉ **Flexible Query Building**
|
|
47
|
+
|
|
48
|
+
- Support for all common MongoDB operators (EQUAL, NOT_EQUAL, GT, GTE, LT, LTE, CONTAINS, NOT_CONTAINS)
|
|
49
|
+
- **NEW**: OR operator for complex logical combinations
|
|
50
|
+
- Composable filters that can be combined and reused
|
|
51
|
+
- Dynamic query construction based on runtime conditions
|
|
52
|
+
|
|
53
|
+
### ๐ **Advanced Querying**
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// Simple equality
|
|
57
|
+
{ status: { $eq: "active" } }
|
|
58
|
+
|
|
59
|
+
// Complex OR conditions
|
|
60
|
+
{ $or: [
|
|
61
|
+
{ name: { $regex: "john" } },
|
|
62
|
+
{ email: { $regex: "john" } }
|
|
63
|
+
]}
|
|
64
|
+
|
|
65
|
+
// Range queries
|
|
66
|
+
{ age: { $gte: 18 }, price: { $lte: 999.99 } }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### ๐ฏ **MongoDB Optimized**
|
|
70
|
+
|
|
71
|
+
- Native MongoDB 6.0+ support
|
|
72
|
+
- Efficient query generation
|
|
73
|
+
- Automatic index-friendly query structure
|
|
74
|
+
|
|
75
|
+
### ๐ฆ **Zero Dependencies**
|
|
76
|
+
|
|
77
|
+
- Only peer dependencies (MongoDB driver)
|
|
78
|
+
- Lightweight bundle size
|
|
79
|
+
|
|
80
|
+
### ๐๏ธ **Clean Architecture**
|
|
81
|
+
|
|
82
|
+
- Repository pattern implementation
|
|
83
|
+
- Domain-driven design principles
|
|
84
|
+
- Separation of concerns
|
|
85
|
+
|
|
86
|
+
## ๐ฆ Installation
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Using npm
|
|
90
|
+
npm install @abejarano/ts-mongodb-criteria
|
|
91
|
+
|
|
92
|
+
# Using yarn
|
|
93
|
+
yarn add @abejarano/ts-mongodb-criteria
|
|
94
|
+
|
|
95
|
+
# Using pnpm
|
|
96
|
+
pnpm add @abejarano/ts-mongodb-criteria
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Peer Dependencies
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# MongoDB driver (required)
|
|
103
|
+
npm install mongodb@^6.0.0
|
|
104
|
+
|
|
105
|
+
# TypeScript (for development)
|
|
106
|
+
npm install -D typescript@^5.0.0
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### System Requirements
|
|
110
|
+
|
|
111
|
+
- **Node.js**: 20.0.0 or higher
|
|
112
|
+
- **TypeScript**: 5.0.0 or higher (for development)
|
|
113
|
+
- **MongoDB**: 6.0.0 or higher
|
|
114
|
+
|
|
115
|
+
## ๐ Quick Start
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import {
|
|
119
|
+
Criteria,
|
|
120
|
+
Filters,
|
|
121
|
+
Order,
|
|
122
|
+
Operator,
|
|
123
|
+
MongoRepository,
|
|
124
|
+
} from "@abejarano/ts-mongodb-criteria"
|
|
125
|
+
|
|
126
|
+
// 1. Create filters using a simple Map-based syntax
|
|
127
|
+
const filters = [
|
|
128
|
+
new Map([
|
|
129
|
+
["field", "status"],
|
|
130
|
+
["operator", Operator.EQUAL],
|
|
131
|
+
["value", "active"],
|
|
132
|
+
]),
|
|
133
|
+
new Map([
|
|
134
|
+
["field", "age"],
|
|
135
|
+
["operator", Operator.GTE],
|
|
136
|
+
["value", "18"],
|
|
137
|
+
]),
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
// 2. Build criteria with filters, sorting, and pagination
|
|
141
|
+
const criteria = new Criteria(
|
|
142
|
+
Filters.fromValues(filters),
|
|
143
|
+
Order.desc("createdAt"),
|
|
144
|
+
20, // limit
|
|
145
|
+
1 // page
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
// 3. Use with your MongoDB repository
|
|
149
|
+
class UserRepository extends MongoRepository<User> {
|
|
150
|
+
collectionName(): string {
|
|
151
|
+
return "users"
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const userRepo = new UserRepository()
|
|
156
|
+
const users = await userRepo.searchByCriteria(criteria)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Your First Query in 30 Seconds:**
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
// Find active users over 18, sorted by creation date
|
|
163
|
+
const activeAdultUsers = new Criteria(
|
|
164
|
+
Filters.fromValues([
|
|
165
|
+
new Map([
|
|
166
|
+
["field", "status"],
|
|
167
|
+
["operator", Operator.EQUAL],
|
|
168
|
+
["value", "active"],
|
|
169
|
+
]),
|
|
170
|
+
new Map([
|
|
171
|
+
["field", "age"],
|
|
172
|
+
["operator", Operator.GTE],
|
|
173
|
+
["value", "18"],
|
|
174
|
+
]),
|
|
175
|
+
]),
|
|
176
|
+
Order.desc("createdAt"),
|
|
177
|
+
10, // Get 10 results
|
|
178
|
+
1 // First page
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
const results = await repository.searchByCriteria(activeAdultUsers)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## ๐ Documentation
|
|
185
|
+
|
|
186
|
+
### ๐ Complete Documentation
|
|
187
|
+
|
|
188
|
+
- **[๐ Quick Start Guide](./docs/quick-start.md)** - Get up and running in minutes
|
|
189
|
+
- **[๐๏ธ Criteria Pattern Guide](./docs/criteria-pattern.md)** - Deep dive into the pattern, architecture, and theory
|
|
190
|
+
- **[๐ง Operators Reference](./docs/operators.md)** - Complete guide to all available operators and their usage
|
|
191
|
+
- **[โก Performance Guide](./docs/performance.md)** - Optimization strategies and best practices
|
|
192
|
+
- **[๐ Migration Guide](./docs/migration.md)** - Migrate from other query systems to Criteria pattern
|
|
193
|
+
|
|
194
|
+
### ๐ฏ Key Concepts
|
|
195
|
+
|
|
196
|
+
#### 1. **Criteria** - The main query builder
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
const criteria = new Criteria(filters, order, limit?, page?)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
#### 2. **Filters** - Collection of filter conditions
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
const filters = Filters.fromValues([...filterMaps])
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### 3. **Order** - Sorting specification
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
const order = Order.desc("createdAt") // or Order.asc("name")
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
#### 4. **Operators** - Available filter operations
|
|
215
|
+
|
|
216
|
+
- `EQUAL`, `NOT_EQUAL` - Exact matching
|
|
217
|
+
- `GT`, `GTE`, `LT`, `LTE` - Range operations
|
|
218
|
+
- `BETWEEN` - Inclusive range with lower and upper bounds
|
|
219
|
+
- `CONTAINS`, `NOT_CONTAINS` - Text search
|
|
220
|
+
- `OR` - Logical OR combinations
|
|
221
|
+
|
|
222
|
+
### ๐ OR Operator Example
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
import { OrCondition } from "@abejarano/ts-mongodb-criteria"
|
|
226
|
+
|
|
227
|
+
// Search across multiple fields
|
|
228
|
+
const searchConditions: OrCondition[] = [
|
|
229
|
+
{ field: "name", operator: Operator.CONTAINS, value: "john" },
|
|
230
|
+
{ field: "email", operator: Operator.CONTAINS, value: "john" },
|
|
231
|
+
]
|
|
232
|
+
|
|
233
|
+
const filters = [
|
|
234
|
+
new Map([
|
|
235
|
+
["field", "search"],
|
|
236
|
+
["operator", Operator.OR],
|
|
237
|
+
["value", searchConditions],
|
|
238
|
+
]),
|
|
239
|
+
]
|
|
240
|
+
|
|
241
|
+
// Generates: { $or: [
|
|
242
|
+
// { name: { $regex: "john" } },
|
|
243
|
+
// { email: { $regex: "john" } }
|
|
244
|
+
// ]}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### โฑ๏ธ BETWEEN Operator Example
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
// Filter users created between two dates
|
|
251
|
+
const filters = [
|
|
252
|
+
new Map([
|
|
253
|
+
["field", "createdAt"],
|
|
254
|
+
["operator", Operator.BETWEEN],
|
|
255
|
+
["value", { start: new Date("2024-01-01"), end: new Date("2024-01-31") }],
|
|
256
|
+
]),
|
|
257
|
+
]
|
|
258
|
+
|
|
259
|
+
const criteria = new Criteria(Filters.fromValues(filters), Order.none())
|
|
260
|
+
|
|
261
|
+
// Generates: { createdAt: { $gte: 2024-01-01, $lte: 2024-01-31 } }
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## ๐งช Testing
|
|
265
|
+
|
|
266
|
+
The library includes comprehensive test coverage (30/30 tests passing).
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
# Run all tests
|
|
270
|
+
npm test
|
|
271
|
+
|
|
272
|
+
# Run tests in watch mode
|
|
273
|
+
npm run test:watch
|
|
274
|
+
|
|
275
|
+
# Run tests with coverage
|
|
276
|
+
npm run test:coverage
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## ๐ค Contributing
|
|
280
|
+
|
|
281
|
+
We welcome contributions! Please follow these guidelines:
|
|
282
|
+
|
|
283
|
+
### Development Setup
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
# Clone the repository
|
|
287
|
+
git clone https://github.com/abejarano/ts-mongo-criteria.git
|
|
288
|
+
cd ts-mongo-criteria
|
|
289
|
+
|
|
290
|
+
# Install dependencies
|
|
291
|
+
yarn install
|
|
292
|
+
|
|
293
|
+
# Run tests
|
|
294
|
+
yarn test
|
|
295
|
+
|
|
296
|
+
# Build the project
|
|
297
|
+
yarn build
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Contribution Process
|
|
301
|
+
|
|
302
|
+
1. **Fork** the repository
|
|
303
|
+
2. **Create** a feature branch (`git checkout -b feature/amazing-feature`)
|
|
304
|
+
3. **Write** tests for your changes
|
|
305
|
+
4. **Ensure** all tests pass (`yarn test`)
|
|
306
|
+
5. **Commit** using conventional commits (`git commit -m 'feat: add amazing feature'`)
|
|
307
|
+
6. **Push** to your branch (`git push origin feature/amazing-feature`)
|
|
308
|
+
7. **Open** a Pull Request
|
|
309
|
+
|
|
310
|
+
## ๐ License
|
|
311
|
+
|
|
312
|
+
This project is licensed under the **MIT License**. See the [LICENSE](LICENSE) file for details.
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## ๐จโ๐ป Author
|
|
317
|
+
|
|
318
|
+
**รngel Bejarano**
|
|
319
|
+
๐ง [angel.bejarano@jaspesoft.com](mailto:angel.bejarano@jaspesoft.com)
|
|
320
|
+
๐ [GitHub](https://github.com/abejarano)
|
|
321
|
+
๐ข [Jaspesoft](https://jaspesoft.com)
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
โญ๏ธ **If this project helps you, please give it a star on GitHub!**
|
|
326
|
+
|
|
327
|
+
๐ค **Questions or suggestions?** Open an issue or start a discussion.
|
|
328
|
+
|
|
329
|
+
๐ข **Follow us** for updates and new features!
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Filters } from "./Filters";
|
|
2
|
+
import { Order } from "./Order";
|
|
3
|
+
export declare class Criteria {
|
|
4
|
+
readonly filters: Filters;
|
|
5
|
+
readonly order: Order;
|
|
6
|
+
readonly limit?: number;
|
|
7
|
+
readonly offset?: number;
|
|
8
|
+
readonly currentPage?: number;
|
|
9
|
+
constructor(filters: Filters, order: Order, limit?: number, offset?: number);
|
|
10
|
+
hasFilters(): boolean;
|
|
11
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Criteria = void 0;
|
|
4
|
+
class Criteria {
|
|
5
|
+
constructor(filters, order, limit, offset) {
|
|
6
|
+
this.filters = filters;
|
|
7
|
+
this.order = order;
|
|
8
|
+
this.limit = limit;
|
|
9
|
+
this.currentPage = offset;
|
|
10
|
+
this.offset =
|
|
11
|
+
offset !== undefined && limit !== undefined
|
|
12
|
+
? (offset - 1) * limit
|
|
13
|
+
: undefined;
|
|
14
|
+
}
|
|
15
|
+
hasFilters() {
|
|
16
|
+
return this.filters.filters.length > 0;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.Criteria = Criteria;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FilterField } from "./FilterField";
|
|
2
|
+
import { FilterOperator } from "./FilterOperator";
|
|
3
|
+
import { FilterInputValue, FilterValue } from "./FilterValue";
|
|
4
|
+
export declare class Filter {
|
|
5
|
+
readonly field: FilterField;
|
|
6
|
+
readonly operator: FilterOperator;
|
|
7
|
+
readonly value: FilterValue;
|
|
8
|
+
constructor(field: FilterField, operator: FilterOperator, value: FilterValue);
|
|
9
|
+
static fromValues(values: Map<string, FilterInputValue>): Filter;
|
|
10
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Filter = void 0;
|
|
4
|
+
const FilterField_1 = require("./FilterField");
|
|
5
|
+
const FilterOperator_1 = require("./FilterOperator");
|
|
6
|
+
const FilterValue_1 = require("./FilterValue");
|
|
7
|
+
const InvalidArgumentError_exception_1 = require("../exceptions/InvalidArgumentError.exception");
|
|
8
|
+
class Filter {
|
|
9
|
+
constructor(field, operator, value) {
|
|
10
|
+
this.field = field;
|
|
11
|
+
this.operator = operator;
|
|
12
|
+
this.value = value;
|
|
13
|
+
}
|
|
14
|
+
static fromValues(values) {
|
|
15
|
+
const field = values.get("field");
|
|
16
|
+
const operator = values.get("operator");
|
|
17
|
+
const value = values.get("value");
|
|
18
|
+
if (!field || !operator || value === undefined) {
|
|
19
|
+
throw new InvalidArgumentError_exception_1.InvalidArgumentError(`The filter is invalid`);
|
|
20
|
+
}
|
|
21
|
+
return new Filter(new FilterField_1.FilterField(field), FilterOperator_1.FilterOperator.fromValue(operator), new FilterValue_1.FilterValue(value));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.Filter = Filter;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FilterField = void 0;
|
|
4
|
+
const valueObject_1 = require("../valueObject");
|
|
5
|
+
class FilterField extends valueObject_1.StringValueObject {
|
|
6
|
+
constructor(value) {
|
|
7
|
+
super(value);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.FilterField = FilterField;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare enum Operator {
|
|
2
|
+
EQUAL = "=",
|
|
3
|
+
NOT_EQUAL = "!=",
|
|
4
|
+
GT = ">",
|
|
5
|
+
LT = "<",
|
|
6
|
+
CONTAINS = "CONTAINS",
|
|
7
|
+
NOT_CONTAINS = "NOT_CONTAINS",
|
|
8
|
+
GTE = ">=",
|
|
9
|
+
LTE = "<=",
|
|
10
|
+
BETWEEN = "BETWEEN",
|
|
11
|
+
OR = "OR"
|
|
12
|
+
}
|
|
13
|
+
export declare class FilterOperator {
|
|
14
|
+
value: Operator;
|
|
15
|
+
constructor(value: Operator);
|
|
16
|
+
static fromValue(value: string): FilterOperator;
|
|
17
|
+
protected throwErrorForInvalidValue(value: Operator): void;
|
|
18
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FilterOperator = exports.Operator = void 0;
|
|
4
|
+
const InvalidArgumentError_exception_1 = require("../exceptions/InvalidArgumentError.exception");
|
|
5
|
+
var Operator;
|
|
6
|
+
(function (Operator) {
|
|
7
|
+
Operator["EQUAL"] = "=";
|
|
8
|
+
Operator["NOT_EQUAL"] = "!=";
|
|
9
|
+
Operator["GT"] = ">";
|
|
10
|
+
Operator["LT"] = "<";
|
|
11
|
+
Operator["CONTAINS"] = "CONTAINS";
|
|
12
|
+
Operator["NOT_CONTAINS"] = "NOT_CONTAINS";
|
|
13
|
+
Operator["GTE"] = ">=";
|
|
14
|
+
Operator["LTE"] = "<=";
|
|
15
|
+
Operator["BETWEEN"] = "BETWEEN";
|
|
16
|
+
Operator["OR"] = "OR";
|
|
17
|
+
})(Operator || (exports.Operator = Operator = {}));
|
|
18
|
+
//export class FilterOperator extends EnumValueObject<Operator> {
|
|
19
|
+
class FilterOperator {
|
|
20
|
+
constructor(value) {
|
|
21
|
+
this.value = value;
|
|
22
|
+
//super(value, Object.values(Operator));
|
|
23
|
+
}
|
|
24
|
+
static fromValue(value) {
|
|
25
|
+
for (const operatorValue of Object.values(Operator)) {
|
|
26
|
+
if (value === operatorValue.toString()) {
|
|
27
|
+
return new FilterOperator(operatorValue);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
throw new InvalidArgumentError_exception_1.InvalidArgumentError(`The filter operator ${value} is invalid`);
|
|
31
|
+
}
|
|
32
|
+
throwErrorForInvalidValue(value) {
|
|
33
|
+
throw new InvalidArgumentError_exception_1.InvalidArgumentError(`The filter operator ${value} is invalid`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.FilterOperator = FilterOperator;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { StringValueObject } from "../valueObject";
|
|
2
|
+
import { Operator } from "./FilterOperator";
|
|
3
|
+
export interface OrCondition {
|
|
4
|
+
field: string;
|
|
5
|
+
operator: Operator;
|
|
6
|
+
value: string;
|
|
7
|
+
}
|
|
8
|
+
export type FilterPrimitive = string | number | boolean | Date;
|
|
9
|
+
export type BetweenValue = {
|
|
10
|
+
start: FilterPrimitive;
|
|
11
|
+
end: FilterPrimitive;
|
|
12
|
+
} | {
|
|
13
|
+
startDate: FilterPrimitive;
|
|
14
|
+
endDate: FilterPrimitive;
|
|
15
|
+
} | {
|
|
16
|
+
from: FilterPrimitive;
|
|
17
|
+
to: FilterPrimitive;
|
|
18
|
+
};
|
|
19
|
+
export type FilterInputValue = FilterPrimitive | FilterPrimitive[] | OrCondition[] | BetweenValue;
|
|
20
|
+
export declare class FilterValue extends StringValueObject {
|
|
21
|
+
private readonly _originalValue;
|
|
22
|
+
constructor(value: FilterInputValue);
|
|
23
|
+
get isOrConditions(): boolean;
|
|
24
|
+
get asOrConditions(): OrCondition[];
|
|
25
|
+
get isBetween(): boolean;
|
|
26
|
+
get asBetween(): {
|
|
27
|
+
start: FilterPrimitive;
|
|
28
|
+
end: FilterPrimitive;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FilterValue = void 0;
|
|
4
|
+
const valueObject_1 = require("../valueObject");
|
|
5
|
+
const isOrConditionArray = (value) => {
|
|
6
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
const candidate = value[0];
|
|
10
|
+
return (typeof candidate === "object" &&
|
|
11
|
+
candidate !== null &&
|
|
12
|
+
"field" in candidate &&
|
|
13
|
+
"operator" in candidate &&
|
|
14
|
+
"value" in candidate);
|
|
15
|
+
};
|
|
16
|
+
const isBetweenObject = (value) => {
|
|
17
|
+
if (value === null || typeof value !== "object") {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
const candidate = value;
|
|
21
|
+
const hasStartEnd = "start" in candidate && "end" in candidate;
|
|
22
|
+
const hasStartDateEndDate = "startDate" in candidate && "endDate" in candidate;
|
|
23
|
+
const hasFromTo = "from" in candidate && "to" in candidate;
|
|
24
|
+
return hasStartEnd || hasStartDateEndDate || hasFromTo;
|
|
25
|
+
};
|
|
26
|
+
const normalizeBetweenValue = (value) => {
|
|
27
|
+
if ("start" in value && "end" in value) {
|
|
28
|
+
return { start: value.start, end: value.end };
|
|
29
|
+
}
|
|
30
|
+
if ("startDate" in value && "endDate" in value) {
|
|
31
|
+
return { start: value.startDate, end: value.endDate };
|
|
32
|
+
}
|
|
33
|
+
return { start: value.from, end: value.to };
|
|
34
|
+
};
|
|
35
|
+
class FilterValue extends valueObject_1.StringValueObject {
|
|
36
|
+
constructor(value) {
|
|
37
|
+
if (Array.isArray(value) && isOrConditionArray(value)) {
|
|
38
|
+
// Handle OrCondition[]
|
|
39
|
+
super(JSON.stringify(value));
|
|
40
|
+
}
|
|
41
|
+
else if (Array.isArray(value)) {
|
|
42
|
+
// Handle primitive arrays (kept for backward compatibility)
|
|
43
|
+
super(value.join(","));
|
|
44
|
+
}
|
|
45
|
+
else if (isBetweenObject(value)) {
|
|
46
|
+
// Store serialized version but keep original reference
|
|
47
|
+
super(JSON.stringify(value));
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// Handle primitive values (string, number, boolean, Date)
|
|
51
|
+
super(value);
|
|
52
|
+
}
|
|
53
|
+
this._originalValue = value;
|
|
54
|
+
}
|
|
55
|
+
get isOrConditions() {
|
|
56
|
+
return isOrConditionArray(this._originalValue);
|
|
57
|
+
}
|
|
58
|
+
get asOrConditions() {
|
|
59
|
+
if (this.isOrConditions) {
|
|
60
|
+
return this._originalValue;
|
|
61
|
+
}
|
|
62
|
+
throw new Error("Value is not an OrCondition array");
|
|
63
|
+
}
|
|
64
|
+
get isBetween() {
|
|
65
|
+
return isBetweenObject(this._originalValue);
|
|
66
|
+
}
|
|
67
|
+
get asBetween() {
|
|
68
|
+
if (this.isBetween) {
|
|
69
|
+
return normalizeBetweenValue(this._originalValue);
|
|
70
|
+
}
|
|
71
|
+
throw new Error("Value is not a BETWEEN structure");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.FilterValue = FilterValue;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Filter } from "./Filter";
|
|
2
|
+
import { FilterInputValue } from "./FilterValue";
|
|
3
|
+
export declare class Filters {
|
|
4
|
+
readonly filters: Filter[];
|
|
5
|
+
constructor(filters: Filter[]);
|
|
6
|
+
static fromValues(filters: Array<Map<string, FilterInputValue>>): Filters;
|
|
7
|
+
static none(): Filters;
|
|
8
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Filters = void 0;
|
|
4
|
+
const Filter_1 = require("./Filter");
|
|
5
|
+
class Filters {
|
|
6
|
+
constructor(filters) {
|
|
7
|
+
this.filters = filters;
|
|
8
|
+
}
|
|
9
|
+
static fromValues(filters) {
|
|
10
|
+
return new Filters(filters.map((values) => Filter_1.Filter.fromValues(values)));
|
|
11
|
+
}
|
|
12
|
+
static none() {
|
|
13
|
+
return new Filters([]);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.Filters = Filters;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { OrderBy } from "./OrderBy";
|
|
2
|
+
import { OrderType } from "./OrderType";
|
|
3
|
+
export declare class Order {
|
|
4
|
+
readonly orderBy: OrderBy;
|
|
5
|
+
readonly orderType: OrderType;
|
|
6
|
+
constructor(orderBy: OrderBy, orderType: OrderType);
|
|
7
|
+
static fromValues(orderBy?: string, orderType?: string): Order;
|
|
8
|
+
static none(): Order;
|
|
9
|
+
static desc(orderBy: string): Order;
|
|
10
|
+
static asc(orderBy: string): Order;
|
|
11
|
+
hasOrder(): boolean;
|
|
12
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Order = void 0;
|
|
4
|
+
const OrderBy_1 = require("./OrderBy");
|
|
5
|
+
const OrderType_1 = require("./OrderType");
|
|
6
|
+
class Order {
|
|
7
|
+
constructor(orderBy, orderType) {
|
|
8
|
+
this.orderBy = orderBy;
|
|
9
|
+
this.orderType = orderType;
|
|
10
|
+
}
|
|
11
|
+
static fromValues(orderBy, orderType) {
|
|
12
|
+
if (!orderBy) {
|
|
13
|
+
return Order.none();
|
|
14
|
+
}
|
|
15
|
+
return new Order(new OrderBy_1.OrderBy(orderBy), OrderType_1.OrderType.fromValue(orderType || OrderType_1.OrderTypes.ASC));
|
|
16
|
+
}
|
|
17
|
+
static none() {
|
|
18
|
+
return new Order(new OrderBy_1.OrderBy(""), new OrderType_1.OrderType(OrderType_1.OrderTypes.NONE));
|
|
19
|
+
}
|
|
20
|
+
static desc(orderBy) {
|
|
21
|
+
return new Order(new OrderBy_1.OrderBy(orderBy), new OrderType_1.OrderType(OrderType_1.OrderTypes.DESC));
|
|
22
|
+
}
|
|
23
|
+
static asc(orderBy) {
|
|
24
|
+
return new Order(new OrderBy_1.OrderBy(orderBy), new OrderType_1.OrderType(OrderType_1.OrderTypes.ASC));
|
|
25
|
+
}
|
|
26
|
+
hasOrder() {
|
|
27
|
+
return !this.orderType.isNone();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.Order = Order;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OrderBy = void 0;
|
|
4
|
+
const ValueObject_1 = require("../valueObject/ValueObject");
|
|
5
|
+
class OrderBy extends ValueObject_1.ValueObject {
|
|
6
|
+
constructor(value) {
|
|
7
|
+
super(value);
|
|
8
|
+
this.value = value;
|
|
9
|
+
}
|
|
10
|
+
static create(value) {
|
|
11
|
+
return new OrderBy(value);
|
|
12
|
+
}
|
|
13
|
+
getValue() {
|
|
14
|
+
return this.value;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.OrderBy = OrderBy;
|