@cheetah.js/orm 0.1.13 → 0.1.15
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/dist/SqlBuilder.d.ts +19 -4
- package/dist/SqlBuilder.js +299 -81
- package/dist/SqlBuilder.js.map +1 -1
- package/dist/bun/index.js +225061 -0
- package/dist/bun/index.js.map +315 -0
- package/dist/cheetah.js +3 -5
- package/dist/cheetah.js.map +1 -1
- package/dist/common/email.vo.js +2 -6
- package/dist/common/email.vo.js.map +1 -1
- package/dist/common/uuid.js +2 -6
- package/dist/common/uuid.js.map +1 -1
- package/dist/common/value-object.js +3 -7
- package/dist/common/value-object.js.map +1 -1
- package/dist/constants.js +4 -7
- package/dist/constants.js.map +1 -1
- package/dist/decorators/entity.decorator.js +5 -9
- package/dist/decorators/entity.decorator.js.map +1 -1
- package/dist/decorators/index.decorator.js +4 -8
- package/dist/decorators/index.decorator.js.map +1 -1
- package/dist/decorators/one-many.decorator.js +10 -15
- package/dist/decorators/one-many.decorator.js.map +1 -1
- package/dist/decorators/primary-key.decorator.js +3 -7
- package/dist/decorators/primary-key.decorator.js.map +1 -1
- package/dist/decorators/property.decorator.js +13 -17
- package/dist/decorators/property.decorator.js.map +1 -1
- package/dist/domain/base-entity.js +12 -8
- package/dist/domain/base-entity.js.map +1 -1
- package/dist/domain/collection.js +2 -7
- package/dist/domain/collection.js.map +1 -1
- package/dist/domain/entities.js +7 -10
- package/dist/domain/entities.js.map +1 -1
- package/dist/domain/reference.js +1 -5
- package/dist/domain/reference.js.map +1 -1
- package/dist/driver/driver.interface.d.ts +17 -4
- package/dist/driver/driver.interface.js +1 -2
- package/dist/driver/pg-driver.js +4 -7
- package/dist/driver/pg-driver.js.map +1 -1
- package/dist/entry.js +5 -8
- package/dist/entry.js.map +1 -1
- package/dist/index.js +15 -31
- package/dist/index.js.map +1 -1
- package/dist/migration/diff-calculator.js +1 -5
- package/dist/migration/diff-calculator.js.map +1 -1
- package/dist/migration/migrator.d.ts +1 -1
- package/dist/migration/migrator.js +16 -43
- package/dist/migration/migrator.js.map +1 -1
- package/dist/orm.js +7 -10
- package/dist/orm.js.map +1 -1
- package/dist/orm.service.js +28 -58
- package/dist/orm.service.js.map +1 -1
- package/dist/utils.js +1 -5
- package/dist/utils.js.map +1 -1
- package/package.json +2 -2
- package/test/domain/base-entity.spec.ts +81 -39
- package/test/domain/relationship.spec.ts +173 -0
package/dist/SqlBuilder.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AutoPath, FilterQuery, QueryOrderMap, ValueOrInstance } from './driver/driver.interface';
|
|
1
|
+
import { AutoPath, FilterQuery, QueryOrderMap, Statement, ValueOrInstance } from './driver/driver.interface';
|
|
2
2
|
export declare class SqlBuilder<T> {
|
|
3
3
|
private readonly driver;
|
|
4
4
|
private entityStorage;
|
|
@@ -9,8 +9,10 @@ export declare class SqlBuilder<T> {
|
|
|
9
9
|
private lastKeyNotOperator;
|
|
10
10
|
private logger;
|
|
11
11
|
private updatedColumns;
|
|
12
|
+
private originalColumns;
|
|
12
13
|
constructor(model: new () => T);
|
|
13
14
|
select(columns?: AutoPath<T, never, '*'>[]): SqlBuilder<T>;
|
|
15
|
+
setStrategy(strategy?: 'joined' | 'select'): SqlBuilder<T>;
|
|
14
16
|
insert(values: Partial<{
|
|
15
17
|
[K in keyof T]: ValueOrInstance<T[K]>;
|
|
16
18
|
}>): SqlBuilder<T>;
|
|
@@ -23,14 +25,27 @@ export declare class SqlBuilder<T> {
|
|
|
23
25
|
}) | QueryOrderMap<T>[]): SqlBuilder<T>;
|
|
24
26
|
limit(limit: number | undefined): SqlBuilder<T>;
|
|
25
27
|
offset(offset: number | undefined): SqlBuilder<T>;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
load(load: string[]): SqlBuilder<T>;
|
|
29
|
+
private addJoinForRelationshipPath;
|
|
30
|
+
private getPrimaryKeyColumnName;
|
|
29
31
|
execute(): Promise<{
|
|
30
32
|
query: any;
|
|
31
33
|
startTime: number;
|
|
32
34
|
sql: string;
|
|
33
35
|
}>;
|
|
36
|
+
executeAndReturnFirst(): Promise<T | undefined>;
|
|
37
|
+
executeAndReturnFirstOrFail(): Promise<T>;
|
|
38
|
+
executeAndReturnAll(): Promise<T[]>;
|
|
39
|
+
private handleSelectJoin;
|
|
40
|
+
getPathForSelectJoin(selectJoin: Statement<any>): string[] | null;
|
|
41
|
+
private setValueByPath;
|
|
42
|
+
private getPathForSelectJoinRecursive;
|
|
43
|
+
private findIdRecursively;
|
|
44
|
+
private generateColumns;
|
|
45
|
+
private extractAliasForColumns;
|
|
46
|
+
private filterInvalidColumns;
|
|
47
|
+
private includeUpdatedColumns;
|
|
48
|
+
private logExecution;
|
|
34
49
|
startTransaction(): Promise<void>;
|
|
35
50
|
commit(): Promise<void>;
|
|
36
51
|
rollback(): Promise<void>;
|
package/dist/SqlBuilder.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const value_object_1 = require("./common/value-object");
|
|
7
|
-
class SqlBuilder {
|
|
1
|
+
import { EntityStorage } from './domain/entities';
|
|
2
|
+
import { Orm } from './orm';
|
|
3
|
+
import { ValueObject } from './common/value-object';
|
|
4
|
+
import { BaseEntity } from '@cheetah.js/orm/domain/base-entity';
|
|
5
|
+
export class SqlBuilder {
|
|
8
6
|
driver;
|
|
9
7
|
entityStorage;
|
|
10
8
|
statements = {};
|
|
@@ -14,11 +12,12 @@ class SqlBuilder {
|
|
|
14
12
|
lastKeyNotOperator = '';
|
|
15
13
|
logger;
|
|
16
14
|
updatedColumns = [];
|
|
15
|
+
originalColumns = [];
|
|
17
16
|
constructor(model) {
|
|
18
|
-
const orm =
|
|
17
|
+
const orm = Orm.getInstance();
|
|
19
18
|
this.driver = orm.driverInstance;
|
|
20
19
|
this.logger = orm.logger;
|
|
21
|
-
this.entityStorage =
|
|
20
|
+
this.entityStorage = EntityStorage.getInstance();
|
|
22
21
|
this.getEntity(model);
|
|
23
22
|
}
|
|
24
23
|
select(columns) {
|
|
@@ -26,17 +25,18 @@ class SqlBuilder {
|
|
|
26
25
|
const schema = this.entity.schema || 'public';
|
|
27
26
|
this.statements.statement = 'select';
|
|
28
27
|
this.statements.columns = columns;
|
|
28
|
+
this.originalColumns = columns || [];
|
|
29
29
|
this.statements.alias = this.getAlias(tableName);
|
|
30
30
|
this.statements.table = `"${schema}"."${tableName}"`;
|
|
31
31
|
return this;
|
|
32
32
|
}
|
|
33
|
+
setStrategy(strategy = 'joined') {
|
|
34
|
+
this.statements.strategy = strategy;
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
33
37
|
insert(values) {
|
|
34
38
|
const { tableName, schema } = this.getTableName();
|
|
35
|
-
|
|
36
|
-
if (this.extendsFrom(value_object_1.ValueObject, values[value].constructor.prototype)) {
|
|
37
|
-
values[value] = values[value].getValue();
|
|
38
|
-
}
|
|
39
|
-
}
|
|
39
|
+
processValuesForInsert(values);
|
|
40
40
|
this.statements.statement = 'insert';
|
|
41
41
|
this.statements.alias = this.getAlias(tableName);
|
|
42
42
|
this.statements.table = `"${schema}"."${tableName}"`;
|
|
@@ -45,11 +45,7 @@ class SqlBuilder {
|
|
|
45
45
|
}
|
|
46
46
|
update(values) {
|
|
47
47
|
const { tableName, schema } = this.getTableName();
|
|
48
|
-
|
|
49
|
-
if (this.extendsFrom(value_object_1.ValueObject, values[value].constructor.prototype)) {
|
|
50
|
-
values[value] = values[value].getValue();
|
|
51
|
-
}
|
|
52
|
-
}
|
|
48
|
+
processValuesForUpdate(values);
|
|
53
49
|
this.statements.statement = 'update';
|
|
54
50
|
this.statements.alias = this.getAlias(tableName);
|
|
55
51
|
this.statements.table = `${schema}.${tableName}`;
|
|
@@ -57,14 +53,14 @@ class SqlBuilder {
|
|
|
57
53
|
return this;
|
|
58
54
|
}
|
|
59
55
|
where(where) {
|
|
60
|
-
if (
|
|
56
|
+
if (!where || Object.keys(where).length === 0) {
|
|
61
57
|
return this;
|
|
62
58
|
}
|
|
63
|
-
this.statements.where = this.conditionToSql(where, this.statements.alias);
|
|
59
|
+
this.statements.where = this.conditionToSql(where, this.statements.alias, this.model);
|
|
64
60
|
return this;
|
|
65
61
|
}
|
|
66
62
|
orderBy(orderBy) {
|
|
67
|
-
if (
|
|
63
|
+
if (!orderBy) {
|
|
68
64
|
return this;
|
|
69
65
|
}
|
|
70
66
|
this.statements.orderBy = this.objectToStringMap(orderBy);
|
|
@@ -78,13 +74,77 @@ class SqlBuilder {
|
|
|
78
74
|
this.statements.offset = offset;
|
|
79
75
|
return this;
|
|
80
76
|
}
|
|
77
|
+
load(load) {
|
|
78
|
+
load?.forEach(relationshipPath => {
|
|
79
|
+
this.addJoinForRelationshipPath(this.entity, relationshipPath);
|
|
80
|
+
});
|
|
81
|
+
if (this.statements.join) {
|
|
82
|
+
this.statements.join = this.statements.join?.reverse();
|
|
83
|
+
}
|
|
84
|
+
if (this.statements.selectJoin) {
|
|
85
|
+
this.statements.selectJoin = this.statements.selectJoin?.reverse();
|
|
86
|
+
}
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
addJoinForRelationshipPath(entity, relationshipPath) {
|
|
90
|
+
const relationshipNames = relationshipPath.split('.');
|
|
91
|
+
let currentEntity = entity;
|
|
92
|
+
let currentAlias = this.statements.alias;
|
|
93
|
+
let statement = this.statements.strategy === 'joined' ? this.statements.join : this.statements.selectJoin;
|
|
94
|
+
let nameAliasProperty = this.statements.strategy === 'joined' ? 'joinAlias' : 'alias';
|
|
95
|
+
relationshipNames.forEach((relationshipName, index) => {
|
|
96
|
+
const relationship = currentEntity.relations.find(rel => rel.propertyKey === relationshipName);
|
|
97
|
+
if (!relationship) {
|
|
98
|
+
// @ts-ignore
|
|
99
|
+
throw new Error(`Relationship "${relationshipName}" not found in entity "${currentEntity.name}"`);
|
|
100
|
+
}
|
|
101
|
+
const isLastRelationship = index === relationshipNames.length - 1;
|
|
102
|
+
if (index === (relationshipNames.length - 2 >= 0 ? relationshipNames.length - 2 : 0)) {
|
|
103
|
+
const join = statement?.find(j => j.joinProperty === relationshipName);
|
|
104
|
+
if (join) {
|
|
105
|
+
// @ts-ignore
|
|
106
|
+
currentAlias = join[nameAliasProperty];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (relationship.relation === 'many-to-one' && isLastRelationship) {
|
|
110
|
+
this.applyJoin(relationship, {}, currentAlias);
|
|
111
|
+
statement = this.statements.strategy === 'joined' ? this.statements.join : this.statements.selectJoin;
|
|
112
|
+
currentAlias = statement[statement.length - 1][nameAliasProperty];
|
|
113
|
+
}
|
|
114
|
+
currentEntity = this.entityStorage.get(relationship.entity());
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
getPrimaryKeyColumnName(entity) {
|
|
118
|
+
// Lógica para obter o nome da coluna de chave primária da entidade
|
|
119
|
+
// Aqui você pode substituir por sua própria lógica, dependendo da estrutura do seu projeto
|
|
120
|
+
// Por exemplo, se a chave primária for sempre 'id', você pode retornar 'id'.
|
|
121
|
+
// Se a lógica for mais complexa, você pode adicionar um método na classe Options para obter a chave primária.
|
|
122
|
+
return 'id';
|
|
123
|
+
}
|
|
124
|
+
async execute() {
|
|
125
|
+
if (!this.statements.columns) {
|
|
126
|
+
this.statements.columns = this.generateColumns();
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
this.extractAliasForColumns();
|
|
130
|
+
this.filterInvalidColumns();
|
|
131
|
+
}
|
|
132
|
+
this.statements.join = this.statements.join?.reverse();
|
|
133
|
+
this.includeUpdatedColumns();
|
|
134
|
+
const result = await this.driver.executeStatement(this.statements);
|
|
135
|
+
this.logExecution(result);
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
81
138
|
async executeAndReturnFirst() {
|
|
82
139
|
this.statements.limit = 1;
|
|
83
140
|
const result = await this.execute();
|
|
84
141
|
if (result.query.rows.length === 0) {
|
|
85
142
|
return undefined;
|
|
86
143
|
}
|
|
87
|
-
|
|
144
|
+
const entities = result.query.rows[0];
|
|
145
|
+
const model = await this.transformToModel(this.model, this.statements, entities);
|
|
146
|
+
await this.handleSelectJoin(entities, model);
|
|
147
|
+
return model;
|
|
88
148
|
}
|
|
89
149
|
async executeAndReturnFirstOrFail() {
|
|
90
150
|
this.statements.limit = 1;
|
|
@@ -92,40 +152,126 @@ class SqlBuilder {
|
|
|
92
152
|
if (result.query.rows.length === 0) {
|
|
93
153
|
throw new Error('Result not found');
|
|
94
154
|
}
|
|
95
|
-
|
|
155
|
+
const entities = result.query.rows[0];
|
|
156
|
+
const model = await this.transformToModel(this.model, this.statements, entities);
|
|
157
|
+
await this.handleSelectJoin(entities, model);
|
|
158
|
+
return model;
|
|
96
159
|
}
|
|
97
|
-
// TODO: Corrigir tipagem do retorno de acordo com o driver
|
|
98
160
|
async executeAndReturnAll() {
|
|
99
161
|
const result = await this.execute();
|
|
100
162
|
if (result.query.rows.length === 0) {
|
|
101
163
|
return [];
|
|
102
164
|
}
|
|
103
|
-
|
|
165
|
+
const rows = result.query.rows;
|
|
166
|
+
const results = [];
|
|
167
|
+
for (const row of rows) {
|
|
168
|
+
const models = this.transformToModel(this.model, this.statements, row);
|
|
169
|
+
await this.handleSelectJoin(row, models);
|
|
170
|
+
results.push(models);
|
|
171
|
+
}
|
|
172
|
+
return results;
|
|
104
173
|
}
|
|
105
|
-
async
|
|
106
|
-
if (!this.statements.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
174
|
+
async handleSelectJoin(entities, models) {
|
|
175
|
+
if (!this.statements.selectJoin || this.statements.selectJoin.length === 0) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
for (const join of this.statements.selectJoin.reverse()) {
|
|
179
|
+
let ids = entities[`${join.originAlias}_${join.primaryKey}`];
|
|
180
|
+
if (typeof ids === 'undefined') {
|
|
181
|
+
// get of models
|
|
182
|
+
const selectJoined = this.statements.selectJoin.find(j => j.joinEntity === join.originEntity);
|
|
183
|
+
if (!selectJoined) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
ids = this.findIdRecursively(models, selectJoined, join);
|
|
187
|
+
}
|
|
188
|
+
if (Array.isArray(ids)) {
|
|
189
|
+
ids = ids.map((id) => this.t(id)).join(', ');
|
|
190
|
+
}
|
|
191
|
+
if (join.where) {
|
|
192
|
+
join.where = `${join.where} AND ${join.alias}."${join.fkKey}" IN (${ids})`;
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
join.where = `${join.alias}."${join.fkKey}" IN (${ids})`;
|
|
115
196
|
}
|
|
116
|
-
|
|
197
|
+
if (join.columns && join.columns.length > 0) {
|
|
198
|
+
join.columns = join.columns.map(
|
|
199
|
+
// @ts-ignore
|
|
200
|
+
(column) => `${join.alias}."${column}" as "${join.alias}_${column}"`);
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
join.columns = this.getColumnsEntity(join.joinEntity, join.alias);
|
|
204
|
+
}
|
|
205
|
+
const child = await this.driver.executeStatement(join);
|
|
206
|
+
this.logger.debug(`SQL: ${child.sql} [${Date.now() - child.startTime}ms]`);
|
|
207
|
+
const property = this.entityStorage.get(this.model).relations.find((rel) => rel.propertyKey === join.joinProperty);
|
|
208
|
+
const values = child.query.rows.map((row) => this.transformToModel(join.joinEntity, join, row));
|
|
209
|
+
const path = this.getPathForSelectJoin(join);
|
|
210
|
+
this.setValueByPath(models, path, property?.type === Array ? [...values] : values[0]);
|
|
117
211
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
212
|
+
return models;
|
|
213
|
+
}
|
|
214
|
+
getPathForSelectJoin(selectJoin) {
|
|
215
|
+
const path = this.getPathForSelectJoinRecursive(this.statements, selectJoin);
|
|
216
|
+
return path.reverse();
|
|
217
|
+
}
|
|
218
|
+
setValueByPath(obj, path, value) {
|
|
219
|
+
let currentObj = obj;
|
|
220
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
221
|
+
const key = path[i];
|
|
222
|
+
currentObj[key] = currentObj[key] || {};
|
|
223
|
+
currentObj = currentObj[key];
|
|
224
|
+
}
|
|
225
|
+
currentObj[path[path.length - 1]] = value;
|
|
226
|
+
}
|
|
227
|
+
getPathForSelectJoinRecursive(statements, selectJoin) {
|
|
228
|
+
const originJoin = this.statements.selectJoin.find(j => j.joinEntity === selectJoin.originEntity);
|
|
229
|
+
let pathInJoin = [];
|
|
230
|
+
if (!originJoin) {
|
|
231
|
+
return [selectJoin.joinProperty];
|
|
232
|
+
}
|
|
233
|
+
if (originJoin.originEntity !== statements.originEntity) {
|
|
234
|
+
pathInJoin = this.getPathForSelectJoinRecursive(statements, originJoin);
|
|
235
|
+
}
|
|
236
|
+
return [selectJoin.joinProperty, ...pathInJoin];
|
|
237
|
+
}
|
|
238
|
+
findIdRecursively(models, selectJoined, join) {
|
|
239
|
+
let ids = models[selectJoined.originProperty][join.primaryKey];
|
|
240
|
+
if (typeof ids === 'undefined') {
|
|
241
|
+
const nextSelectJoined = this.statements.selectJoin.find(j => j.joinEntity === selectJoined.originEntity);
|
|
242
|
+
if (nextSelectJoined) {
|
|
243
|
+
// Chamada recursiva para a próxima camada
|
|
244
|
+
ids = this.findIdRecursively(models, nextSelectJoined, join);
|
|
245
|
+
}
|
|
123
246
|
}
|
|
247
|
+
return ids;
|
|
248
|
+
}
|
|
249
|
+
generateColumns() {
|
|
250
|
+
let columns = [
|
|
251
|
+
...this.getColumnsEntity(this.model, this.statements.alias),
|
|
252
|
+
];
|
|
253
|
+
if (this.statements.join) {
|
|
254
|
+
columns = [
|
|
255
|
+
...columns,
|
|
256
|
+
...this.statements.join.flatMap(join => this.getColumnsEntity(join.joinEntity, join.joinAlias)),
|
|
257
|
+
];
|
|
258
|
+
}
|
|
259
|
+
return columns;
|
|
260
|
+
}
|
|
261
|
+
extractAliasForColumns() {
|
|
262
|
+
// @ts-ignore
|
|
263
|
+
this.statements.columns = this.statements.columns.map((column) => {
|
|
264
|
+
return this.discoverColumnAlias(column);
|
|
265
|
+
}).flat();
|
|
266
|
+
}
|
|
267
|
+
filterInvalidColumns() {
|
|
268
|
+
this.statements.columns = this.statements.columns.filter(Boolean);
|
|
269
|
+
}
|
|
270
|
+
includeUpdatedColumns() {
|
|
124
271
|
this.statements.columns.push(...this.updatedColumns);
|
|
125
|
-
|
|
126
|
-
|
|
272
|
+
}
|
|
273
|
+
logExecution(result) {
|
|
127
274
|
this.logger.debug(`SQL: ${result.sql} [${Date.now() - result.startTime}ms]`);
|
|
128
|
-
return result;
|
|
129
275
|
}
|
|
130
276
|
startTransaction() {
|
|
131
277
|
return this.driver.startTransaction();
|
|
@@ -172,20 +318,29 @@ class SqlBuilder {
|
|
|
172
318
|
}
|
|
173
319
|
return `${this.statements.alias}."${column}" as ${this.statements.alias}_${column}`;
|
|
174
320
|
}
|
|
175
|
-
if (typeof this.statements.join === 'undefined') {
|
|
321
|
+
if (typeof this.statements.join === 'undefined' && typeof this.statements.selectJoin === 'undefined') {
|
|
176
322
|
throw new Error('Join not found');
|
|
177
323
|
}
|
|
178
324
|
const entities = column.split('.');
|
|
179
325
|
let lastEntity = this.model;
|
|
180
326
|
let lastAlias = this.statements.alias;
|
|
181
327
|
const relationsMap = new Map(this.entity.relations.map(rel => [rel.propertyKey, rel]));
|
|
182
|
-
const joinMap = new Map(
|
|
328
|
+
const joinMap = new Map();
|
|
329
|
+
const joinSelectMap = new Map();
|
|
330
|
+
this.statements.join?.forEach(join => joinMap.set(join.joinProperty, join));
|
|
331
|
+
this.statements.selectJoin?.forEach(join => joinSelectMap.set(join.joinProperty, join));
|
|
183
332
|
for (let i = 0; i < entities.length; i++) {
|
|
184
333
|
if (i === 0) {
|
|
185
334
|
const relation = relationsMap.get(entities[i]);
|
|
186
335
|
lastEntity = relation?.entity();
|
|
187
336
|
// @ts-ignore
|
|
188
|
-
|
|
337
|
+
if (joinMap.has(entities[i])) {
|
|
338
|
+
lastAlias = joinMap.get(entities[i]).joinAlias;
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
lastAlias = joinSelectMap.get(entities[i])?.alias;
|
|
342
|
+
return undefined;
|
|
343
|
+
}
|
|
189
344
|
}
|
|
190
345
|
else {
|
|
191
346
|
if ((i + 1) === entities.length) {
|
|
@@ -219,19 +374,23 @@ class SqlBuilder {
|
|
|
219
374
|
addLogicalOperatorToSql(conditions, operator) {
|
|
220
375
|
return `(${conditions.join(` ${operator} `)})`;
|
|
221
376
|
}
|
|
222
|
-
conditionToSql(condition, alias) {
|
|
377
|
+
conditionToSql(condition, alias, model) {
|
|
223
378
|
const sqlParts = [];
|
|
224
379
|
const operators = ['$eq', '$ne', '$in', '$nin', '$like', '$gt', '$gte', '$lt', '$lte', '$and', '$or'];
|
|
225
380
|
for (let [key, value] of Object.entries(condition)) {
|
|
226
|
-
if (this.extendsFrom(
|
|
381
|
+
if (this.extendsFrom(ValueObject, value.constructor.prototype)) {
|
|
227
382
|
value = value.getValue();
|
|
228
383
|
}
|
|
229
384
|
if (!operators.includes(key)) {
|
|
230
385
|
this.lastKeyNotOperator = key;
|
|
231
386
|
}
|
|
232
|
-
const
|
|
387
|
+
const entity = this.entityStorage.get(model);
|
|
388
|
+
const relationShip = entity.relations?.find(rel => rel.propertyKey === key);
|
|
233
389
|
if (relationShip) {
|
|
234
|
-
|
|
390
|
+
const sql = this.applyJoin(relationShip, value, alias);
|
|
391
|
+
if (this.statements.strategy === 'joined') {
|
|
392
|
+
sqlParts.push(sql);
|
|
393
|
+
}
|
|
235
394
|
}
|
|
236
395
|
else if (typeof value !== 'object' || value === null) {
|
|
237
396
|
if (key === '$eq') {
|
|
@@ -245,7 +404,7 @@ class SqlBuilder {
|
|
|
245
404
|
}
|
|
246
405
|
else {
|
|
247
406
|
if (['$or', '$and'].includes(key)) {
|
|
248
|
-
sqlParts.push(this.addLogicalOperatorToSql(value.map((cond) => this.conditionToSql(cond, alias)), key.toUpperCase().replace('$', '')));
|
|
407
|
+
sqlParts.push(this.addLogicalOperatorToSql(value.map((cond) => this.conditionToSql(cond, alias, model)), key.toUpperCase().replace('$', '')));
|
|
249
408
|
}
|
|
250
409
|
for (const operator of operators) {
|
|
251
410
|
if (operator in value) {
|
|
@@ -279,7 +438,7 @@ class SqlBuilder {
|
|
|
279
438
|
break;
|
|
280
439
|
case '$and':
|
|
281
440
|
case '$or':
|
|
282
|
-
const parts = value[operator].map((cond) => this.conditionToSql(cond, alias));
|
|
441
|
+
const parts = value[operator].map((cond) => this.conditionToSql(cond, alias, model));
|
|
283
442
|
sqlParts.push(this.addLogicalOperatorToSql(parts, operator.toUpperCase().replace('$', '')));
|
|
284
443
|
break;
|
|
285
444
|
}
|
|
@@ -287,6 +446,9 @@ class SqlBuilder {
|
|
|
287
446
|
}
|
|
288
447
|
}
|
|
289
448
|
}
|
|
449
|
+
if (sqlParts.length === 0) {
|
|
450
|
+
return '';
|
|
451
|
+
}
|
|
290
452
|
return this.addLogicalOperatorToSql(sqlParts, 'AND');
|
|
291
453
|
}
|
|
292
454
|
t(value) {
|
|
@@ -306,33 +468,52 @@ class SqlBuilder {
|
|
|
306
468
|
}
|
|
307
469
|
}
|
|
308
470
|
const joinAlias = `${this.getAlias(joinTableName)}`;
|
|
309
|
-
const joinWhere = this.conditionToSql(value, joinAlias);
|
|
310
|
-
this.statements.join = this.statements.join || [];
|
|
471
|
+
const joinWhere = this.conditionToSql(value, joinAlias, relationShip.entity());
|
|
311
472
|
let on = '';
|
|
312
473
|
switch (relationShip.relation) {
|
|
313
474
|
case "one-to-many":
|
|
314
|
-
on = `${joinAlias}
|
|
475
|
+
on = `${joinAlias}."${this.getFkKey(relationShip)}" = ${alias}."${originPrimaryKey}"`;
|
|
315
476
|
break;
|
|
316
477
|
case "many-to-one":
|
|
317
|
-
on = `${alias}
|
|
478
|
+
on = `${alias}."${relationShip.propertyKey}" = ${joinAlias}."${this.getFkKey(relationShip)}"`;
|
|
318
479
|
break;
|
|
319
480
|
}
|
|
320
|
-
this.statements.
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
481
|
+
if (this.statements.strategy === 'joined') {
|
|
482
|
+
this.statements.join = this.statements.join || [];
|
|
483
|
+
this.statements.join.push({
|
|
484
|
+
joinAlias: joinAlias,
|
|
485
|
+
joinTable: joinTableName,
|
|
486
|
+
joinSchema: joinSchema || 'public',
|
|
487
|
+
joinWhere: joinWhere,
|
|
488
|
+
joinProperty: relationShip.propertyKey,
|
|
489
|
+
originAlias: alias,
|
|
490
|
+
originSchema: schema,
|
|
491
|
+
originTable: tableName,
|
|
492
|
+
propertyKey: relationShip.propertyKey,
|
|
493
|
+
joinEntity: relationShip.entity(),
|
|
494
|
+
type: 'LEFT',
|
|
495
|
+
// @ts-ignore
|
|
496
|
+
on,
|
|
497
|
+
originalEntity: relationShip.originalEntity,
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
else {
|
|
501
|
+
this.statements.selectJoin = this.statements.selectJoin || [];
|
|
502
|
+
this.statements.selectJoin.push({
|
|
503
|
+
statement: 'select',
|
|
504
|
+
columns: this.originalColumns.filter(column => column.startsWith(`${relationShip.propertyKey}`)).map(column => column.split('.')[1]) || [],
|
|
505
|
+
table: `"${joinSchema || 'public'}"."${joinTableName}"`,
|
|
506
|
+
alias: joinAlias,
|
|
507
|
+
where: joinWhere,
|
|
508
|
+
joinProperty: relationShip.propertyKey,
|
|
509
|
+
fkKey: this.getFkKey(relationShip),
|
|
510
|
+
primaryKey: originPrimaryKey,
|
|
511
|
+
originAlias: alias,
|
|
512
|
+
originProperty: relationShip.propertyKey,
|
|
513
|
+
joinEntity: relationShip.entity(),
|
|
514
|
+
originEntity: relationShip.originalEntity,
|
|
515
|
+
});
|
|
516
|
+
}
|
|
336
517
|
return joinWhere;
|
|
337
518
|
}
|
|
338
519
|
getFkKey(relationShip) {
|
|
@@ -360,14 +541,14 @@ class SqlBuilder {
|
|
|
360
541
|
}
|
|
361
542
|
this.entity = entity;
|
|
362
543
|
}
|
|
363
|
-
transformToModel(data) {
|
|
364
|
-
const instance = new
|
|
544
|
+
transformToModel(model, statement, data) {
|
|
545
|
+
const instance = new model();
|
|
365
546
|
instance.$_isPersisted = true;
|
|
366
547
|
const entitiesByAlias = {
|
|
367
|
-
[
|
|
548
|
+
[statement.alias]: instance,
|
|
368
549
|
};
|
|
369
550
|
const entitiesOptions = new Map();
|
|
370
|
-
entitiesOptions.set(
|
|
551
|
+
entitiesOptions.set(statement.alias, this.entityStorage.get(instance.constructor));
|
|
371
552
|
if (this.statements.join) {
|
|
372
553
|
this.statements.join.forEach(join => {
|
|
373
554
|
const joinInstance = new join.joinEntity();
|
|
@@ -384,7 +565,7 @@ class SqlBuilder {
|
|
|
384
565
|
}
|
|
385
566
|
const entityProperty = entitiesOptions.get(alias).showProperties[prop];
|
|
386
567
|
if (entityProperty) {
|
|
387
|
-
if (this.extendsFrom(
|
|
568
|
+
if (this.extendsFrom(ValueObject, entityProperty.type.prototype)) {
|
|
388
569
|
// @ts-ignore
|
|
389
570
|
entity[prop] = new entityProperty.type(value);
|
|
390
571
|
return;
|
|
@@ -431,7 +612,16 @@ class SqlBuilder {
|
|
|
431
612
|
if (!e) {
|
|
432
613
|
throw new Error('Entity not found');
|
|
433
614
|
}
|
|
434
|
-
|
|
615
|
+
const columns = Object.keys(e.showProperties).map(key => `${alias}."${key}" as "${alias}_${key}"`);
|
|
616
|
+
if (e.relations) {
|
|
617
|
+
for (const relation of e.relations) {
|
|
618
|
+
if (relation.relation === 'many-to-one') {
|
|
619
|
+
// @ts-ignore
|
|
620
|
+
columns.push(`${alias}."${relation.propertyKey}" as "${alias}_${relation.propertyKey}"`);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
return columns;
|
|
435
625
|
}
|
|
436
626
|
withDefaultValues(values, entityOptions) {
|
|
437
627
|
const property = Object.entries(entityOptions.showProperties).filter(([_, value]) => value.options.onInsert);
|
|
@@ -471,5 +661,33 @@ class SqlBuilder {
|
|
|
471
661
|
return false;
|
|
472
662
|
}
|
|
473
663
|
}
|
|
474
|
-
|
|
664
|
+
function processValuesForInsert(values) {
|
|
665
|
+
for (const value in values) {
|
|
666
|
+
if (extendsFrom(ValueObject, values[value].constructor.prototype)) {
|
|
667
|
+
values[value] = values[value].getValue();
|
|
668
|
+
continue;
|
|
669
|
+
}
|
|
670
|
+
if (values[value] instanceof BaseEntity) {
|
|
671
|
+
// @ts-ignore
|
|
672
|
+
values[value] = values[value].id; // TODO: get primary key
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
function processValuesForUpdate(values) {
|
|
677
|
+
for (const value in values) {
|
|
678
|
+
if (extendsFrom(ValueObject, values[value].constructor.prototype)) {
|
|
679
|
+
values[value] = values[value].getValue();
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
function extendsFrom(baseClass, instance) {
|
|
684
|
+
let proto = Object.getPrototypeOf(instance);
|
|
685
|
+
while (proto) {
|
|
686
|
+
if (proto === baseClass.prototype) {
|
|
687
|
+
return true;
|
|
688
|
+
}
|
|
689
|
+
proto = Object.getPrototypeOf(proto);
|
|
690
|
+
}
|
|
691
|
+
return false;
|
|
692
|
+
}
|
|
475
693
|
//# sourceMappingURL=SqlBuilder.js.map
|