@uql/core 3.1.0 → 3.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +134 -176
- package/README.md +413 -0
- package/package.json +31 -26
- package/dist/package.json +0 -131
- package/src/@types/index.d.ts +0 -1
- package/src/@types/jest.d.ts +0 -6
- package/src/browser/http/bus.spec.ts +0 -22
- package/src/browser/http/bus.ts +0 -17
- package/src/browser/http/http.spec.ts +0 -70
- package/src/browser/http/http.ts +0 -55
- package/src/browser/http/index.ts +0 -2
- package/src/browser/index.ts +0 -4
- package/src/browser/options.spec.ts +0 -37
- package/src/browser/options.ts +0 -18
- package/src/browser/querier/genericClientRepository.spec.ts +0 -105
- package/src/browser/querier/genericClientRepository.ts +0 -49
- package/src/browser/querier/httpQuerier.ts +0 -82
- package/src/browser/querier/index.ts +0 -3
- package/src/browser/querier/querier.util.spec.ts +0 -35
- package/src/browser/querier/querier.util.ts +0 -18
- package/src/browser/type/clientQuerier.ts +0 -45
- package/src/browser/type/clientQuerierPool.ts +0 -5
- package/src/browser/type/clientRepository.ts +0 -22
- package/src/browser/type/index.ts +0 -4
- package/src/browser/type/request.ts +0 -25
- package/src/dialect/abstractDialect.ts +0 -28
- package/src/dialect/abstractSqlDialect-spec.ts +0 -1309
- package/src/dialect/abstractSqlDialect.ts +0 -805
- package/src/dialect/index.ts +0 -3
- package/src/dialect/namingStrategy.spec.ts +0 -52
- package/src/dialect/queryContext.ts +0 -69
- package/src/entity/decorator/definition.spec.ts +0 -736
- package/src/entity/decorator/definition.ts +0 -265
- package/src/entity/decorator/entity.ts +0 -8
- package/src/entity/decorator/field.ts +0 -9
- package/src/entity/decorator/id.ts +0 -9
- package/src/entity/decorator/index.ts +0 -5
- package/src/entity/decorator/relation.spec.ts +0 -41
- package/src/entity/decorator/relation.ts +0 -34
- package/src/entity/index.ts +0 -1
- package/src/express/@types/express.d.ts +0 -8
- package/src/express/@types/index.d.ts +0 -1
- package/src/express/index.ts +0 -2
- package/src/express/querierMiddleware.ts +0 -217
- package/src/express/query.util.spec.ts +0 -40
- package/src/express/query.util.ts +0 -21
- package/src/index.ts +0 -9
- package/src/maria/index.ts +0 -3
- package/src/maria/mariaDialect.spec.ts +0 -207
- package/src/maria/mariaDialect.ts +0 -42
- package/src/maria/mariaQuerierPool.test.ts +0 -23
- package/src/maria/mariadbQuerier.test.ts +0 -23
- package/src/maria/mariadbQuerier.ts +0 -45
- package/src/maria/mariadbQuerierPool.ts +0 -21
- package/src/migrate/cli.ts +0 -301
- package/src/migrate/generator/index.ts +0 -4
- package/src/migrate/generator/mongoSchemaGenerator.spec.ts +0 -112
- package/src/migrate/generator/mongoSchemaGenerator.ts +0 -115
- package/src/migrate/generator/mysqlSchemaGenerator.spec.ts +0 -34
- package/src/migrate/generator/mysqlSchemaGenerator.ts +0 -92
- package/src/migrate/generator/postgresSchemaGenerator.spec.ts +0 -44
- package/src/migrate/generator/postgresSchemaGenerator.ts +0 -127
- package/src/migrate/generator/sqliteSchemaGenerator.spec.ts +0 -33
- package/src/migrate/generator/sqliteSchemaGenerator.ts +0 -81
- package/src/migrate/index.ts +0 -41
- package/src/migrate/introspection/index.ts +0 -4
- package/src/migrate/introspection/mongoIntrospector.spec.ts +0 -75
- package/src/migrate/introspection/mongoIntrospector.ts +0 -47
- package/src/migrate/introspection/mysqlIntrospector.spec.ts +0 -113
- package/src/migrate/introspection/mysqlIntrospector.ts +0 -278
- package/src/migrate/introspection/postgresIntrospector.spec.ts +0 -112
- package/src/migrate/introspection/postgresIntrospector.ts +0 -329
- package/src/migrate/introspection/sqliteIntrospector.spec.ts +0 -112
- package/src/migrate/introspection/sqliteIntrospector.ts +0 -296
- package/src/migrate/migrator-mongo.test.ts +0 -54
- package/src/migrate/migrator.spec.ts +0 -255
- package/src/migrate/migrator.test.ts +0 -94
- package/src/migrate/migrator.ts +0 -719
- package/src/migrate/namingStrategy.spec.ts +0 -22
- package/src/migrate/schemaGenerator-advanced.spec.ts +0 -138
- package/src/migrate/schemaGenerator.spec.ts +0 -190
- package/src/migrate/schemaGenerator.ts +0 -478
- package/src/migrate/storage/databaseStorage.spec.ts +0 -69
- package/src/migrate/storage/databaseStorage.ts +0 -100
- package/src/migrate/storage/index.ts +0 -2
- package/src/migrate/storage/jsonStorage.ts +0 -58
- package/src/migrate/type.ts +0 -1
- package/src/mongo/index.ts +0 -3
- package/src/mongo/mongoDialect.spec.ts +0 -251
- package/src/mongo/mongoDialect.ts +0 -238
- package/src/mongo/mongodbQuerier.test.ts +0 -45
- package/src/mongo/mongodbQuerier.ts +0 -256
- package/src/mongo/mongodbQuerierPool.test.ts +0 -25
- package/src/mongo/mongodbQuerierPool.ts +0 -24
- package/src/mysql/index.ts +0 -3
- package/src/mysql/mysql2Querier.test.ts +0 -20
- package/src/mysql/mysql2Querier.ts +0 -49
- package/src/mysql/mysql2QuerierPool.test.ts +0 -20
- package/src/mysql/mysql2QuerierPool.ts +0 -21
- package/src/mysql/mysqlDialect.spec.ts +0 -20
- package/src/mysql/mysqlDialect.ts +0 -16
- package/src/namingStrategy/defaultNamingStrategy.ts +0 -18
- package/src/namingStrategy/index.spec.ts +0 -36
- package/src/namingStrategy/index.ts +0 -2
- package/src/namingStrategy/snakeCaseNamingStrategy.ts +0 -15
- package/src/options.spec.ts +0 -41
- package/src/options.ts +0 -18
- package/src/postgres/index.ts +0 -3
- package/src/postgres/manual-types.d.ts +0 -4
- package/src/postgres/pgQuerier.test.ts +0 -25
- package/src/postgres/pgQuerier.ts +0 -45
- package/src/postgres/pgQuerierPool.test.ts +0 -28
- package/src/postgres/pgQuerierPool.ts +0 -21
- package/src/postgres/postgresDialect.spec.ts +0 -428
- package/src/postgres/postgresDialect.ts +0 -144
- package/src/querier/abstractQuerier-test.ts +0 -584
- package/src/querier/abstractQuerier.ts +0 -353
- package/src/querier/abstractQuerierPool-test.ts +0 -20
- package/src/querier/abstractQuerierPool.ts +0 -18
- package/src/querier/abstractSqlQuerier-spec.ts +0 -979
- package/src/querier/abstractSqlQuerier-test.ts +0 -21
- package/src/querier/abstractSqlQuerier.ts +0 -138
- package/src/querier/decorator/index.ts +0 -3
- package/src/querier/decorator/injectQuerier.spec.ts +0 -74
- package/src/querier/decorator/injectQuerier.ts +0 -45
- package/src/querier/decorator/serialized.spec.ts +0 -98
- package/src/querier/decorator/serialized.ts +0 -13
- package/src/querier/decorator/transactional.spec.ts +0 -240
- package/src/querier/decorator/transactional.ts +0 -56
- package/src/querier/index.ts +0 -4
- package/src/repository/genericRepository.spec.ts +0 -111
- package/src/repository/genericRepository.ts +0 -74
- package/src/repository/index.ts +0 -1
- package/src/sqlite/index.ts +0 -3
- package/src/sqlite/manual-types.d.ts +0 -4
- package/src/sqlite/sqliteDialect.spec.ts +0 -155
- package/src/sqlite/sqliteDialect.ts +0 -76
- package/src/sqlite/sqliteQuerier.spec.ts +0 -36
- package/src/sqlite/sqliteQuerier.test.ts +0 -21
- package/src/sqlite/sqliteQuerier.ts +0 -37
- package/src/sqlite/sqliteQuerierPool.test.ts +0 -12
- package/src/sqlite/sqliteQuerierPool.ts +0 -38
- package/src/test/entityMock.ts +0 -375
- package/src/test/index.ts +0 -3
- package/src/test/it.util.ts +0 -69
- package/src/test/spec.util.ts +0 -57
- package/src/type/entity.ts +0 -218
- package/src/type/index.ts +0 -9
- package/src/type/migration.ts +0 -241
- package/src/type/namingStrategy.ts +0 -17
- package/src/type/querier.ts +0 -143
- package/src/type/querierPool.ts +0 -26
- package/src/type/query.ts +0 -506
- package/src/type/repository.ts +0 -142
- package/src/type/universalQuerier.ts +0 -133
- package/src/type/utility.ts +0 -21
- package/src/util/dialect.util-extra.spec.ts +0 -96
- package/src/util/dialect.util.spec.ts +0 -23
- package/src/util/dialect.util.ts +0 -134
- package/src/util/index.ts +0 -5
- package/src/util/object.util.spec.ts +0 -29
- package/src/util/object.util.ts +0 -27
- package/src/util/raw.ts +0 -11
- package/src/util/sql.util-extra.spec.ts +0 -17
- package/src/util/sql.util.spec.ts +0 -208
- package/src/util/sql.util.ts +0 -104
- package/src/util/string.util.spec.ts +0 -46
- package/src/util/string.util.ts +0 -35
- package/tsconfig.build.json +0 -5
- package/tsconfig.json +0 -8
|
@@ -1,805 +0,0 @@
|
|
|
1
|
-
import { getMeta } from '../entity/index.js';
|
|
2
|
-
import {
|
|
3
|
-
type EntityMeta,
|
|
4
|
-
type FieldKey,
|
|
5
|
-
type FieldOptions,
|
|
6
|
-
type NamingStrategy,
|
|
7
|
-
type Query,
|
|
8
|
-
type QueryComparisonOptions,
|
|
9
|
-
type QueryConflictPaths,
|
|
10
|
-
type QueryContext,
|
|
11
|
-
type QueryDialect,
|
|
12
|
-
type QueryOptions,
|
|
13
|
-
type QueryPager,
|
|
14
|
-
QueryRaw,
|
|
15
|
-
type QueryRawFnOptions,
|
|
16
|
-
type QuerySearch,
|
|
17
|
-
type QuerySelect,
|
|
18
|
-
type QuerySelectArray,
|
|
19
|
-
type QuerySelectOptions,
|
|
20
|
-
type QuerySort,
|
|
21
|
-
type QuerySortDirection,
|
|
22
|
-
type QueryTextSearchOptions,
|
|
23
|
-
type QueryWhere,
|
|
24
|
-
type QueryWhereArray,
|
|
25
|
-
type QueryWhereFieldOperatorMap,
|
|
26
|
-
type QueryWhereMap,
|
|
27
|
-
type QueryWhereOptions,
|
|
28
|
-
type SqlQueryDialect,
|
|
29
|
-
type Type,
|
|
30
|
-
} from '../type/index.js';
|
|
31
|
-
|
|
32
|
-
import {
|
|
33
|
-
buildSortMap,
|
|
34
|
-
buldQueryWhereAsMap,
|
|
35
|
-
type CallbackKey,
|
|
36
|
-
escapeSqlId,
|
|
37
|
-
fillOnFields,
|
|
38
|
-
filterFieldKeys,
|
|
39
|
-
filterRelationKeys,
|
|
40
|
-
flatObject,
|
|
41
|
-
getFieldCallbackValue,
|
|
42
|
-
getFieldKeys,
|
|
43
|
-
getKeys,
|
|
44
|
-
hasKeys,
|
|
45
|
-
isSelectingRelations,
|
|
46
|
-
raw,
|
|
47
|
-
} from '../util/index.js';
|
|
48
|
-
|
|
49
|
-
import { AbstractDialect } from './abstractDialect.js';
|
|
50
|
-
import { SqlQueryContext } from './queryContext.js';
|
|
51
|
-
|
|
52
|
-
export abstract class AbstractSqlDialect extends AbstractDialect implements QueryDialect, SqlQueryDialect {
|
|
53
|
-
constructor(
|
|
54
|
-
namingStrategy?: NamingStrategy,
|
|
55
|
-
readonly escapeIdChar: '`' | '"' = '`',
|
|
56
|
-
readonly beginTransactionCommand: string = 'START TRANSACTION',
|
|
57
|
-
readonly commitTransactionCommand: string = 'COMMIT',
|
|
58
|
-
readonly rollbackTransactionCommand: string = 'ROLLBACK',
|
|
59
|
-
) {
|
|
60
|
-
super(namingStrategy);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
createContext(): QueryContext {
|
|
64
|
-
return new SqlQueryContext(this);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
addValue(values: unknown[], value: unknown): string {
|
|
68
|
-
values.push(value ?? null);
|
|
69
|
-
return this.placeholder(values.length);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
placeholder(_index: number): string {
|
|
73
|
-
return '?';
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
returningId<E>(entity: Type<E>): string {
|
|
77
|
-
const meta = getMeta(entity);
|
|
78
|
-
const idName = this.resolveColumnName(meta.id, meta.fields[meta.id]);
|
|
79
|
-
return `RETURNING ${this.escapeId(idName)} ${this.escapeId('id')}`;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
search<E>(ctx: QueryContext, entity: Type<E>, q: Query<E> = {}, opts: QueryOptions = {}): void {
|
|
83
|
-
const meta = getMeta(entity);
|
|
84
|
-
const tableName = this.resolveTableName(entity, meta);
|
|
85
|
-
const prefix = (opts.prefix ?? (opts.autoPrefix || isSelectingRelations(meta, q.$select))) ? tableName : undefined;
|
|
86
|
-
opts = { ...opts, prefix };
|
|
87
|
-
this.where<E>(ctx, entity, q.$where, opts);
|
|
88
|
-
this.sort<E>(ctx, entity, q.$sort, opts);
|
|
89
|
-
this.pager(ctx, q);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
selectFields<E>(ctx: QueryContext, entity: Type<E>, select: QuerySelect<E>, opts: QuerySelectOptions = {}): void {
|
|
93
|
-
const meta = getMeta(entity);
|
|
94
|
-
const prefix = opts.prefix ? opts.prefix + '.' : '';
|
|
95
|
-
const escapedPrefix = this.escapeId(opts.prefix, true, true);
|
|
96
|
-
|
|
97
|
-
let selectArr: QuerySelectArray<E>;
|
|
98
|
-
|
|
99
|
-
if (select) {
|
|
100
|
-
if (Array.isArray(select)) {
|
|
101
|
-
selectArr = select;
|
|
102
|
-
} else {
|
|
103
|
-
const selectPositive = getKeys(select).filter((it) => select[it]) as FieldKey<E>[];
|
|
104
|
-
selectArr = selectPositive.length
|
|
105
|
-
? selectPositive
|
|
106
|
-
: (getFieldKeys(meta.fields).filter((it) => !(it in select)) as FieldKey<E>[]);
|
|
107
|
-
}
|
|
108
|
-
selectArr = selectArr.filter((it) => it instanceof QueryRaw || it in meta.fields);
|
|
109
|
-
if (opts.prefix && !selectArr.includes(meta.id)) {
|
|
110
|
-
selectArr = [meta.id, ...selectArr];
|
|
111
|
-
}
|
|
112
|
-
} else {
|
|
113
|
-
selectArr = getFieldKeys(meta.fields) as FieldKey<E>[];
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (!selectArr.length) {
|
|
117
|
-
ctx.append(escapedPrefix + '*');
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
selectArr.forEach((key, index) => {
|
|
122
|
-
if (index > 0) ctx.append(', ');
|
|
123
|
-
if (key instanceof QueryRaw) {
|
|
124
|
-
this.getRawValue(ctx, {
|
|
125
|
-
value: key,
|
|
126
|
-
prefix: opts.prefix,
|
|
127
|
-
escapedPrefix,
|
|
128
|
-
autoPrefixAlias: opts.autoPrefixAlias,
|
|
129
|
-
});
|
|
130
|
-
} else {
|
|
131
|
-
const field = meta.fields[key as FieldKey<E>];
|
|
132
|
-
const columnName = this.resolveColumnName(key, field);
|
|
133
|
-
if (field.virtual) {
|
|
134
|
-
this.getRawValue(ctx, {
|
|
135
|
-
value: raw(field.virtual.value, key as string),
|
|
136
|
-
prefix: opts.prefix,
|
|
137
|
-
escapedPrefix,
|
|
138
|
-
autoPrefixAlias: opts.autoPrefixAlias,
|
|
139
|
-
});
|
|
140
|
-
} else {
|
|
141
|
-
ctx.append(escapedPrefix + this.escapeId(columnName));
|
|
142
|
-
}
|
|
143
|
-
if (!field.virtual && (columnName !== key || opts.autoPrefixAlias)) {
|
|
144
|
-
const aliasStr = (prefix + key) as string;
|
|
145
|
-
// Replace dots with underscores for alias to avoid syntax errors
|
|
146
|
-
const safeAlias = aliasStr.replace(/\./g, '_');
|
|
147
|
-
ctx.append(' ' + this.escapeId(safeAlias, true));
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
select<E>(ctx: QueryContext, entity: Type<E>, select: QuerySelect<E>, opts: QueryOptions = {}): void {
|
|
154
|
-
const meta = getMeta(entity);
|
|
155
|
-
const tableName = this.resolveTableName(entity, meta);
|
|
156
|
-
const prefix = (opts.prefix ?? (opts.autoPrefix || isSelectingRelations(meta, select))) ? tableName : undefined;
|
|
157
|
-
|
|
158
|
-
ctx.append('SELECT ');
|
|
159
|
-
this.selectFields(ctx, entity, select, { prefix });
|
|
160
|
-
// Add related fields BEFORE FROM clause
|
|
161
|
-
this.selectRelationFields(ctx, entity, select, { prefix });
|
|
162
|
-
ctx.append(` FROM ${this.escapeId(tableName)}`);
|
|
163
|
-
// Add JOINs AFTER FROM clause
|
|
164
|
-
this.selectRelationJoins(ctx, entity, select, { prefix });
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
protected selectRelationFields<E>(
|
|
168
|
-
ctx: QueryContext,
|
|
169
|
-
entity: Type<E>,
|
|
170
|
-
select: QuerySelect<E>,
|
|
171
|
-
opts: { prefix?: string } = {},
|
|
172
|
-
): void {
|
|
173
|
-
if (Array.isArray(select)) {
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const meta = getMeta(entity);
|
|
178
|
-
const tableName = this.resolveTableName(entity, meta);
|
|
179
|
-
const relKeys = filterRelationKeys(meta, select);
|
|
180
|
-
const isSelectArray = Array.isArray(select);
|
|
181
|
-
const prefix = opts.prefix;
|
|
182
|
-
|
|
183
|
-
for (const relKey of relKeys) {
|
|
184
|
-
const relOpts = meta.relations[relKey];
|
|
185
|
-
|
|
186
|
-
if (relOpts.cardinality === '1m' || relOpts.cardinality === 'mm') {
|
|
187
|
-
continue;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const isFirstLevel = prefix === tableName;
|
|
191
|
-
const joinRelAlias = isFirstLevel ? relKey : prefix ? prefix + '.' + relKey : relKey;
|
|
192
|
-
const relEntity = relOpts.entity();
|
|
193
|
-
const relSelect = select[relKey as string];
|
|
194
|
-
const relQuery = isSelectArray ? {} : Array.isArray(relSelect) ? { $select: relSelect } : relSelect;
|
|
195
|
-
|
|
196
|
-
ctx.append(', ');
|
|
197
|
-
this.selectFields(ctx, relEntity, relQuery.$select, {
|
|
198
|
-
prefix: joinRelAlias,
|
|
199
|
-
autoPrefixAlias: true,
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
// Recursively add nested relation fields
|
|
203
|
-
this.selectRelationFields(ctx, relEntity, relQuery.$select, {
|
|
204
|
-
prefix: joinRelAlias,
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
protected selectRelationJoins<E>(
|
|
210
|
-
ctx: QueryContext,
|
|
211
|
-
entity: Type<E>,
|
|
212
|
-
select: QuerySelect<E>,
|
|
213
|
-
opts: { prefix?: string } = {},
|
|
214
|
-
): void {
|
|
215
|
-
if (Array.isArray(select)) {
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const meta = getMeta(entity);
|
|
220
|
-
const tableName = this.resolveTableName(entity, meta);
|
|
221
|
-
const relKeys = filterRelationKeys(meta, select);
|
|
222
|
-
const isSelectArray = Array.isArray(select);
|
|
223
|
-
const prefix = opts.prefix;
|
|
224
|
-
|
|
225
|
-
for (const relKey of relKeys) {
|
|
226
|
-
const relOpts = meta.relations[relKey];
|
|
227
|
-
|
|
228
|
-
if (relOpts.cardinality === '1m' || relOpts.cardinality === 'mm') {
|
|
229
|
-
continue;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const isFirstLevel = prefix === tableName;
|
|
233
|
-
const joinRelAlias = isFirstLevel ? (relKey as string) : prefix ? prefix + '.' + relKey : (relKey as string);
|
|
234
|
-
const relEntity = relOpts.entity();
|
|
235
|
-
const relSelect = select[relKey as string];
|
|
236
|
-
const relQuery = isSelectArray ? {} : Array.isArray(relSelect) ? { $select: relSelect } : relSelect;
|
|
237
|
-
|
|
238
|
-
const relMeta = getMeta(relEntity);
|
|
239
|
-
const relTableName = this.resolveTableName(relEntity, relMeta);
|
|
240
|
-
const relEntityName = this.escapeId(relTableName);
|
|
241
|
-
const relPath = prefix ? this.escapeId(prefix, true) : this.escapeId(tableName);
|
|
242
|
-
const joinType = relQuery.$required ? 'INNER' : 'LEFT';
|
|
243
|
-
const joinAlias = this.escapeId(joinRelAlias, true);
|
|
244
|
-
|
|
245
|
-
ctx.append(` ${joinType} JOIN ${relEntityName} ${joinAlias} ON `);
|
|
246
|
-
ctx.append(
|
|
247
|
-
relOpts.references
|
|
248
|
-
.map((it) => {
|
|
249
|
-
const foreignColumnName = this.resolveColumnName(it.foreign, relMeta.fields[it.foreign]);
|
|
250
|
-
const localColumnName = this.resolveColumnName(it.local, meta.fields[it.local]);
|
|
251
|
-
return `${joinAlias}.${this.escapeId(foreignColumnName)} = ${relPath}.${this.escapeId(localColumnName)}`;
|
|
252
|
-
})
|
|
253
|
-
.join(' AND '),
|
|
254
|
-
);
|
|
255
|
-
|
|
256
|
-
if (relQuery.$where) {
|
|
257
|
-
ctx.append(' AND ');
|
|
258
|
-
this.where(ctx, relEntity, relQuery.$where, { prefix: joinRelAlias, clause: false });
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// Recursively add nested relation JOINs
|
|
262
|
-
this.selectRelationJoins(ctx, relEntity, relQuery.$select, {
|
|
263
|
-
prefix: joinRelAlias,
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
where<E>(ctx: QueryContext, entity: Type<E>, where: QueryWhere<E> = {}, opts: QueryWhereOptions = {}): void {
|
|
269
|
-
const meta = getMeta(entity);
|
|
270
|
-
const { usePrecedence, clause = 'WHERE', softDelete } = opts;
|
|
271
|
-
|
|
272
|
-
where = buldQueryWhereAsMap(meta, where);
|
|
273
|
-
|
|
274
|
-
if (meta.softDelete && (softDelete || softDelete === undefined) && !where[meta.softDelete as string]) {
|
|
275
|
-
where[meta.softDelete as string] = null;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
const entries = Object.entries(where);
|
|
279
|
-
|
|
280
|
-
if (!entries.length) {
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if (clause) {
|
|
285
|
-
ctx.append(` ${clause} `);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
if (usePrecedence) {
|
|
289
|
-
ctx.append('(');
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
entries.forEach(([key, val], index) => {
|
|
293
|
-
if (index > 0) {
|
|
294
|
-
ctx.append(' AND ');
|
|
295
|
-
}
|
|
296
|
-
this.compare(ctx, entity, key as keyof QueryWhereMap<E>, val as any, {
|
|
297
|
-
...opts,
|
|
298
|
-
usePrecedence: entries.length > 1,
|
|
299
|
-
});
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
if (usePrecedence) {
|
|
303
|
-
ctx.append(')');
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
compare<E, K extends keyof QueryWhereMap<E>>(
|
|
308
|
-
ctx: QueryContext,
|
|
309
|
-
entity: Type<E>,
|
|
310
|
-
key: K,
|
|
311
|
-
val: QueryWhereMap<E>[K],
|
|
312
|
-
opts: QueryComparisonOptions = {},
|
|
313
|
-
): void {
|
|
314
|
-
const meta = getMeta(entity);
|
|
315
|
-
|
|
316
|
-
if (val instanceof QueryRaw) {
|
|
317
|
-
if (key === '$exists' || key === '$nexists') {
|
|
318
|
-
ctx.append(key === '$exists' ? 'EXISTS (' : 'NOT EXISTS (');
|
|
319
|
-
const tableName = this.resolveTableName(entity, meta);
|
|
320
|
-
this.getRawValue(ctx, {
|
|
321
|
-
value: val,
|
|
322
|
-
prefix: tableName,
|
|
323
|
-
escapedPrefix: this.escapeId(tableName, false, true),
|
|
324
|
-
});
|
|
325
|
-
ctx.append(')');
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
this.getComparisonKey(ctx, entity, key as FieldKey<E>, opts);
|
|
329
|
-
ctx.append(' = ');
|
|
330
|
-
this.getRawValue(ctx, { value: val });
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
if (key === '$text') {
|
|
335
|
-
const search = val as QueryTextSearchOptions<E>;
|
|
336
|
-
const fields = search.$fields.map((fKey) => {
|
|
337
|
-
const field = meta.fields[fKey];
|
|
338
|
-
const columnName = this.resolveColumnName(fKey, field);
|
|
339
|
-
return this.escapeId(columnName);
|
|
340
|
-
});
|
|
341
|
-
ctx.append(`MATCH(${fields.join(', ')}) AGAINST(`);
|
|
342
|
-
ctx.addValue(search.$value);
|
|
343
|
-
ctx.append(')');
|
|
344
|
-
return;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
if (key === '$and' || key === '$or' || key === '$not' || key === '$nor') {
|
|
348
|
-
const negateOperatorMap = {
|
|
349
|
-
$not: '$and',
|
|
350
|
-
$nor: '$or',
|
|
351
|
-
} as const;
|
|
352
|
-
|
|
353
|
-
const op: '$and' | '$or' = negateOperatorMap[key as string] ?? key;
|
|
354
|
-
const negate = key in negateOperatorMap ? 'NOT' : '';
|
|
355
|
-
|
|
356
|
-
const valArr = val as QueryWhereArray<E>;
|
|
357
|
-
const hasManyItems = valArr.length > 1;
|
|
358
|
-
|
|
359
|
-
if ((opts.usePrecedence || negate) && hasManyItems) {
|
|
360
|
-
ctx.append((negate ? negate + ' ' : '') + '(');
|
|
361
|
-
} else if (negate) {
|
|
362
|
-
ctx.append(negate + ' ');
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
valArr.forEach((whereEntry, index) => {
|
|
366
|
-
if (index > 0) {
|
|
367
|
-
ctx.append(op === '$or' ? ' OR ' : ' AND ');
|
|
368
|
-
}
|
|
369
|
-
if (whereEntry instanceof QueryRaw) {
|
|
370
|
-
this.getRawValue(ctx, {
|
|
371
|
-
value: whereEntry,
|
|
372
|
-
prefix: opts.prefix,
|
|
373
|
-
escapedPrefix: this.escapeId(opts.prefix, true, true),
|
|
374
|
-
});
|
|
375
|
-
} else {
|
|
376
|
-
this.where(ctx, entity, whereEntry, {
|
|
377
|
-
prefix: opts.prefix,
|
|
378
|
-
usePrecedence: hasManyItems && !Array.isArray(whereEntry) && getKeys(whereEntry).length > 1,
|
|
379
|
-
clause: false,
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
if ((opts.usePrecedence || negate) && hasManyItems) {
|
|
385
|
-
ctx.append(')');
|
|
386
|
-
}
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
const value = Array.isArray(val) ? { $in: val } : typeof val === 'object' && val !== null ? val : { $eq: val };
|
|
391
|
-
const operators = getKeys(value) as (keyof QueryWhereFieldOperatorMap<E>)[];
|
|
392
|
-
|
|
393
|
-
if (operators.length > 1) {
|
|
394
|
-
ctx.append('(');
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
operators.forEach((op, index) => {
|
|
398
|
-
if (index > 0) {
|
|
399
|
-
ctx.append(' AND ');
|
|
400
|
-
}
|
|
401
|
-
this.compareFieldOperator(ctx, entity, key as FieldKey<E>, op, value[op], opts);
|
|
402
|
-
});
|
|
403
|
-
|
|
404
|
-
if (operators.length > 1) {
|
|
405
|
-
ctx.append(')');
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
compareFieldOperator<E, K extends keyof QueryWhereFieldOperatorMap<E>>(
|
|
410
|
-
ctx: QueryContext,
|
|
411
|
-
entity: Type<E>,
|
|
412
|
-
key: FieldKey<E>,
|
|
413
|
-
op: K,
|
|
414
|
-
val: QueryWhereFieldOperatorMap<E>[K],
|
|
415
|
-
opts: QueryOptions = {},
|
|
416
|
-
): void {
|
|
417
|
-
switch (op) {
|
|
418
|
-
case '$eq':
|
|
419
|
-
this.getComparisonKey(ctx, entity, key, opts);
|
|
420
|
-
if (val === null) {
|
|
421
|
-
ctx.append(' IS NULL');
|
|
422
|
-
} else {
|
|
423
|
-
ctx.append(' = ');
|
|
424
|
-
ctx.addValue(val);
|
|
425
|
-
}
|
|
426
|
-
break;
|
|
427
|
-
case '$ne':
|
|
428
|
-
this.getComparisonKey(ctx, entity, key, opts);
|
|
429
|
-
if (val === null) {
|
|
430
|
-
ctx.append(' IS NOT NULL');
|
|
431
|
-
} else {
|
|
432
|
-
ctx.append(' <> ');
|
|
433
|
-
ctx.addValue(val);
|
|
434
|
-
}
|
|
435
|
-
break;
|
|
436
|
-
case '$not':
|
|
437
|
-
ctx.append('NOT (');
|
|
438
|
-
this.compare(ctx, entity, key as any, val as any, opts);
|
|
439
|
-
ctx.append(')');
|
|
440
|
-
break;
|
|
441
|
-
case '$gt':
|
|
442
|
-
this.getComparisonKey(ctx, entity, key, opts);
|
|
443
|
-
ctx.append(' > ');
|
|
444
|
-
ctx.addValue(val);
|
|
445
|
-
break;
|
|
446
|
-
case '$gte':
|
|
447
|
-
this.getComparisonKey(ctx, entity, key, opts);
|
|
448
|
-
ctx.append(' >= ');
|
|
449
|
-
ctx.addValue(val);
|
|
450
|
-
break;
|
|
451
|
-
case '$lt':
|
|
452
|
-
this.getComparisonKey(ctx, entity, key, opts);
|
|
453
|
-
ctx.append(' < ');
|
|
454
|
-
ctx.addValue(val);
|
|
455
|
-
break;
|
|
456
|
-
case '$lte':
|
|
457
|
-
this.getComparisonKey(ctx, entity, key, opts);
|
|
458
|
-
ctx.append(' <= ');
|
|
459
|
-
ctx.addValue(val);
|
|
460
|
-
break;
|
|
461
|
-
case '$startsWith':
|
|
462
|
-
this.getComparisonKey(ctx, entity, key, opts);
|
|
463
|
-
ctx.append(' LIKE ');
|
|
464
|
-
ctx.addValue(`${val}%`);
|
|
465
|
-
break;
|
|
466
|
-
case '$istartsWith':
|
|
467
|
-
this.getComparisonKey(ctx, entity, key, opts);
|
|
468
|
-
ctx.append(' LIKE ');
|
|
469
|
-
ctx.addValue(`${(val as string).toLowerCase()}%`);
|
|
470
|
-
break;
|
|
471
|
-
case '$endsWith':
|
|
472
|
-
this.getComparisonKey(ctx, entity, key, opts);
|
|
473
|
-
ctx.append(' LIKE ');
|
|
474
|
-
ctx.addValue(`%${val}`);
|
|
475
|
-
break;
|
|
476
|
-
case '$iendsWith':
|
|
477
|
-
this.getComparisonKey(ctx, entity, key, opts);
|
|
478
|
-
ctx.append(' LIKE ');
|
|
479
|
-
ctx.addValue(`%${(val as string).toLowerCase()}`);
|
|
480
|
-
break;
|
|
481
|
-
case '$includes':
|
|
482
|
-
this.getComparisonKey(ctx, entity, key, opts);
|
|
483
|
-
ctx.append(' LIKE ');
|
|
484
|
-
ctx.addValue(`%${val}%`);
|
|
485
|
-
break;
|
|
486
|
-
case '$iincludes':
|
|
487
|
-
this.getComparisonKey(ctx, entity, key, opts);
|
|
488
|
-
ctx.append(' LIKE ');
|
|
489
|
-
ctx.addValue(`%${(val as string).toLowerCase()}%`);
|
|
490
|
-
break;
|
|
491
|
-
case '$ilike':
|
|
492
|
-
this.getComparisonKey(ctx, entity, key, opts);
|
|
493
|
-
ctx.append(' LIKE ');
|
|
494
|
-
ctx.addValue((val as string).toLowerCase());
|
|
495
|
-
break;
|
|
496
|
-
case '$like':
|
|
497
|
-
this.getComparisonKey(ctx, entity, key, opts);
|
|
498
|
-
ctx.append(' LIKE ');
|
|
499
|
-
ctx.addValue(val);
|
|
500
|
-
break;
|
|
501
|
-
case '$in':
|
|
502
|
-
this.getComparisonKey(ctx, entity, key, opts);
|
|
503
|
-
if (Array.isArray(val) && val.length > 0) {
|
|
504
|
-
ctx.append(' IN (');
|
|
505
|
-
this.addValues(ctx, val as any[]);
|
|
506
|
-
ctx.append(')');
|
|
507
|
-
} else {
|
|
508
|
-
ctx.append(' IN (NULL)');
|
|
509
|
-
}
|
|
510
|
-
break;
|
|
511
|
-
case '$nin':
|
|
512
|
-
this.getComparisonKey(ctx, entity, key, opts);
|
|
513
|
-
if (Array.isArray(val) && val.length > 0) {
|
|
514
|
-
ctx.append(' NOT IN (');
|
|
515
|
-
this.addValues(ctx, val as any[]);
|
|
516
|
-
ctx.append(')');
|
|
517
|
-
} else {
|
|
518
|
-
ctx.append(' NOT IN (NULL)');
|
|
519
|
-
}
|
|
520
|
-
break;
|
|
521
|
-
case '$regex':
|
|
522
|
-
this.getComparisonKey(ctx, entity, key, opts);
|
|
523
|
-
ctx.append(' REGEXP ');
|
|
524
|
-
ctx.addValue(val);
|
|
525
|
-
break;
|
|
526
|
-
default:
|
|
527
|
-
throw TypeError(`unknown operator: ${op}`);
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
protected addValues(ctx: QueryContext, vals: unknown[]): void {
|
|
532
|
-
vals.forEach((val, index) => {
|
|
533
|
-
if (index > 0) {
|
|
534
|
-
ctx.append(', ');
|
|
535
|
-
}
|
|
536
|
-
ctx.addValue(val);
|
|
537
|
-
});
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
getComparisonKey<E>(ctx: QueryContext, entity: Type<E>, key: FieldKey<E>, { prefix }: QueryOptions = {}): void {
|
|
541
|
-
const meta = getMeta(entity);
|
|
542
|
-
const escapedPrefix = this.escapeId(prefix, true, true);
|
|
543
|
-
const field = meta.fields[key];
|
|
544
|
-
|
|
545
|
-
if (field?.virtual) {
|
|
546
|
-
this.getRawValue(ctx, {
|
|
547
|
-
value: field.virtual,
|
|
548
|
-
prefix,
|
|
549
|
-
escapedPrefix,
|
|
550
|
-
});
|
|
551
|
-
return;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
const columnName = this.resolveColumnName(key, field);
|
|
555
|
-
ctx.append(escapedPrefix + this.escapeId(columnName));
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
sort<E>(ctx: QueryContext, entity: Type<E>, sort: QuerySort<E>, { prefix }: QueryOptions): void {
|
|
559
|
-
const sortMap = buildSortMap(sort);
|
|
560
|
-
if (!hasKeys(sortMap)) {
|
|
561
|
-
return;
|
|
562
|
-
}
|
|
563
|
-
const meta = getMeta(entity);
|
|
564
|
-
const flattenedSort = flatObject(sortMap, prefix);
|
|
565
|
-
const directionMap = { 1: '', asc: '', '-1': ' DESC', desc: ' DESC' } as const;
|
|
566
|
-
|
|
567
|
-
ctx.append(' ORDER BY ');
|
|
568
|
-
|
|
569
|
-
Object.entries(flattenedSort).forEach(([key, sort], index) => {
|
|
570
|
-
if (index > 0) {
|
|
571
|
-
ctx.append(', ');
|
|
572
|
-
}
|
|
573
|
-
const field = meta.fields[key];
|
|
574
|
-
const name = this.resolveColumnName(key, field);
|
|
575
|
-
const direction = directionMap[sort as QuerySortDirection];
|
|
576
|
-
ctx.append(this.escapeId(name) + direction);
|
|
577
|
-
});
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
pager(ctx: QueryContext, opts: QueryPager): void {
|
|
581
|
-
if (opts.$limit) {
|
|
582
|
-
ctx.append(` LIMIT ${Number(opts.$limit)}`);
|
|
583
|
-
}
|
|
584
|
-
if (opts.$skip !== undefined) {
|
|
585
|
-
ctx.append(` OFFSET ${Number(opts.$skip)}`);
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
count<E>(ctx: QueryContext, entity: Type<E>, q: QuerySearch<E>, opts?: QueryOptions): void {
|
|
590
|
-
const search: Query<E> = { ...q };
|
|
591
|
-
delete search.$sort;
|
|
592
|
-
this.select<E>(ctx, entity, [raw('COUNT(*)', 'count')], undefined);
|
|
593
|
-
this.search(ctx, entity, search, opts);
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
find<E>(ctx: QueryContext, entity: Type<E>, q: Query<E> = {}, opts?: QueryOptions): void {
|
|
597
|
-
this.select(ctx, entity, q.$select, opts);
|
|
598
|
-
this.search(ctx, entity, q, opts);
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
insert<E>(ctx: QueryContext, entity: Type<E>, payload: E | E[], opts?: QueryOptions): void {
|
|
602
|
-
const meta = getMeta(entity);
|
|
603
|
-
const payloads = fillOnFields(meta, payload, 'onInsert');
|
|
604
|
-
const keys = filterFieldKeys(meta, payloads[0], 'onInsert');
|
|
605
|
-
|
|
606
|
-
const columns = keys.map((key) => {
|
|
607
|
-
const field = meta.fields[key];
|
|
608
|
-
return this.escapeId(this.resolveColumnName(key, field));
|
|
609
|
-
});
|
|
610
|
-
const tableName = this.resolveTableName(entity, meta);
|
|
611
|
-
ctx.append(`INSERT INTO ${this.escapeId(tableName)} (${columns.join(', ')}) VALUES (`);
|
|
612
|
-
|
|
613
|
-
payloads.forEach((it, recordIndex) => {
|
|
614
|
-
if (recordIndex > 0) {
|
|
615
|
-
ctx.append('), (');
|
|
616
|
-
}
|
|
617
|
-
keys.forEach((key, keyIndex) => {
|
|
618
|
-
if (keyIndex > 0) {
|
|
619
|
-
ctx.append(', ');
|
|
620
|
-
}
|
|
621
|
-
const field = meta.fields[key];
|
|
622
|
-
this.formatPersistableValue(ctx, field, it[key]);
|
|
623
|
-
});
|
|
624
|
-
});
|
|
625
|
-
ctx.append(')');
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
update<E>(ctx: QueryContext, entity: Type<E>, q: QuerySearch<E>, payload: E, opts?: QueryOptions): void {
|
|
629
|
-
const meta = getMeta(entity);
|
|
630
|
-
const [filledPayload] = fillOnFields(meta, payload, 'onUpdate');
|
|
631
|
-
const keys = filterFieldKeys(meta, filledPayload, 'onUpdate');
|
|
632
|
-
|
|
633
|
-
const tableName = this.resolveTableName(entity, meta);
|
|
634
|
-
ctx.append(`UPDATE ${this.escapeId(tableName)} SET `);
|
|
635
|
-
keys.forEach((key, index) => {
|
|
636
|
-
if (index > 0) {
|
|
637
|
-
ctx.append(', ');
|
|
638
|
-
}
|
|
639
|
-
const field = meta.fields[key];
|
|
640
|
-
const columnName = this.resolveColumnName(key, field);
|
|
641
|
-
ctx.append(`${this.escapeId(columnName)} = `);
|
|
642
|
-
this.formatPersistableValue(ctx, field, filledPayload[key]);
|
|
643
|
-
});
|
|
644
|
-
|
|
645
|
-
this.search(ctx, entity, q, opts);
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
upsert<E>(ctx: QueryContext, entity: Type<E>, conflictPaths: QueryConflictPaths<E>, payload: E): void {
|
|
649
|
-
const meta = getMeta(entity);
|
|
650
|
-
const update = this.getUpsertUpdateAssignments(ctx, meta, conflictPaths, payload, (name) => `VALUES(${name})`);
|
|
651
|
-
|
|
652
|
-
if (update) {
|
|
653
|
-
this.insert(ctx, entity, payload);
|
|
654
|
-
ctx.append(` ON DUPLICATE KEY UPDATE ${update}`);
|
|
655
|
-
} else {
|
|
656
|
-
const insertCtx = this.createContext();
|
|
657
|
-
this.insert(insertCtx, entity, payload);
|
|
658
|
-
ctx.append(insertCtx.sql.replace(/^INSERT/, 'INSERT IGNORE'));
|
|
659
|
-
insertCtx.values.forEach((val) => {
|
|
660
|
-
ctx.pushValue(val);
|
|
661
|
-
});
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
protected getUpsertUpdateAssignments<E>(
|
|
666
|
-
ctx: QueryContext,
|
|
667
|
-
meta: EntityMeta<E>,
|
|
668
|
-
conflictPaths: QueryConflictPaths<E>,
|
|
669
|
-
payload: E,
|
|
670
|
-
callback?: (columnName: string) => string,
|
|
671
|
-
): string {
|
|
672
|
-
const [filledPayload] = fillOnFields(meta, payload, 'onUpdate');
|
|
673
|
-
const fields = filterFieldKeys(meta, filledPayload, 'onUpdate');
|
|
674
|
-
return fields
|
|
675
|
-
.filter((col) => !conflictPaths[col])
|
|
676
|
-
.map((col) => {
|
|
677
|
-
const field = meta.fields[col];
|
|
678
|
-
const columnName = this.resolveColumnName(col, field);
|
|
679
|
-
if (callback) {
|
|
680
|
-
return `${this.escapeId(columnName)} = ${callback(this.escapeId(columnName))}`;
|
|
681
|
-
}
|
|
682
|
-
const valCtx = this.createContext();
|
|
683
|
-
this.formatPersistableValue(valCtx, field, filledPayload[col]);
|
|
684
|
-
valCtx.values.forEach((val) => {
|
|
685
|
-
ctx.pushValue(val);
|
|
686
|
-
});
|
|
687
|
-
return `${this.escapeId(columnName)} = ${valCtx.sql}`;
|
|
688
|
-
})
|
|
689
|
-
.join(', ');
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
protected getUpsertConflictPathsStr<E>(meta: EntityMeta<E>, conflictPaths: QueryConflictPaths<E>): string {
|
|
693
|
-
return getKeys(conflictPaths)
|
|
694
|
-
.map((key) => {
|
|
695
|
-
const field = meta.fields[key];
|
|
696
|
-
const columnName = this.resolveColumnName(key, field);
|
|
697
|
-
return this.escapeId(columnName);
|
|
698
|
-
})
|
|
699
|
-
.join(', ');
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
delete<E>(ctx: QueryContext, entity: Type<E>, q: QuerySearch<E>, opts: QueryOptions = {}): void {
|
|
703
|
-
const meta = getMeta(entity);
|
|
704
|
-
const tableName = this.resolveTableName(entity, meta);
|
|
705
|
-
|
|
706
|
-
if (opts.softDelete || opts.softDelete === undefined) {
|
|
707
|
-
if (meta.softDelete) {
|
|
708
|
-
const field = meta.fields[meta.softDelete];
|
|
709
|
-
const value = getFieldCallbackValue(field.onDelete);
|
|
710
|
-
const columnName = this.resolveColumnName(meta.softDelete, field);
|
|
711
|
-
ctx.append(`UPDATE ${this.escapeId(tableName)} SET ${this.escapeId(columnName)} = `);
|
|
712
|
-
ctx.addValue(value);
|
|
713
|
-
this.search(ctx, entity, q, opts);
|
|
714
|
-
return;
|
|
715
|
-
}
|
|
716
|
-
if (opts.softDelete) {
|
|
717
|
-
throw TypeError(`'${tableName}' has not enabled 'softDelete'`);
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
ctx.append(`DELETE FROM ${this.escapeId(tableName)}`);
|
|
722
|
-
this.search(ctx, entity, q, opts);
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
escapeId(val: string, forbidQualified?: boolean, addDot?: boolean): string {
|
|
726
|
-
return escapeSqlId(val, this.escapeIdChar, forbidQualified, addDot);
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
protected getPersistables<E>(
|
|
730
|
-
ctx: QueryContext,
|
|
731
|
-
meta: EntityMeta<E>,
|
|
732
|
-
payload: E | E[],
|
|
733
|
-
callbackKey: CallbackKey,
|
|
734
|
-
): Record<string, unknown>[] {
|
|
735
|
-
const payloads = fillOnFields(meta, payload, callbackKey);
|
|
736
|
-
return payloads.map((it) => this.getPersistable(ctx, meta, it, callbackKey));
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
protected getPersistable<E>(
|
|
740
|
-
ctx: QueryContext,
|
|
741
|
-
meta: EntityMeta<E>,
|
|
742
|
-
payload: E,
|
|
743
|
-
callbackKey: CallbackKey,
|
|
744
|
-
): Record<string, unknown> {
|
|
745
|
-
const filledPayload = fillOnFields(meta, payload, callbackKey)[0];
|
|
746
|
-
const keys = filterFieldKeys(meta, filledPayload, callbackKey);
|
|
747
|
-
return keys.reduce(
|
|
748
|
-
(acc, key) => {
|
|
749
|
-
const field = meta.fields[key];
|
|
750
|
-
const valCtx = this.createContext();
|
|
751
|
-
this.formatPersistableValue(valCtx, field, filledPayload[key]);
|
|
752
|
-
valCtx.values.forEach((val) => {
|
|
753
|
-
ctx.pushValue(val);
|
|
754
|
-
});
|
|
755
|
-
acc[key as string] = valCtx.sql;
|
|
756
|
-
return acc;
|
|
757
|
-
},
|
|
758
|
-
{} as Record<string, unknown>,
|
|
759
|
-
);
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
protected formatPersistableValue<E>(ctx: QueryContext, field: FieldOptions, value: unknown): void {
|
|
763
|
-
if (value instanceof QueryRaw) {
|
|
764
|
-
this.getRawValue(ctx, { value });
|
|
765
|
-
return;
|
|
766
|
-
}
|
|
767
|
-
if (field?.type === 'json' || field?.type === 'jsonb') {
|
|
768
|
-
ctx.addValue(value ? JSON.stringify(value) : null);
|
|
769
|
-
return;
|
|
770
|
-
}
|
|
771
|
-
if (field?.type === 'vector' && Array.isArray(value)) {
|
|
772
|
-
ctx.addValue(`[${value.join(',')}]`);
|
|
773
|
-
return;
|
|
774
|
-
}
|
|
775
|
-
ctx.addValue(value);
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
getRawValue(ctx: QueryContext, opts: QueryRawFnOptions & { value: QueryRaw; autoPrefixAlias?: boolean }) {
|
|
779
|
-
const { value, prefix = '', escapedPrefix, autoPrefixAlias } = opts;
|
|
780
|
-
if (typeof value.value === 'function') {
|
|
781
|
-
const res = value.value({
|
|
782
|
-
...opts,
|
|
783
|
-
ctx,
|
|
784
|
-
dialect: this,
|
|
785
|
-
prefix,
|
|
786
|
-
escapedPrefix: escapedPrefix ?? this.escapeId(prefix, true, true),
|
|
787
|
-
});
|
|
788
|
-
if (typeof res === 'string' || (typeof res === 'number' && !Number.isNaN(res))) {
|
|
789
|
-
ctx.append(String(res));
|
|
790
|
-
}
|
|
791
|
-
} else {
|
|
792
|
-
ctx.append(prefix + String(value.value));
|
|
793
|
-
}
|
|
794
|
-
const alias = value.alias;
|
|
795
|
-
if (alias) {
|
|
796
|
-
const fullAlias = autoPrefixAlias ? prefix + alias : alias;
|
|
797
|
-
// Replace dots with underscores for alias to avoid syntax errors
|
|
798
|
-
const safeAlias = fullAlias.replace(/\./g, '_');
|
|
799
|
-
const escapedFullAlias = this.escapeId(safeAlias, true);
|
|
800
|
-
ctx.append(' ' + escapedFullAlias);
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
abstract escape(value: unknown): string;
|
|
805
|
-
}
|