@generazioneai/genquery 0.1.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 +28 -0
- package/README.md +218 -0
- package/dist/adapters/base.d.ts +32 -0
- package/dist/adapters/base.d.ts.map +1 -0
- package/dist/adapters/base.js +3 -0
- package/dist/adapters/base.js.map +1 -0
- package/dist/adapters/typeorm/adapter.d.ts +35 -0
- package/dist/adapters/typeorm/adapter.d.ts.map +1 -0
- package/dist/adapters/typeorm/adapter.js +111 -0
- package/dist/adapters/typeorm/adapter.js.map +1 -0
- package/dist/adapters/typeorm/aliases.d.ts +25 -0
- package/dist/adapters/typeorm/aliases.d.ts.map +1 -0
- package/dist/adapters/typeorm/aliases.js +47 -0
- package/dist/adapters/typeorm/aliases.js.map +1 -0
- package/dist/adapters/typeorm/create.d.ts +29 -0
- package/dist/adapters/typeorm/create.d.ts.map +1 -0
- package/dist/adapters/typeorm/create.js +29 -0
- package/dist/adapters/typeorm/create.js.map +1 -0
- package/dist/adapters/typeorm/escape.d.ts +5 -0
- package/dist/adapters/typeorm/escape.d.ts.map +1 -0
- package/dist/adapters/typeorm/escape.js +13 -0
- package/dist/adapters/typeorm/escape.js.map +1 -0
- package/dist/adapters/typeorm/index.d.ts +4 -0
- package/dist/adapters/typeorm/index.d.ts.map +1 -0
- package/dist/adapters/typeorm/index.js +10 -0
- package/dist/adapters/typeorm/index.js.map +1 -0
- package/dist/adapters/typeorm/joins.d.ts +29 -0
- package/dist/adapters/typeorm/joins.d.ts.map +1 -0
- package/dist/adapters/typeorm/joins.js +91 -0
- package/dist/adapters/typeorm/joins.js.map +1 -0
- package/dist/adapters/typeorm/params.d.ts +8 -0
- package/dist/adapters/typeorm/params.d.ts.map +1 -0
- package/dist/adapters/typeorm/params.js +15 -0
- package/dist/adapters/typeorm/params.js.map +1 -0
- package/dist/adapters/typeorm/schema-from-typeorm.d.ts +50 -0
- package/dist/adapters/typeorm/schema-from-typeorm.d.ts.map +1 -0
- package/dist/adapters/typeorm/schema-from-typeorm.js +170 -0
- package/dist/adapters/typeorm/schema-from-typeorm.js.map +1 -0
- package/dist/adapters/typeorm/where.d.ts +26 -0
- package/dist/adapters/typeorm/where.d.ts.map +1 -0
- package/dist/adapters/typeorm/where.js +297 -0
- package/dist/adapters/typeorm/where.js.map +1 -0
- package/dist/datetime.d.ts +4 -0
- package/dist/datetime.d.ts.map +1 -0
- package/dist/datetime.js +86 -0
- package/dist/datetime.js.map +1 -0
- package/dist/engine.d.ts +52 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +52 -0
- package/dist/engine.js.map +1 -0
- package/dist/errors.d.ts +10 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +16 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/parsed.d.ts +127 -0
- package/dist/parsed.d.ts.map +1 -0
- package/dist/parsed.js +8 -0
- package/dist/parsed.js.map +1 -0
- package/dist/parser.d.ts +5 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +404 -0
- package/dist/parser.js.map +1 -0
- package/dist/schema.d.ts +57 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +36 -0
- package/dist/schema.js.map +1 -0
- package/dist/types.d.ts +180 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +15 -0
- package/dist/types.js.map +1 -0
- package/package.json +70 -0
- package/spec.md +221 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, GenerazioneAi S.R.L. and genquery contributors
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# genquery
|
|
2
|
+
|
|
3
|
+
ORM-agnostic JSON query language with pluggable adapters.
|
|
4
|
+
|
|
5
|
+
Frontends send a `GenQueryInput` object. The backend validates it against a `Schema` and an adapter translates the result into ORM operations. The first adapter targets TypeORM (PostgreSQL-flavored SQL).
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @generazioneai/genquery
|
|
11
|
+
# TypeORM adapter (optional)
|
|
12
|
+
npm install typeorm
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick start (TypeORM)
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import "reflect-metadata";
|
|
19
|
+
import { DataSource } from "typeorm";
|
|
20
|
+
import { createTypeORMEngine } from "@generazioneai/genquery/typeorm";
|
|
21
|
+
|
|
22
|
+
// 1. Initialize TypeORM with your entity classes
|
|
23
|
+
const dataSource = new DataSource({ /* ... */ entities: [User, Post] });
|
|
24
|
+
await dataSource.initialize();
|
|
25
|
+
|
|
26
|
+
// 2. One line to set up the schema, adapter, and engine
|
|
27
|
+
const engine = createTypeORMEngine(dataSource);
|
|
28
|
+
|
|
29
|
+
// 3. Run a query from a request body
|
|
30
|
+
const qb = dataSource.getRepository(User).createQueryBuilder("User");
|
|
31
|
+
|
|
32
|
+
const result = engine.run(
|
|
33
|
+
{
|
|
34
|
+
searchBy: { firstName: "mario" },
|
|
35
|
+
orderBy: "createdAt",
|
|
36
|
+
pagination: { page: 0, perPage: 20 },
|
|
37
|
+
},
|
|
38
|
+
qb, // target QueryBuilder — entity name + entity type both read from this
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const users = await result.getMany();
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`createTypeORMEngine` is a thin wrapper around `schemaFromTypeORM` → `new TypeORMAdapter` → `new GenQueryEngine`. The root entity (`"User"` in this case) is derived from `qb.expressionMap.mainAlias.metadata.name` at runtime, and the TS entity type is read from `SelectQueryBuilder<User>`. If you need to override or your adapter can't introspect, the 3-arg form still works: `engine.run(input, "User", qb)`.
|
|
45
|
+
|
|
46
|
+
Need fine-grained control? You can still build it manually:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
const schema = schemaFromTypeORM(dataSource, { overrides: { User: { meta: "string" } } });
|
|
50
|
+
const adapter = new TypeORMAdapter(schema, { paramPrefix: "q" });
|
|
51
|
+
const engine = new GenQueryEngine({ adapter }); // schema is read from the adapter
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Or pass the same options to `createTypeORMEngine`:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
const engine = createTypeORMEngine(dataSource, {
|
|
58
|
+
schema: { overrides: { User: { meta: "string" } } },
|
|
59
|
+
adapter: { paramPrefix: "q" },
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Core concepts
|
|
64
|
+
|
|
65
|
+
### Schema
|
|
66
|
+
|
|
67
|
+
The `Schema` describes your data model independently of any ORM. The parser uses it to reject unknown fields; the adapter uses it to know which fields are dates vs strings vs relations.
|
|
68
|
+
|
|
69
|
+
With TypeORM, derive it from the DataSource — no duplication:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { schemaFromTypeORM } from "@generazioneai/genquery/typeorm";
|
|
73
|
+
|
|
74
|
+
const schema = schemaFromTypeORM(dataSource);
|
|
75
|
+
// optional: restrict to specific entities
|
|
76
|
+
const schema = schemaFromTypeORM(dataSource, { entities: [User, Post] });
|
|
77
|
+
// optional: override fields with non-standard column types
|
|
78
|
+
const schema = schemaFromTypeORM(dataSource, {
|
|
79
|
+
overrides: { User: { preferences: "string" } },
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Or declare one explicitly (no ORM, or fine-grained control):
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
const schema: Schema = {
|
|
87
|
+
entities: {
|
|
88
|
+
EntityName: {
|
|
89
|
+
name: "EntityName",
|
|
90
|
+
primaryKey: "id", // optional, defaults to "id"
|
|
91
|
+
fields: {
|
|
92
|
+
fieldName: { type: "string" | "number" | "boolean" | "date" },
|
|
93
|
+
},
|
|
94
|
+
relations: {
|
|
95
|
+
relationName: { target: "OtherEntity", kind: "one" | "many" },
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Query input
|
|
103
|
+
|
|
104
|
+
A `GenQueryInput` is a plain JSON object with five optional top-level keys.
|
|
105
|
+
|
|
106
|
+
The entity type is inferred automatically from the `target` argument when it has a recognizable shape (e.g. a TypeORM `SelectQueryBuilder<User>`). No explicit generic is required — autocomplete and value-shape checking flow from the QueryBuilder's entity type:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
const qb = dataSource.getRepository(User).createQueryBuilder("User");
|
|
110
|
+
// qb is SelectQueryBuilder<User> — entity type flows into the call below
|
|
111
|
+
|
|
112
|
+
engine.run(
|
|
113
|
+
{
|
|
114
|
+
searchBy: {
|
|
115
|
+
firstName: "mario", // OK
|
|
116
|
+
age: { operation: ">=", value: 18 }, // OK — number → comparison
|
|
117
|
+
birthDate: { after: "2000-01-01T00:00:00Z" }, // OK — date → range
|
|
118
|
+
posts: { title: "typescript" }, // OK — relation → recursive
|
|
119
|
+
// age: "x", // ✗ type error: number field can't take a string
|
|
120
|
+
// nope: "x", // ✗ type error: 'nope' isn't a field on User
|
|
121
|
+
},
|
|
122
|
+
orderBy: { field: "lastName", order: "asc" }, // ✓ field constrained to User keys
|
|
123
|
+
select: { firstName: true }, // ✓ only primitive fields
|
|
124
|
+
include: { posts: "all" }, // ✓ only relations
|
|
125
|
+
},
|
|
126
|
+
qb,
|
|
127
|
+
);
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The inference distinguishes fields (primitives → searchable / selectable) from relations (objects/arrays → includable / recursive search), and picks the right value shape per field type (string/number/boolean/Date/enum).
|
|
131
|
+
|
|
132
|
+
If your target type doesn't expose the entity (e.g. an adapter whose target is `undefined`), the input falls back to a loose form where any key/value is accepted — the runtime parser still validates everything against the schema.
|
|
133
|
+
|
|
134
|
+
Top-level keys:
|
|
135
|
+
|
|
136
|
+
| Key | Default | Purpose |
|
|
137
|
+
|-----|---------|---------|
|
|
138
|
+
| `searchBy` | — | Filter conditions (AND + OR) |
|
|
139
|
+
| `orderBy` | — | Sort field and direction |
|
|
140
|
+
| `select` | `"all"` | Which fields to return |
|
|
141
|
+
| `include` | `"none"` | Which relations to join |
|
|
142
|
+
| `pagination` | `"all"` | Page / limit |
|
|
143
|
+
|
|
144
|
+
Full query language reference: [docs/query-reference.md](docs/query-reference.md)
|
|
145
|
+
|
|
146
|
+
### Engine
|
|
147
|
+
|
|
148
|
+
`GenQueryEngine` is the public entry point. It asserts that the schema passed to it and the schema held by the adapter are the same instance.
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
const engine = new GenQueryEngine({ adapter }); // schema comes from the adapter
|
|
152
|
+
|
|
153
|
+
// parse + apply (rootEntity derived from target when the adapter supports it)
|
|
154
|
+
engine.run(input, target);
|
|
155
|
+
// or explicit rootEntity:
|
|
156
|
+
engine.run(input, rootEntity, target);
|
|
157
|
+
|
|
158
|
+
// parse only (requires explicit rootEntity — no target to infer from)
|
|
159
|
+
const parsed = engine.parse(input, rootEntity);
|
|
160
|
+
|
|
161
|
+
// apply a previously parsed query
|
|
162
|
+
engine.runParsed(parsed, target);
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Errors
|
|
166
|
+
|
|
167
|
+
Parse failures throw `QueryValidationError` with a `path` field pointing to the offending location in the input (e.g. `"searchBy.posts.title.value"`).
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { QueryValidationError } from "@generazioneai/genquery";
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
engine.run(input, "User", qb);
|
|
174
|
+
} catch (e) {
|
|
175
|
+
if (e instanceof QueryValidationError) {
|
|
176
|
+
console.error(e.path, e.message);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Examples
|
|
182
|
+
|
|
183
|
+
See [docs/examples.md](docs/examples.md) for full worked examples covering:
|
|
184
|
+
- String search modes (splitword, exact, nativeregex)
|
|
185
|
+
- Date ranges
|
|
186
|
+
- Numeric comparisons
|
|
187
|
+
- OR conditions
|
|
188
|
+
- Relation filtering and inclusion
|
|
189
|
+
- Pagination and sorting
|
|
190
|
+
|
|
191
|
+
## Architecture
|
|
192
|
+
|
|
193
|
+
Three layers, strictly separated:
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
Wire types (types.ts)
|
|
197
|
+
└─ Parser validates + normalizes → Parsed types (parsed.ts)
|
|
198
|
+
└─ Adapter consumes ParsedQuery + Schema → ORM output
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Adapters never see wire types. New adapters implement `Adapter<TTarget, TResult>` (re-exported from the package root).
|
|
202
|
+
|
|
203
|
+
See [docs/custom-adapter.md](docs/custom-adapter.md) for instructions.
|
|
204
|
+
|
|
205
|
+
## Documentation
|
|
206
|
+
|
|
207
|
+
| File | Contents |
|
|
208
|
+
|------|----------|
|
|
209
|
+
| [docs/getting-started.md](docs/getting-started.md) | Installation, setup, first query |
|
|
210
|
+
| [docs/query-reference.md](docs/query-reference.md) | Full query language reference |
|
|
211
|
+
| [docs/typeorm-adapter.md](docs/typeorm-adapter.md) | TypeORM adapter options and internals |
|
|
212
|
+
| [docs/custom-adapter.md](docs/custom-adapter.md) | Building a custom adapter |
|
|
213
|
+
| [docs/examples.md](docs/examples.md) | End-to-end examples |
|
|
214
|
+
| [spec.md](spec.md) | Source-of-truth wire format spec |
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
[BSD 3-Clause](LICENSE)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ParsedQuery } from "../parsed";
|
|
2
|
+
import type { Schema } from "../schema";
|
|
3
|
+
/**
|
|
4
|
+
* Adapters translate a `ParsedQuery` into ORM-specific operations.
|
|
5
|
+
*
|
|
6
|
+
* The interface is intentionally generic in both the host-provided target
|
|
7
|
+
* (e.g. a TypeORM `SelectQueryBuilder`, a Prisma client, ...) and the produced
|
|
8
|
+
* result (e.g. the same query builder mutated in place, a Prisma `findMany`
|
|
9
|
+
* argument object, ...). Each adapter declares the concrete shapes through
|
|
10
|
+
* its own module.
|
|
11
|
+
*/
|
|
12
|
+
export interface Adapter<TTarget, TResult> {
|
|
13
|
+
/** Stable adapter identifier (e.g. "typeorm", "prisma"). Useful for logging. */
|
|
14
|
+
readonly name: string;
|
|
15
|
+
/** Returns the schema the adapter was built against. */
|
|
16
|
+
readonly schema: Schema;
|
|
17
|
+
/**
|
|
18
|
+
* Apply the parsed query against `target`. Implementations are free to
|
|
19
|
+
* mutate `target` and return it, or to build a fresh value.
|
|
20
|
+
*/
|
|
21
|
+
apply(target: TTarget, query: ParsedQuery): TResult;
|
|
22
|
+
/**
|
|
23
|
+
* Optionally derive the root entity name from a target. When implemented,
|
|
24
|
+
* `engine.run(input, target)` can be called without an explicit
|
|
25
|
+
* `rootEntity` string — the engine asks the adapter to extract it from the
|
|
26
|
+
* target (e.g. TypeORM exposes it via `qb.expressionMap.mainAlias.metadata`).
|
|
27
|
+
* Return `undefined` if the target lacks the metadata; the engine will
|
|
28
|
+
* throw a helpful error.
|
|
29
|
+
*/
|
|
30
|
+
getRootEntity?(target: TTarget): string | undefined;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/adapters/base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAExC;;;;;;;;GAQG;AACH,MAAM,WAAW,OAAO,CAAC,OAAO,EAAE,OAAO;IACvC,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,wDAAwD;IACxD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC;IAEpD;;;;;;;OAOG;IACH,aAAa,CAAC,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;CACrD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/adapters/base.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type ObjectLiteral, type SelectQueryBuilder } from "typeorm";
|
|
2
|
+
import type { ParsedQuery } from "../../parsed";
|
|
3
|
+
import { type Schema } from "../../schema";
|
|
4
|
+
import type { Adapter } from "../base";
|
|
5
|
+
export interface TypeORMAdapterOptions {
|
|
6
|
+
/** Override the parameter name prefix used in generated SQL. */
|
|
7
|
+
paramPrefix?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Applies a parsed GenQuery to a TypeORM `SelectQueryBuilder`. The builder is
|
|
11
|
+
* mutated in place and returned for convenience.
|
|
12
|
+
*
|
|
13
|
+
* Typical use:
|
|
14
|
+
*
|
|
15
|
+
* const qb = userRepo.createQueryBuilder("user");
|
|
16
|
+
* adapter.apply(qb, parsed);
|
|
17
|
+
* const rows = await qb.getMany();
|
|
18
|
+
*/
|
|
19
|
+
export declare class TypeORMAdapter implements Adapter<SelectQueryBuilder<ObjectLiteral>, SelectQueryBuilder<ObjectLiteral>> {
|
|
20
|
+
readonly schema: Schema;
|
|
21
|
+
private readonly options;
|
|
22
|
+
readonly name = "typeorm";
|
|
23
|
+
constructor(schema: Schema, options?: TypeORMAdapterOptions);
|
|
24
|
+
/**
|
|
25
|
+
* Derive the root entity name from a TypeORM `SelectQueryBuilder`. Returns
|
|
26
|
+
* the entity class name as TypeORM knows it (e.g. `"User"`), so the engine
|
|
27
|
+
* can look it up in the schema without the caller having to repeat it.
|
|
28
|
+
*/
|
|
29
|
+
getRootEntity(qb: SelectQueryBuilder<ObjectLiteral>): string | undefined;
|
|
30
|
+
apply<T extends ObjectLiteral>(qb: SelectQueryBuilder<T>, query: ParsedQuery): SelectQueryBuilder<T>;
|
|
31
|
+
private applyRootSelect;
|
|
32
|
+
private applyJoin;
|
|
33
|
+
private applyPagination;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/typeorm/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAChF,OAAO,KAAK,EAAE,WAAW,EAAgB,MAAM,cAAc,CAAC;AAC9D,OAAO,EAEL,KAAK,MAAM,EAGZ,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAMvC,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;GASG;AACH,qBAAa,cACX,YACE,OAAO,CAAC,kBAAkB,CAAC,aAAa,CAAC,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAC;aAK7D,MAAM,EAAE,MAAM;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJ1B,QAAQ,CAAC,IAAI,aAAa;gBAGR,MAAM,EAAE,MAAM,EACb,OAAO,GAAE,qBAA0B;IAGtD;;;;OAIG;IACH,aAAa,CAAC,EAAE,EAAE,kBAAkB,CAAC,aAAa,CAAC,GAAG,MAAM,GAAG,SAAS;IAIxE,KAAK,CAAC,CAAC,SAAS,aAAa,EAC3B,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC,EACzB,KAAK,EAAE,WAAW,GACjB,kBAAkB,CAAC,CAAC,CAAC;IA8CxB,OAAO,CAAC,eAAe;IAkBvB,OAAO,CAAC,SAAS;IAuBjB,OAAO,CAAC,eAAe;CAWxB"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TypeORMAdapter = void 0;
|
|
4
|
+
const typeorm_1 = require("typeorm");
|
|
5
|
+
const schema_1 = require("../../schema");
|
|
6
|
+
const aliases_1 = require("./aliases");
|
|
7
|
+
const joins_1 = require("./joins");
|
|
8
|
+
const params_1 = require("./params");
|
|
9
|
+
const where_1 = require("./where");
|
|
10
|
+
/**
|
|
11
|
+
* Applies a parsed GenQuery to a TypeORM `SelectQueryBuilder`. The builder is
|
|
12
|
+
* mutated in place and returned for convenience.
|
|
13
|
+
*
|
|
14
|
+
* Typical use:
|
|
15
|
+
*
|
|
16
|
+
* const qb = userRepo.createQueryBuilder("user");
|
|
17
|
+
* adapter.apply(qb, parsed);
|
|
18
|
+
* const rows = await qb.getMany();
|
|
19
|
+
*/
|
|
20
|
+
class TypeORMAdapter {
|
|
21
|
+
constructor(schema, options = {}) {
|
|
22
|
+
this.schema = schema;
|
|
23
|
+
this.options = options;
|
|
24
|
+
this.name = "typeorm";
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Derive the root entity name from a TypeORM `SelectQueryBuilder`. Returns
|
|
28
|
+
* the entity class name as TypeORM knows it (e.g. `"User"`), so the engine
|
|
29
|
+
* can look it up in the schema without the caller having to repeat it.
|
|
30
|
+
*/
|
|
31
|
+
getRootEntity(qb) {
|
|
32
|
+
return qb.expressionMap?.mainAlias?.metadata?.name;
|
|
33
|
+
}
|
|
34
|
+
apply(qb, query) {
|
|
35
|
+
const rootEntity = (0, schema_1.getEntity)(this.schema, query.rootEntity);
|
|
36
|
+
const aliases = new aliases_1.AliasRegistry(qb.alias);
|
|
37
|
+
const params = new params_1.ParamCounter(this.options.paramPrefix);
|
|
38
|
+
// 1. Root selection (must happen before leftJoinAndSelect calls, since
|
|
39
|
+
// `.select()` replaces the entire selection list).
|
|
40
|
+
this.applyRootSelect(qb, rootEntity, query.select, aliases.root());
|
|
41
|
+
// 2. Plan + apply all joins (includes + searchBy relations).
|
|
42
|
+
const plans = (0, joins_1.planJoins)(query, this.schema, aliases);
|
|
43
|
+
for (const plan of plans) {
|
|
44
|
+
this.applyJoin(qb, plan);
|
|
45
|
+
}
|
|
46
|
+
// 3. WHERE.
|
|
47
|
+
if (query.searchBy) {
|
|
48
|
+
const ctx = {
|
|
49
|
+
schema: this.schema,
|
|
50
|
+
aliases,
|
|
51
|
+
params,
|
|
52
|
+
paramBag: {},
|
|
53
|
+
currentAlias: aliases.root(),
|
|
54
|
+
currentPath: "",
|
|
55
|
+
currentEntity: query.rootEntity,
|
|
56
|
+
connection: qb.connection,
|
|
57
|
+
};
|
|
58
|
+
qb.andWhere(new typeorm_1.Brackets((sub) => (0, where_1.applySearchByInside)(sub, query.searchBy, ctx)));
|
|
59
|
+
}
|
|
60
|
+
// 4. ORDER BY.
|
|
61
|
+
if (query.orderBy) {
|
|
62
|
+
qb.addOrderBy(`${aliases.root()}.${query.orderBy.field}`, query.orderBy.order.toUpperCase());
|
|
63
|
+
}
|
|
64
|
+
// 5. Pagination.
|
|
65
|
+
this.applyPagination(qb, query.pagination);
|
|
66
|
+
return qb;
|
|
67
|
+
}
|
|
68
|
+
applyRootSelect(qb, entity, select, rootAlias) {
|
|
69
|
+
if (select.kind === "all")
|
|
70
|
+
return; // default behaviour
|
|
71
|
+
const pk = (0, schema_1.primaryKeyOf)(entity);
|
|
72
|
+
if (select.kind === "none") {
|
|
73
|
+
qb.select([`${rootAlias}.${pk}`]);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
// fields
|
|
77
|
+
const set = new Set(select.fields);
|
|
78
|
+
set.add(pk); // keep primary key so hydration + relations still work
|
|
79
|
+
qb.select([...set].map((f) => `${rootAlias}.${f}`));
|
|
80
|
+
}
|
|
81
|
+
applyJoin(qb, plan) {
|
|
82
|
+
const targetEntity = (0, schema_1.getEntity)(this.schema, plan.targetEntity);
|
|
83
|
+
switch (plan.selection.kind) {
|
|
84
|
+
case "none":
|
|
85
|
+
qb.leftJoin(plan.propertyPath, plan.alias);
|
|
86
|
+
return;
|
|
87
|
+
case "all":
|
|
88
|
+
qb.leftJoinAndSelect(plan.propertyPath, plan.alias);
|
|
89
|
+
return;
|
|
90
|
+
case "fields": {
|
|
91
|
+
qb.leftJoin(plan.propertyPath, plan.alias);
|
|
92
|
+
const pk = (0, schema_1.primaryKeyOf)(targetEntity);
|
|
93
|
+
const set = new Set(plan.selection.fields);
|
|
94
|
+
set.add(pk);
|
|
95
|
+
qb.addSelect([...set].map((f) => `${plan.alias}.${f}`));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
applyPagination(qb, pagination) {
|
|
101
|
+
if (pagination.kind === "all")
|
|
102
|
+
return;
|
|
103
|
+
if (pagination.kind === "first") {
|
|
104
|
+
qb.skip(0).take(1);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
qb.skip(pagination.page * pagination.perPage).take(pagination.perPage);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.TypeORMAdapter = TypeORMAdapter;
|
|
111
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/adapters/typeorm/adapter.ts"],"names":[],"mappings":";;;AAAA,qCAAgF;AAEhF,yCAKsB;AAEtB,uCAA0C;AAC1C,mCAAmD;AACnD,qCAAwC;AACxC,mCAA6D;AAO7D;;;;;;;;;GASG;AACH,MAAa,cAAc;IAMzB,YACkB,MAAc,EACb,UAAiC,EAAE;QADpC,WAAM,GAAN,MAAM,CAAQ;QACb,YAAO,GAAP,OAAO,CAA4B;QAJ7C,SAAI,GAAG,SAAS,CAAC;IAKvB,CAAC;IAEJ;;;;OAIG;IACH,aAAa,CAAC,EAAqC;QACjD,OAAO,EAAE,CAAC,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC;IACrD,CAAC;IAED,KAAK,CACH,EAAyB,EACzB,KAAkB;QAElB,MAAM,UAAU,GAAG,IAAA,kBAAS,EAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;QAC5D,MAAM,OAAO,GAAG,IAAI,uBAAa,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,IAAI,qBAAY,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAE1D,uEAAuE;QACvE,sDAAsD;QACtD,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAEnE,6DAA6D;QAC7D,MAAM,KAAK,GAAG,IAAA,iBAAS,EAAC,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACrD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC3B,CAAC;QAED,YAAY;QACZ,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,GAAG,GAAa;gBACpB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,OAAO;gBACP,MAAM;gBACN,QAAQ,EAAE,EAAE;gBACZ,YAAY,EAAE,OAAO,CAAC,IAAI,EAAE;gBAC5B,WAAW,EAAE,EAAE;gBACf,aAAa,EAAE,KAAK,CAAC,UAAU;gBAC/B,UAAU,EAAE,EAAE,CAAC,UAAU;aAC1B,CAAC;YACF,EAAE,CAAC,QAAQ,CACT,IAAI,kBAAQ,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAA,2BAAmB,EAAC,GAAG,EAAE,KAAK,CAAC,QAAS,EAAE,GAAG,CAAC,CAAC,CACtE,CAAC;QACJ,CAAC;QAED,eAAe;QACf,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YAClB,EAAE,CAAC,UAAU,CACX,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAC1C,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,EAAoB,CACpD,CAAC;QACJ,CAAC;QAED,iBAAiB;QACjB,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;QAE3C,OAAO,EAAE,CAAC;IACZ,CAAC;IAEO,eAAe,CACrB,EAAyB,EACzB,MAAwB,EACxB,MAAoB,EACpB,SAAiB;QAEjB,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK;YAAE,OAAO,CAAC,oBAAoB;QACvD,MAAM,EAAE,GAAG,IAAA,qBAAY,EAAC,MAAM,CAAC,CAAC;QAChC,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC3B,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;YAClC,OAAO;QACT,CAAC;QACD,SAAS;QACT,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACnC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,uDAAuD;QACpE,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,SAAS,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACtD,CAAC;IAEO,SAAS,CACf,EAAyB,EACzB,IAAc;QAEd,MAAM,YAAY,GAAG,IAAA,kBAAS,EAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAC/D,QAAQ,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;YAC5B,KAAK,MAAM;gBACT,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC3C,OAAO;YACT,KAAK,KAAK;gBACR,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;gBACpD,OAAO;YACT,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC3C,MAAM,EAAE,GAAG,IAAA,qBAAY,EAAC,YAAY,CAAC,CAAC;gBACtC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBAC3C,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACZ,EAAE,CAAC,SAAS,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;gBACxD,OAAO;YACT,CAAC;QACH,CAAC;IACH,CAAC;IAEO,eAAe,CACrB,EAAyB,EACzB,UAAqC;QAErC,IAAI,UAAU,CAAC,IAAI,KAAK,KAAK;YAAE,OAAO;QACtC,IAAI,UAAU,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAChC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACnB,OAAO;QACT,CAAC;QACD,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IACzE,CAAC;CACF;AAzHD,wCAyHC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manages join aliases for a single query. Each (path, alias) pair is unique
|
|
3
|
+
* within a query builder; aliases are derived from the relation path and a
|
|
4
|
+
* monotonic counter to avoid collisions and to stay under Postgres' identifier
|
|
5
|
+
* limit (63 chars).
|
|
6
|
+
*/
|
|
7
|
+
export declare class AliasRegistry {
|
|
8
|
+
private rootAlias;
|
|
9
|
+
private byPath;
|
|
10
|
+
private counter;
|
|
11
|
+
constructor(rootAlias: string);
|
|
12
|
+
/** Returns the alias for `path` if a join was previously registered. */
|
|
13
|
+
get(path: string): string | undefined;
|
|
14
|
+
/** Returns the alias for the root entity. */
|
|
15
|
+
root(): string;
|
|
16
|
+
/**
|
|
17
|
+
* Register an alias for `path`. `path` is expected to be a dot-joined chain
|
|
18
|
+
* of relation names (e.g. "posts.comments"). The alias incorporates the path
|
|
19
|
+
* but is truncated and suffixed with a counter for uniqueness.
|
|
20
|
+
*/
|
|
21
|
+
register(path: string): string;
|
|
22
|
+
/** Iterate registered (path, alias) pairs in insertion order. */
|
|
23
|
+
entries(): IterableIterator<[string, string]>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=aliases.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aliases.d.ts","sourceRoot":"","sources":["../../../src/adapters/typeorm/aliases.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,qBAAa,aAAa;IAIZ,OAAO,CAAC,SAAS;IAH7B,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,OAAO,CAAK;gBAEA,SAAS,EAAE,MAAM;IAErC,wEAAwE;IACxE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIrC,6CAA6C;IAC7C,IAAI,IAAI,MAAM;IAId;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAY9B,iEAAiE;IACjE,OAAO,IAAI,gBAAgB,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAG9C"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AliasRegistry = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Manages join aliases for a single query. Each (path, alias) pair is unique
|
|
6
|
+
* within a query builder; aliases are derived from the relation path and a
|
|
7
|
+
* monotonic counter to avoid collisions and to stay under Postgres' identifier
|
|
8
|
+
* limit (63 chars).
|
|
9
|
+
*/
|
|
10
|
+
class AliasRegistry {
|
|
11
|
+
constructor(rootAlias) {
|
|
12
|
+
this.rootAlias = rootAlias;
|
|
13
|
+
this.byPath = new Map();
|
|
14
|
+
this.counter = 0;
|
|
15
|
+
}
|
|
16
|
+
/** Returns the alias for `path` if a join was previously registered. */
|
|
17
|
+
get(path) {
|
|
18
|
+
return this.byPath.get(path);
|
|
19
|
+
}
|
|
20
|
+
/** Returns the alias for the root entity. */
|
|
21
|
+
root() {
|
|
22
|
+
return this.rootAlias;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Register an alias for `path`. `path` is expected to be a dot-joined chain
|
|
26
|
+
* of relation names (e.g. "posts.comments"). The alias incorporates the path
|
|
27
|
+
* but is truncated and suffixed with a counter for uniqueness.
|
|
28
|
+
*/
|
|
29
|
+
register(path) {
|
|
30
|
+
const existing = this.byPath.get(path);
|
|
31
|
+
if (existing)
|
|
32
|
+
return existing;
|
|
33
|
+
const suffix = String(this.counter++);
|
|
34
|
+
const base = `${this.rootAlias}_${path.replace(/\./g, "_")}`;
|
|
35
|
+
// Stay well under Postgres' 63-char identifier limit.
|
|
36
|
+
const trimmed = base.length > 50 ? base.slice(0, 50) : base;
|
|
37
|
+
const alias = `${trimmed}_${suffix}`;
|
|
38
|
+
this.byPath.set(path, alias);
|
|
39
|
+
return alias;
|
|
40
|
+
}
|
|
41
|
+
/** Iterate registered (path, alias) pairs in insertion order. */
|
|
42
|
+
entries() {
|
|
43
|
+
return this.byPath.entries();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.AliasRegistry = AliasRegistry;
|
|
47
|
+
//# sourceMappingURL=aliases.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aliases.js","sourceRoot":"","sources":["../../../src/adapters/typeorm/aliases.ts"],"names":[],"mappings":";;;AAAA;;;;;GAKG;AACH,MAAa,aAAa;IAIxB,YAAoB,SAAiB;QAAjB,cAAS,GAAT,SAAS,CAAQ;QAH7B,WAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;QACnC,YAAO,GAAG,CAAC,CAAC;IAEoB,CAAC;IAEzC,wEAAwE;IACxE,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED,6CAA6C;IAC7C,IAAI;QACF,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED;;;;OAIG;IACH,QAAQ,CAAC,IAAY;QACnB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAC9B,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QACtC,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;QAC7D,sDAAsD;QACtD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5D,MAAM,KAAK,GAAG,GAAG,OAAO,IAAI,MAAM,EAAE,CAAC;QACrC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC7B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,iEAAiE;IACjE,OAAO;QACL,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;IAC/B,CAAC;CACF;AArCD,sCAqCC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { DataSource, ObjectLiteral, SelectQueryBuilder } from "typeorm";
|
|
2
|
+
import { GenQueryEngine } from "../../engine";
|
|
3
|
+
import { type TypeORMAdapterOptions } from "./adapter";
|
|
4
|
+
import { type SchemaFromTypeORMOptions } from "./schema-from-typeorm";
|
|
5
|
+
export interface CreateTypeORMEngineOptions {
|
|
6
|
+
/** Options forwarded to `schemaFromTypeORM` (entity filter, overrides, ...). */
|
|
7
|
+
schema?: SchemaFromTypeORMOptions;
|
|
8
|
+
/** Options forwarded to the `TypeORMAdapter` constructor (paramPrefix, ...). */
|
|
9
|
+
adapter?: TypeORMAdapterOptions;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* One-line setup for the common case: read the schema from TypeORM, build the
|
|
13
|
+
* adapter and the engine.
|
|
14
|
+
*
|
|
15
|
+
* await dataSource.initialize();
|
|
16
|
+
* const engine = createTypeORMEngine(dataSource);
|
|
17
|
+
*
|
|
18
|
+
* For per-entity type overrides or custom adapter parameters:
|
|
19
|
+
*
|
|
20
|
+
* const engine = createTypeORMEngine(dataSource, {
|
|
21
|
+
* schema: { entities: [User, Post], overrides: { User: { meta: "string" } } },
|
|
22
|
+
* adapter: { paramPrefix: "q" },
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* The DataSource must be initialized before calling this — `entityMetadatas`
|
|
26
|
+
* is empty otherwise.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createTypeORMEngine(dataSource: DataSource, options?: CreateTypeORMEngineOptions): GenQueryEngine<SelectQueryBuilder<ObjectLiteral>, SelectQueryBuilder<ObjectLiteral>>;
|
|
29
|
+
//# sourceMappingURL=create.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/adapters/typeorm/create.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAkB,KAAK,qBAAqB,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EAEL,KAAK,wBAAwB,EAC9B,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,0BAA0B;IACzC,gFAAgF;IAChF,MAAM,CAAC,EAAE,wBAAwB,CAAC;IAClC,gFAAgF;IAChF,OAAO,CAAC,EAAE,qBAAqB,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,0BAA+B,GACvC,cAAc,CACf,kBAAkB,CAAC,aAAa,CAAC,EACjC,kBAAkB,CAAC,aAAa,CAAC,CAClC,CAIA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createTypeORMEngine = createTypeORMEngine;
|
|
4
|
+
const engine_1 = require("../../engine");
|
|
5
|
+
const adapter_1 = require("./adapter");
|
|
6
|
+
const schema_from_typeorm_1 = require("./schema-from-typeorm");
|
|
7
|
+
/**
|
|
8
|
+
* One-line setup for the common case: read the schema from TypeORM, build the
|
|
9
|
+
* adapter and the engine.
|
|
10
|
+
*
|
|
11
|
+
* await dataSource.initialize();
|
|
12
|
+
* const engine = createTypeORMEngine(dataSource);
|
|
13
|
+
*
|
|
14
|
+
* For per-entity type overrides or custom adapter parameters:
|
|
15
|
+
*
|
|
16
|
+
* const engine = createTypeORMEngine(dataSource, {
|
|
17
|
+
* schema: { entities: [User, Post], overrides: { User: { meta: "string" } } },
|
|
18
|
+
* adapter: { paramPrefix: "q" },
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* The DataSource must be initialized before calling this — `entityMetadatas`
|
|
22
|
+
* is empty otherwise.
|
|
23
|
+
*/
|
|
24
|
+
function createTypeORMEngine(dataSource, options = {}) {
|
|
25
|
+
const schema = (0, schema_from_typeorm_1.schemaFromTypeORM)(dataSource, options.schema);
|
|
26
|
+
const adapter = new adapter_1.TypeORMAdapter(schema, options.adapter);
|
|
27
|
+
return new engine_1.GenQueryEngine({ adapter });
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/adapters/typeorm/create.ts"],"names":[],"mappings":";;AAgCA,kDAUC;AAzCD,yCAA8C;AAC9C,uCAAuE;AACvE,+DAG+B;AAS/B;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,mBAAmB,CACjC,UAAsB,EACtB,UAAsC,EAAE;IAKxC,MAAM,MAAM,GAAG,IAAA,uCAAiB,EAAC,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7D,MAAM,OAAO,GAAG,IAAI,wBAAc,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,OAAO,IAAI,uBAAc,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Escape user input that will be embedded in a LIKE/ILIKE pattern. */
|
|
2
|
+
export declare function escapeLike(value: string): string;
|
|
3
|
+
/** Split a search string by whitespace, dropping empty parts. */
|
|
4
|
+
export declare function splitWords(value: string): string[];
|
|
5
|
+
//# sourceMappingURL=escape.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escape.d.ts","sourceRoot":"","sources":["../../../src/adapters/typeorm/escape.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,iEAAiE;AACjE,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAElD"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.escapeLike = escapeLike;
|
|
4
|
+
exports.splitWords = splitWords;
|
|
5
|
+
/** Escape user input that will be embedded in a LIKE/ILIKE pattern. */
|
|
6
|
+
function escapeLike(value) {
|
|
7
|
+
return value.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
8
|
+
}
|
|
9
|
+
/** Split a search string by whitespace, dropping empty parts. */
|
|
10
|
+
function splitWords(value) {
|
|
11
|
+
return value.split(/\s+/).filter((s) => s.length > 0);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=escape.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"escape.js","sourceRoot":"","sources":["../../../src/adapters/typeorm/escape.ts"],"names":[],"mappings":";;AACA,gCAEC;AAGD,gCAEC;AARD,uEAAuE;AACvE,SAAgB,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAChF,CAAC;AAED,iEAAiE;AACjE,SAAgB,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { TypeORMAdapter, type TypeORMAdapterOptions } from "./adapter";
|
|
2
|
+
export { schemaFromTypeORM, type SchemaFromTypeORMOptions, } from "./schema-from-typeorm";
|
|
3
|
+
export { createTypeORMEngine, type CreateTypeORMEngineOptions, } from "./create";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/typeorm/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EACL,iBAAiB,EACjB,KAAK,wBAAwB,GAC9B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,mBAAmB,EACnB,KAAK,0BAA0B,GAChC,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createTypeORMEngine = exports.schemaFromTypeORM = exports.TypeORMAdapter = void 0;
|
|
4
|
+
var adapter_1 = require("./adapter");
|
|
5
|
+
Object.defineProperty(exports, "TypeORMAdapter", { enumerable: true, get: function () { return adapter_1.TypeORMAdapter; } });
|
|
6
|
+
var schema_from_typeorm_1 = require("./schema-from-typeorm");
|
|
7
|
+
Object.defineProperty(exports, "schemaFromTypeORM", { enumerable: true, get: function () { return schema_from_typeorm_1.schemaFromTypeORM; } });
|
|
8
|
+
var create_1 = require("./create");
|
|
9
|
+
Object.defineProperty(exports, "createTypeORMEngine", { enumerable: true, get: function () { return create_1.createTypeORMEngine; } });
|
|
10
|
+
//# sourceMappingURL=index.js.map
|