@nulledexp/translatable-criteria 1.0.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/LICENSE +21 -0
- package/README.md +207 -0
- package/package.json +71 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Nelson Alberto Cabrera Quijada
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# @nulledexp/translatable-criteria
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@nulledexp/translatable-criteria)
|
|
4
|
+

|
|
5
|
+
[]()
|
|
6
|
+
[](./src/docs/introduction/en.md)
|
|
7
|
+
|
|
8
|
+
A TypeScript library for building data-source agnostic, translatable query criteria. Define complex filtering, ordering, and join logic in a structured, type-safe way, then translate it to your specific data source using custom translators.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @nulledexp/translatable-criteria
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Overview
|
|
17
|
+
|
|
18
|
+
This library simplifies the construction of complex data queries by providing a consistent and abstract way to define filtering, ordering, field selection, pagination (offset and cursor-based), and relationship (joins) configurations. The core concept revolves around the `Criteria` object hierarchy, which allows developers to define sophisticated query specifications in a data source-agnostic manner. These `Criteria` objects can then be processed by a `CriteriaTranslator` (using the Visitor pattern) to generate queries for various data sources.
|
|
19
|
+
|
|
20
|
+
## Key Features
|
|
21
|
+
|
|
22
|
+
- **Enhanced Type-Safety:** Construct queries with a fluent, strongly-typed interface, benefiting from compile-time and runtime validation of field names, aliases, and join parameters based on your schemas.
|
|
23
|
+
- **Powerful Filtering:** Define intricate filtering logic with multiple operators (including for JSON and arrays) and grouping. Filter groups are automatically normalized for consistency.
|
|
24
|
+
- **Flexible Join System:** Support for various join types (inner, left, full outer) and pivot table configurations, with validation of join parameters according to the relation type.
|
|
25
|
+
- **Default Join Field Selection:** When a join is added, if `setSelect()` is not explicitly called on the `JoinCriteria`, all fields from the joined schema will be automatically included in the main `SELECT` clause. This can be overridden by using `setSelect()` on the specific `JoinCriteria`.
|
|
26
|
+
- **Field Selection:** Specify exactly which fields to retrieve using `setSelect()`. Use `resetSelect()` to select all fields (which is also the default behavior).
|
|
27
|
+
- **Pagination:** Supports both offset-based (`setTake()`, `setSkip()`) and cursor-based (`setCursor()`) pagination.
|
|
28
|
+
- **Visitor Pattern for Translation:** Criteria objects implement an `accept` method, allowing for clean and extensible translation logic via the Visitor pattern.
|
|
29
|
+
- **Data Source Agnostic:** Design criteria independently of the underlying data source.
|
|
30
|
+
- **Translator-Based Architecture:** The core library defines criteria; actual translation is handled by separate translator packages that implement the `CriteriaTranslator` interface.
|
|
31
|
+
- **Full TypeScript Support:** Benefit from compile-time validation and autocompletion.
|
|
32
|
+
|
|
33
|
+
## Core Concepts
|
|
34
|
+
|
|
35
|
+
The library is built upon a few fundamental concepts. For detailed explanations, please refer to our Core Concepts Documentation.
|
|
36
|
+
|
|
37
|
+
- **`Criteria` Hierarchy:** Abstract base for query specifications (`RootCriteria`, `InnerJoinCriteria`, etc.). Learn more.
|
|
38
|
+
- **`CriteriaFactory`:** Recommended utility for creating `Criteria` instances (e.g., `CriteriaFactory.GetCriteria(...)`, `CriteriaFactory.GetInnerJoinCriteria(...)`). Learn more.
|
|
39
|
+
- **Schemas (`CriteriaSchema` & `GetTypedCriteriaSchema`):** Define your data entities' structure for type-safe criteria construction. Learn more.
|
|
40
|
+
- **`CriteriaTranslator`:** Abstract class for converting `Criteria` objects into specific data source queries using the Visitor pattern. Learn more.
|
|
41
|
+
|
|
42
|
+
## Usage Example (Core Library)
|
|
43
|
+
|
|
44
|
+
This package provides the tools to define your query criteria.
|
|
45
|
+
|
|
46
|
+
### 1. Define Schemas
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { GetTypedCriteriaSchema } from '@nulledexp/translatable-criteria';
|
|
50
|
+
|
|
51
|
+
export const UserSchema = GetTypedCriteriaSchema({
|
|
52
|
+
source_name: 'user',
|
|
53
|
+
alias: ['users', 'user', 'publisher'],
|
|
54
|
+
fields: ['uuid', 'email', 'username', 'created_at'],
|
|
55
|
+
joins: [
|
|
56
|
+
{ alias: 'posts', join_relation_type: 'one_to_many' },
|
|
57
|
+
// other joins like 'permissions', 'addresses' can be defined here
|
|
58
|
+
],
|
|
59
|
+
});
|
|
60
|
+
export type UserSchema = typeof UserSchema;
|
|
61
|
+
|
|
62
|
+
export const PostSchema = GetTypedCriteriaSchema({
|
|
63
|
+
source_name: 'post',
|
|
64
|
+
alias: ['posts', 'post'],
|
|
65
|
+
fields: [
|
|
66
|
+
'uuid',
|
|
67
|
+
'title',
|
|
68
|
+
'body',
|
|
69
|
+
'user_uuid',
|
|
70
|
+
'created_at',
|
|
71
|
+
'categories', // Example: for array filters
|
|
72
|
+
'metadata', // Example: for JSON filters
|
|
73
|
+
],
|
|
74
|
+
joins: [
|
|
75
|
+
{ alias: 'comments', join_relation_type: 'one_to_many' },
|
|
76
|
+
{ alias: 'publisher', join_relation_type: 'many_to_one' },
|
|
77
|
+
],
|
|
78
|
+
});
|
|
79
|
+
export type PostSchema = typeof PostSchema;
|
|
80
|
+
|
|
81
|
+
// Define other schemas (PermissionSchema, PostCommentSchema, AddressSchema) as needed for your application.
|
|
82
|
+
// See the full documentation for more examples.
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 2. Create Criteria
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import {
|
|
89
|
+
CriteriaFactory,
|
|
90
|
+
FilterOperator,
|
|
91
|
+
} from '@nulledexp/translatable-criteria';
|
|
92
|
+
import { UserSchema } from './path/to/your/criteria/schemas'; // Adjust path
|
|
93
|
+
|
|
94
|
+
// Create Criteria for the User entity
|
|
95
|
+
const userCriteria = CriteriaFactory.GetCriteria(UserSchema, 'users');
|
|
96
|
+
|
|
97
|
+
// Example: Add a simple filter
|
|
98
|
+
userCriteria.where({
|
|
99
|
+
field: 'email', // Type-safe based on UserSchema.fields
|
|
100
|
+
operator: FilterOperator.CONTAINS,
|
|
101
|
+
value: '@example.com',
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Example: Add ordering
|
|
105
|
+
userCriteria.orderBy('created_at', 'DESC');
|
|
106
|
+
|
|
107
|
+
// The 'userCriteria' object is now ready to be passed to a translator.
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Available Translators
|
|
111
|
+
|
|
112
|
+
To interact with a database, you'll need a translator package.
|
|
113
|
+
|
|
114
|
+
- **`@nulledexp/typeorm-mysql-criteria-translator`**:
|
|
115
|
+
A translator for generating TypeORM `SelectQueryBuilder` instances for MySQL.
|
|
116
|
+
- **Author:** Nelson Cabrera
|
|
117
|
+
- **Installation**:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npm install @nulledexp/typeorm-mysql-criteria-translator
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
- **Usage (basic)**:
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
import {
|
|
127
|
+
CriteriaFactory,
|
|
128
|
+
FilterOperator,
|
|
129
|
+
} from '@nulledexp/translatable-criteria';
|
|
130
|
+
import { TypeOrmMysqlTranslator } from '@nulledexp/typeorm-mysql-criteria-translator'; // Using new suggested name
|
|
131
|
+
import { UserSchema } from './path/to/your/criteria/schemas'; // Your Criteria Schema
|
|
132
|
+
// import { YourTypeOrmUserEntity } from './path/to/your/typeorm/entities'; // Your actual TypeORM entity
|
|
133
|
+
// import { DbDatasource } from './path-to-your-datasource-config'; // Your initialized TypeORM DataSource instance
|
|
134
|
+
|
|
135
|
+
// 1. Define your Criteria using @nulledexp/translatable-criteria
|
|
136
|
+
const criteria = CriteriaFactory.GetCriteria(UserSchema, 'users') // 'users' is an alias from UserSchema
|
|
137
|
+
.where({
|
|
138
|
+
field: 'username', // Field from UserSchema
|
|
139
|
+
operator: FilterOperator.EQUALS,
|
|
140
|
+
value: 'testuser',
|
|
141
|
+
})
|
|
142
|
+
.setTake(10);
|
|
143
|
+
|
|
144
|
+
// 2. Use the translator with your TypeORM QueryBuilder
|
|
145
|
+
// (Conceptual - assuming DbDatasource and YourTypeOrmUserEntity are set up)
|
|
146
|
+
|
|
147
|
+
// const queryBuilder = DbDatasource.getRepository(YourTypeOrmUserEntity)
|
|
148
|
+
// .createQueryBuilder(criteria.alias); // Alias must match root criteria alias
|
|
149
|
+
|
|
150
|
+
// const translator = new TypeOrmMysqlTranslator<YourTypeOrmUserEntity>();
|
|
151
|
+
// translator.translate(criteria, queryBuilder);
|
|
152
|
+
|
|
153
|
+
// Now queryBuilder is populated with the translated criteria
|
|
154
|
+
// console.log(queryBuilder.getSql(), queryBuilder.getParameters());
|
|
155
|
+
// const results = await queryBuilder.getMany();
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
- **Note:** This translator has been tested with integration tests. Please review its implementation at its repository (replace with actual repo link if different) to ensure it meets your specific project needs and production requirements. Contributions and bug reports are welcome!
|
|
159
|
+
|
|
160
|
+
- **(More translators coming soon or can be created by the community)**
|
|
161
|
+
|
|
162
|
+
### Developing Custom Translators
|
|
163
|
+
|
|
164
|
+
You can create your own translators by extending the abstract `CriteriaTranslator` class. See the Developing Custom Translators Guide for details.
|
|
165
|
+
|
|
166
|
+
## Type Safety Features
|
|
167
|
+
|
|
168
|
+
- Compile-time validation of field names within criteria based on schemas.
|
|
169
|
+
- Type-checked join configurations ensuring compatibility between schemas.
|
|
170
|
+
- Autocomplete support for schema fields and defined join aliases.
|
|
171
|
+
- Validation of alias usage in `Criteria` constructors.
|
|
172
|
+
- Robust validation of join parameters based on `join_relation_type`.
|
|
173
|
+
- Validation for selected fields, cursor fields, take/skip values.
|
|
174
|
+
- Strictly typed filter values based on the `FilterOperator` used.
|
|
175
|
+
|
|
176
|
+
## Roadmap (Core Library)
|
|
177
|
+
|
|
178
|
+
- [x] Implement cursor pagination.
|
|
179
|
+
- [x] Implement field selection (`setSelect`, `resetSelect`).
|
|
180
|
+
- [x] Implement `ORDER BY` for root and joined criteria (with `sequenceId` for stable global ordering).
|
|
181
|
+
- [x] Implement `LIMIT` and `OFFSET` (take/skip) for pagination.
|
|
182
|
+
- [x] Implement `PivotJoin` for many-to-many relationships.
|
|
183
|
+
- [x] Strictly typed filter values based on operator.
|
|
184
|
+
- [x] New filter operators (JSON, Array, Set).
|
|
185
|
+
- [x] Enhanced documentation with detailed examples for translator development.
|
|
186
|
+
- [x] `OuterJoinCriteria` support in the core logic.
|
|
187
|
+
- [ ] Explore utility functions to simplify translator development.
|
|
188
|
+
- [ ] Explore utility functions to simplify schema development.
|
|
189
|
+
- [ ] Add more comprehensive unit test coverage for criteria construction and edge cases.
|
|
190
|
+
|
|
191
|
+
## Contributing
|
|
192
|
+
|
|
193
|
+
This project is in active development. Contributions are welcome! Please feel free to submit a Pull Request on our GitHub repository.
|
|
194
|
+
|
|
195
|
+
## License
|
|
196
|
+
|
|
197
|
+
This project is licensed under the MIT License - see the `LICENSE` file for details.
|
|
198
|
+
|
|
199
|
+
## Contact
|
|
200
|
+
|
|
201
|
+
- **LinkedIn:** [Nelson Cabrera](https://www.linkedin.com/in/nulled-nelsoncabrera/)
|
|
202
|
+
- **Email:** [contact@nelsoncabrera.dev](mailto:contact@nelsoncabrera.dev)
|
|
203
|
+
- **GitHub:** [github.com/Techscq](https://github.com/Techscq)
|
|
204
|
+
|
|
205
|
+
## Author
|
|
206
|
+
|
|
207
|
+
Nelson Cabrera ([@Techscq](https://github.com/Techscq))
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nulledexp/translatable-criteria",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "A TypeScript library for building data-source agnostic, translatable query criteria. Define complex filtering, ordering, and join logic in a structured, type-safe way, then translate it to your specific data source using custom translators.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"criteria",
|
|
8
|
+
"query",
|
|
9
|
+
"filter",
|
|
10
|
+
"join",
|
|
11
|
+
"translator",
|
|
12
|
+
"data-access",
|
|
13
|
+
"query-builder",
|
|
14
|
+
"typescript",
|
|
15
|
+
"dsl",
|
|
16
|
+
"database",
|
|
17
|
+
"agnostic",
|
|
18
|
+
"data-source-agnostic"
|
|
19
|
+
],
|
|
20
|
+
"main": "./dist/index.js",
|
|
21
|
+
"exports": {
|
|
22
|
+
"./package.json": "./package.json",
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"import": "./dist/index.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "rimraf ./dist && tsc",
|
|
30
|
+
"ci": "npm run check-circular && npm run check-format && npm run check-exports && npm run test",
|
|
31
|
+
"format": "prettier --write .",
|
|
32
|
+
"check-format": "prettier --check .",
|
|
33
|
+
"check-exports": "attw --pack . --ignore-rules=cjs-resolves-to-esm",
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"dev": "vitest",
|
|
36
|
+
"build-watch": "tsc --watch",
|
|
37
|
+
"check-circular": "npx madge --circular --extensions ts ./src",
|
|
38
|
+
"local-release": "changeset version && changeset publish",
|
|
39
|
+
"prepublishOnly": "npm run ci"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/Techscq/translatable-criteria",
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/Techscq/translatable-criteria/issues"
|
|
44
|
+
},
|
|
45
|
+
"author": "Nelson Cabrera <contact@nelsoncabrera.dev>",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/Techscq/translatable-criteria.git"
|
|
49
|
+
},
|
|
50
|
+
"files": [
|
|
51
|
+
"dist",
|
|
52
|
+
"LICENSE",
|
|
53
|
+
"README.md"
|
|
54
|
+
],
|
|
55
|
+
"type": "module",
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@arethetypeswrong/cli": "^0.18.2",
|
|
58
|
+
"@changesets/cli": "^2.29.4",
|
|
59
|
+
"@types/node": "^24.0.0",
|
|
60
|
+
"@types/uuid": "^10.0.0",
|
|
61
|
+
"dotenv": "^16.5.0",
|
|
62
|
+
"madge": "^7.0.0",
|
|
63
|
+
"prettier": "^3.5.3",
|
|
64
|
+
"rimraf": "^6.0.1",
|
|
65
|
+
"ts-unused-exports": "^11.0.1",
|
|
66
|
+
"tsx": "^4.20.1",
|
|
67
|
+
"typescript": "^5.8.3",
|
|
68
|
+
"uuid": "^11.1.0",
|
|
69
|
+
"vitest": "^3.2.3"
|
|
70
|
+
}
|
|
71
|
+
}
|