@hed-hog/api-pagination 0.0.3 → 0.0.5
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/.eslintrc.js +9 -9
- package/.prettierrc.js +4 -4
- package/dist/databases/abstract.database.d.ts +7 -3
- package/dist/databases/abstract.database.d.ts.map +1 -1
- package/dist/databases/abstract.database.js +42 -1
- package/dist/databases/abstract.database.js.map +1 -1
- package/dist/pagination.service.d.ts +20 -1
- package/dist/pagination.service.d.ts.map +1 -1
- package/dist/pagination.service.js +171 -19
- package/dist/pagination.service.js.map +1 -1
- package/package.json +15 -6
- package/src/databases/abstract.database.ts +59 -1
- package/src/pagination.service.ts +284 -24
- package/tsconfig.json +1 -1
- package/tsconfig.production.tsbuildinfo +1 -1
- package/src/constants/pagination.constants.d.ts.map +0 -1
- package/src/constants/pagination.constants.js +0 -6
- package/src/constants/pagination.constants.js.map +0 -1
- package/src/databases/abstract.database.d.ts.map +0 -1
- package/src/databases/abstract.database.js +0 -655
- package/src/databases/abstract.database.js.map +0 -1
- package/src/databases/database.d.ts.map +0 -1
- package/src/databases/database.factory.d.ts.map +0 -1
- package/src/databases/database.factory.js +0 -20
- package/src/databases/database.factory.js.map +0 -1
- package/src/databases/database.js +0 -9
- package/src/databases/database.js.map +0 -1
- package/src/databases/index.d.ts.map +0 -1
- package/src/databases/index.js +0 -20
- package/src/databases/index.js.map +0 -1
- package/src/databases/mysql.database.d.ts.map +0 -1
- package/src/databases/mysql.database.js +0 -22
- package/src/databases/mysql.database.js.map +0 -1
- package/src/databases/postgres.database.d.ts.map +0 -1
- package/src/databases/postgres.database.js +0 -22
- package/src/databases/postgres.database.js.map +0 -1
- package/src/decorator/pagination.decorator.d.ts.map +0 -1
- package/src/decorator/pagination.decorator.js +0 -58
- package/src/decorator/pagination.decorator.js.map +0 -1
- package/src/dto/pagination.dto.d.ts.map +0 -1
- package/src/dto/pagination.dto.js +0 -58
- package/src/dto/pagination.dto.js.map +0 -1
- package/src/enums/patination.enums.d.ts.map +0 -1
- package/src/enums/patination.enums.js +0 -17
- package/src/enums/patination.enums.js.map +0 -1
- package/src/index.d.ts.map +0 -1
- package/src/index.js +0 -23
- package/src/index.js.map +0 -1
- package/src/pagination.module.d.ts.map +0 -1
- package/src/pagination.module.js +0 -22
- package/src/pagination.module.js.map +0 -1
- package/src/pagination.service.d.ts.map +0 -1
- package/src/pagination.service.js +0 -252
- package/src/pagination.service.js.map +0 -1
- package/src/types/pagination.types.d.ts.map +0 -1
- package/src/types/pagination.types.js +0 -3
- package/src/types/pagination.types.js.map +0 -1
- package/src/types/query-option.d.ts.map +0 -1
- package/src/types/query-option.js +0 -3
- package/src/types/query-option.js.map +0 -1
- package/src/types/relation-n2n-result.d.ts.map +0 -1
- package/src/types/relation-n2n-result.js +0 -3
- package/src/types/relation-n2n-result.js.map +0 -1
- package/src/types/transaction-queries.d.ts.map +0 -1
- package/src/types/transaction-queries.js +0 -3
- package/src/types/transaction-queries.js.map +0 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Connection } from 'mysql2/promise';
|
|
2
2
|
import { Client } from 'pg';
|
|
3
3
|
import { DataSource } from 'typeorm';
|
|
4
|
+
import { EventEmitter } from 'typeorm/platform/PlatformTools';
|
|
4
5
|
import { QueryOption } from '../types/query-option';
|
|
5
6
|
import { RelationN2NResult } from '../types/relation-n2n-result';
|
|
6
7
|
import { TransactionQueries } from '../types/transaction-queries';
|
|
7
8
|
import { Database } from './database';
|
|
8
|
-
import { EventEmitter } from 'typeorm/platform/PlatformTools';
|
|
9
9
|
|
|
10
10
|
export class AbstractDatabase {
|
|
11
11
|
private client: Client | Connection | null = null;
|
|
@@ -827,4 +827,62 @@ export class AbstractDatabase {
|
|
|
827
827
|
|
|
828
828
|
return result;
|
|
829
829
|
}
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* Executa uma raw query e retorna os resultados
|
|
833
|
+
* Usado para queries parametrizadas com $1, $2, etc.
|
|
834
|
+
*/
|
|
835
|
+
async queryRaw(query: string, values?: any[]): Promise<any[]> {
|
|
836
|
+
if (!this.client) {
|
|
837
|
+
await this.getClient();
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
try {
|
|
841
|
+
let result;
|
|
842
|
+
|
|
843
|
+
switch (this.type) {
|
|
844
|
+
case Database.POSTGRES:
|
|
845
|
+
const pgResult = await (this.client as Client).query(query, values);
|
|
846
|
+
result = pgResult.rows;
|
|
847
|
+
break;
|
|
848
|
+
|
|
849
|
+
case Database.MYSQL:
|
|
850
|
+
// Para MySQL, converter $1, $2 para ?
|
|
851
|
+
const mysqlQuery = query.replace(/\$\d+/g, '?');
|
|
852
|
+
const [rows] = await (this.client as Connection).query(mysqlQuery, values);
|
|
853
|
+
result = rows;
|
|
854
|
+
break;
|
|
855
|
+
|
|
856
|
+
default:
|
|
857
|
+
throw new Error(`Unsupported database type: ${this.type}`);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
if (this.autoClose) {
|
|
861
|
+
await this.client?.end();
|
|
862
|
+
this.client = null;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
return result;
|
|
866
|
+
} catch (error) {
|
|
867
|
+
console.error({
|
|
868
|
+
error,
|
|
869
|
+
query,
|
|
870
|
+
values,
|
|
871
|
+
});
|
|
872
|
+
|
|
873
|
+
if (this.autoClose && this.client) {
|
|
874
|
+
await this.client.end();
|
|
875
|
+
this.client = null;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
throw error;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
/**
|
|
883
|
+
* Escapa um identificador (nome de tabela ou coluna)
|
|
884
|
+
*/
|
|
885
|
+
escapeIdentifier(identifier: string): string {
|
|
886
|
+
return this.getColumnNameWithScaping(identifier).replace(/['"]/g, '');
|
|
887
|
+
}
|
|
830
888
|
}
|
|
@@ -10,14 +10,83 @@ import type { FindManyArgs, PaginationParams } from './types/pagination.types';
|
|
|
10
10
|
|
|
11
11
|
@Injectable()
|
|
12
12
|
export class PaginationService {
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
private readonly logger = new Logger(PaginationService.name);
|
|
14
15
|
private db: any = null;
|
|
16
|
+
|
|
17
|
+
async paginatePrismaModel(model: any, options: {
|
|
18
|
+
page?: number;
|
|
19
|
+
pageSize?: number;
|
|
20
|
+
search?: string;
|
|
21
|
+
sortField?: string;
|
|
22
|
+
sortOrder?: 'asc' | 'desc';
|
|
23
|
+
validSortFields?: string[];
|
|
24
|
+
searchFields?: string[];
|
|
25
|
+
where?: any;
|
|
26
|
+
include?: any;
|
|
27
|
+
}) {
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
|
|
31
|
+
const {
|
|
32
|
+
page = 1,
|
|
33
|
+
pageSize = 10,
|
|
34
|
+
search,
|
|
35
|
+
sortField = 'id',
|
|
36
|
+
sortOrder = 'desc',
|
|
37
|
+
validSortFields = ['id'],
|
|
38
|
+
searchFields = [],
|
|
39
|
+
where: customWhere,
|
|
40
|
+
include,
|
|
41
|
+
} = options;
|
|
42
|
+
|
|
43
|
+
const currentPage = Math.max(Number(page) || 1, 1);
|
|
44
|
+
const limit = Math.max(Number(pageSize) || 10, 1);
|
|
45
|
+
const skip = (currentPage - 1) * limit;
|
|
46
|
+
|
|
47
|
+
let where = customWhere || {};
|
|
48
|
+
if (search && searchFields.length > 0) {
|
|
49
|
+
where = {
|
|
50
|
+
...where,
|
|
51
|
+
OR: searchFields.map((field) => ({
|
|
52
|
+
[field]: { contains: search, mode: 'insensitive' },
|
|
53
|
+
})),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const orderBy =
|
|
58
|
+
sortField && typeof sortField === 'string' && validSortFields.includes(sortField)
|
|
59
|
+
? { [sortField]: sortOrder === 'asc' ? 'asc' : 'desc' }
|
|
60
|
+
: { id: 'desc' };
|
|
61
|
+
|
|
62
|
+
const [data, total] = await Promise.all([
|
|
63
|
+
model.findMany({ skip, take: limit, where, orderBy, include }),
|
|
64
|
+
model.count({ where }),
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
const lastPage = Math.max(1, Math.ceil(total / limit));
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
total,
|
|
71
|
+
lastPage,
|
|
72
|
+
page: currentPage,
|
|
73
|
+
pageSize: limit,
|
|
74
|
+
data,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
} catch (error) {
|
|
78
|
+
this.logger.error('Pagination Error:', error);
|
|
79
|
+
throw new BadRequestException(`Failed to paginate: ${error}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
15
83
|
async paginate<T, M extends any>(
|
|
16
84
|
model: M,
|
|
17
85
|
paginationParams: PaginationParams,
|
|
18
86
|
customQuery?: FindManyArgs<M>,
|
|
19
87
|
translationKey?: string,
|
|
20
88
|
) /*: Promise<PaginatedResult<T>>*/ {
|
|
89
|
+
|
|
21
90
|
try {
|
|
22
91
|
if (!model) {
|
|
23
92
|
throw new BadRequestException('Model is required');
|
|
@@ -42,13 +111,22 @@ export class PaginationService {
|
|
|
42
111
|
let sortOrderCondition: any = {
|
|
43
112
|
id: paginationParams.sortOrder || PageOrderDirection.Asc,
|
|
44
113
|
};
|
|
114
|
+
let needsRawQueryOrdering = false;
|
|
115
|
+
let localeTableName = '';
|
|
116
|
+
let localeSortField = '';
|
|
117
|
+
|
|
118
|
+
this.logger.debug(`Sort field: ${sortField}`);
|
|
45
119
|
|
|
46
120
|
if (sortField) {
|
|
47
121
|
const invalid = this.isInvalidField(sortField, model);
|
|
48
122
|
let localeInvalid = false;
|
|
123
|
+
|
|
124
|
+
this.logger.debug(`Field ${sortField} is invalid in main model: ${invalid}`);
|
|
125
|
+
|
|
49
126
|
if (invalid) {
|
|
50
127
|
localeInvalid = this.isInvalidLocaleField(sortField, model);
|
|
51
|
-
|
|
128
|
+
this.logger.debug(`Field ${sortField} is invalid in locale model: ${localeInvalid}`);
|
|
129
|
+
|
|
52
130
|
if (localeInvalid) {
|
|
53
131
|
this.logger.error(`Invalid field: ${sortField}`);
|
|
54
132
|
throw new BadRequestException(
|
|
@@ -57,9 +135,11 @@ export class PaginationService {
|
|
|
57
135
|
).join(', ')}`,
|
|
58
136
|
);
|
|
59
137
|
} else {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
138
|
+
// Campo existe na tabela locale - precisa usar raw query
|
|
139
|
+
localeTableName = `${(model as any).name}_locale`;
|
|
140
|
+
localeSortField = sortField;
|
|
141
|
+
needsRawQueryOrdering = true;
|
|
142
|
+
this.logger.debug(`Will use raw query ordering for ${localeTableName}.${localeSortField}`);
|
|
63
143
|
}
|
|
64
144
|
} else {
|
|
65
145
|
sortOrderCondition = { [sortField]: sortOrder };
|
|
@@ -106,28 +186,46 @@ export class PaginationService {
|
|
|
106
186
|
delete (customQuery as any).where.OR;
|
|
107
187
|
}
|
|
108
188
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
where: (customQuery as any)?.where || {}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
189
|
+
// Contar total sempre com Prisma normal
|
|
190
|
+
const total = await (model as any).count({
|
|
191
|
+
where: (customQuery as any)?.where || {}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
let data: any[];
|
|
195
|
+
|
|
196
|
+
if (needsRawQueryOrdering) {
|
|
197
|
+
// Usar raw query para ordenação por campo de tabela relacionada
|
|
198
|
+
data = await this.paginateWithLocaleOrdering(
|
|
199
|
+
model,
|
|
200
|
+
localeTableName,
|
|
201
|
+
localeSortField,
|
|
202
|
+
sortOrder,
|
|
203
|
+
skip,
|
|
204
|
+
pageSize,
|
|
205
|
+
customQuery,
|
|
206
|
+
);
|
|
207
|
+
} else {
|
|
208
|
+
// Usar Prisma normal
|
|
209
|
+
const query: any = {
|
|
210
|
+
select: selectCondition,
|
|
211
|
+
where: (customQuery as any)?.where || {},
|
|
212
|
+
orderBy: sortOrderCondition,
|
|
213
|
+
take: pageSize,
|
|
214
|
+
skip,
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
if ((customQuery as any)?.include) {
|
|
218
|
+
query.include = (customQuery as any)?.include;
|
|
219
|
+
delete query.select;
|
|
220
|
+
}
|
|
116
221
|
|
|
117
|
-
|
|
118
|
-
query.include = (customQuery as any)?.include;
|
|
119
|
-
delete query.select;
|
|
222
|
+
data = await (model as any).findMany(query);
|
|
120
223
|
}
|
|
121
224
|
|
|
122
|
-
let [total, data] = await Promise.all([
|
|
123
|
-
(model as any).count({ where: (customQuery as any)?.where || {} }),
|
|
124
|
-
(model as any).findMany(query),
|
|
125
|
-
//this.query(model, query),
|
|
126
|
-
]);
|
|
127
|
-
|
|
128
225
|
const lastPage = Math.ceil(total / pageSize);
|
|
129
226
|
|
|
130
|
-
if (translationKey) {
|
|
227
|
+
if (translationKey !== undefined && translationKey !== null) {
|
|
228
|
+
this.logger.debug(`Applying translations with key: ${translationKey}`);
|
|
131
229
|
data = data.map((item: any) => {
|
|
132
230
|
return itemTranslations(translationKey, item);
|
|
133
231
|
});
|
|
@@ -142,15 +240,177 @@ export class PaginationService {
|
|
|
142
240
|
next: page < lastPage ? page + 1 : null,
|
|
143
241
|
data,
|
|
144
242
|
};
|
|
145
|
-
} catch (error) {
|
|
243
|
+
} catch (error: any) {
|
|
146
244
|
this.logger.error('Pagination Error:', error);
|
|
147
245
|
|
|
148
246
|
if (error instanceof BadRequestException) {
|
|
149
247
|
throw error;
|
|
150
248
|
}
|
|
151
249
|
|
|
152
|
-
throw new BadRequestException(`Failed to paginate: ${error}`);
|
|
250
|
+
throw new BadRequestException(`Failed to paginate: ${error.message || error}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Método auxiliar para paginação com ordenação por campos de tabela locale
|
|
256
|
+
* Usa raw query para ordenação, mas mantém estrutura aninhada do Prisma
|
|
257
|
+
*/
|
|
258
|
+
private async paginateWithLocaleOrdering(
|
|
259
|
+
model: any,
|
|
260
|
+
localeTableName: string,
|
|
261
|
+
sortField: string,
|
|
262
|
+
sortOrder: string,
|
|
263
|
+
skip: number,
|
|
264
|
+
take: number,
|
|
265
|
+
customQuery?: any,
|
|
266
|
+
): Promise<any[]> {
|
|
267
|
+
try {
|
|
268
|
+
const tableName = (model as any).name;
|
|
269
|
+
const db = await this.getDb(model);
|
|
270
|
+
|
|
271
|
+
// Detectar locale code do include (se disponível)
|
|
272
|
+
let localeCode = 'en'; // fallback
|
|
273
|
+
if (customQuery?.include?.[localeTableName]?.where?.locale?.code) {
|
|
274
|
+
localeCode = customQuery.include[localeTableName].where.locale.code;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
this.logger.debug(`Building raw query for ${tableName} ordered by ${localeTableName}.${sortField}`);
|
|
278
|
+
|
|
279
|
+
// Construir WHERE clause da raw query
|
|
280
|
+
const whereConditions: string[] = [];
|
|
281
|
+
let whereParams: any[] = [];
|
|
282
|
+
let paramIndex = 1;
|
|
283
|
+
|
|
284
|
+
if (customQuery?.where) {
|
|
285
|
+
const { conditions, params, nextIndex } = this.buildWhereClause(
|
|
286
|
+
customQuery.where,
|
|
287
|
+
tableName,
|
|
288
|
+
db,
|
|
289
|
+
paramIndex,
|
|
290
|
+
);
|
|
291
|
+
whereConditions.push(...conditions);
|
|
292
|
+
whereParams.push(...params);
|
|
293
|
+
paramIndex = nextIndex;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Adicionar filtro de locale
|
|
297
|
+
whereConditions.push(`l.code = $${paramIndex}`);
|
|
298
|
+
whereParams.push(localeCode);
|
|
299
|
+
paramIndex++;
|
|
300
|
+
|
|
301
|
+
const whereClause = whereConditions.length > 0
|
|
302
|
+
? `WHERE ${whereConditions.join(' AND ')}`
|
|
303
|
+
: '';
|
|
304
|
+
|
|
305
|
+
// Query para buscar IDs ordenados
|
|
306
|
+
const orderDirection = sortOrder.toUpperCase() === 'DESC' ? 'DESC' : 'ASC';
|
|
307
|
+
const orderByClause = `ORDER BY tl.${db.escapeIdentifier(sortField)} ${orderDirection}`;
|
|
308
|
+
|
|
309
|
+
const rawQuery = `
|
|
310
|
+
SELECT DISTINCT t.id
|
|
311
|
+
FROM ${db.escapeIdentifier(tableName)} t
|
|
312
|
+
LEFT JOIN ${db.escapeIdentifier(localeTableName)} tl ON t.id = tl.${tableName}_id
|
|
313
|
+
LEFT JOIN locale l ON tl.locale_id = l.id
|
|
314
|
+
${whereClause}
|
|
315
|
+
${orderByClause}
|
|
316
|
+
LIMIT $${paramIndex} OFFSET $${paramIndex + 1}
|
|
317
|
+
`;
|
|
318
|
+
|
|
319
|
+
whereParams.push(take, skip);
|
|
320
|
+
|
|
321
|
+
this.logger.debug(`Raw query: ${rawQuery}`);
|
|
322
|
+
this.logger.debug(`Params: ${JSON.stringify(whereParams)}`);
|
|
323
|
+
|
|
324
|
+
// Executar raw query para obter IDs ordenados
|
|
325
|
+
const orderedIds = await db.queryRaw(rawQuery, whereParams);
|
|
326
|
+
|
|
327
|
+
if (!orderedIds || orderedIds.length === 0) {
|
|
328
|
+
return [];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const ids = orderedIds.map((row: any) => row.id);
|
|
332
|
+
|
|
333
|
+
this.logger.debug(`Ordered IDs: ${ids.join(', ')}`);
|
|
334
|
+
|
|
335
|
+
// Buscar dados completos com Prisma mantendo estrutura aninhada
|
|
336
|
+
const query: any = {
|
|
337
|
+
where: {
|
|
338
|
+
id: { in: ids },
|
|
339
|
+
...(customQuery?.where || {}),
|
|
340
|
+
},
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
if (customQuery?.include) {
|
|
344
|
+
query.include = customQuery.include;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (customQuery?.select) {
|
|
348
|
+
query.select = customQuery.select;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const data = await model.findMany(query);
|
|
352
|
+
|
|
353
|
+
// Reordenar dados para manter a ordem da raw query
|
|
354
|
+
const orderedData = ids
|
|
355
|
+
.map(id => data.find((item: any) => item.id === id))
|
|
356
|
+
.filter(Boolean);
|
|
357
|
+
|
|
358
|
+
this.logger.debug(`Returning ${orderedData.length} ordered records`);
|
|
359
|
+
|
|
360
|
+
return orderedData;
|
|
361
|
+
|
|
362
|
+
} catch (error: any) {
|
|
363
|
+
this.logger.error(`Error in paginateWithLocaleOrdering: ${error.message}`, error.stack);
|
|
364
|
+
throw new BadRequestException(
|
|
365
|
+
`Failed to paginate with locale ordering: ${error.message}`
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Constrói cláusula WHERE para raw queries
|
|
372
|
+
*/
|
|
373
|
+
private buildWhereClause(
|
|
374
|
+
where: any,
|
|
375
|
+
tableName: string,
|
|
376
|
+
db: any,
|
|
377
|
+
startIndex: number = 1,
|
|
378
|
+
): { conditions: string[]; params: any[]; nextIndex: number } {
|
|
379
|
+
const conditions: string[] = [];
|
|
380
|
+
const params: any[] = [];
|
|
381
|
+
let paramIndex = startIndex;
|
|
382
|
+
|
|
383
|
+
for (const key in where) {
|
|
384
|
+
if (key === 'OR' || key === 'AND') {
|
|
385
|
+
continue; // Simplificação: ignorar OR/AND por enquanto
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const value = where[key];
|
|
389
|
+
|
|
390
|
+
if (typeof value === 'object' && value !== null) {
|
|
391
|
+
// Operadores especiais do Prisma
|
|
392
|
+
if ('in' in value) {
|
|
393
|
+
const placeholders = value.in.map(() => `$${paramIndex++}`).join(', ');
|
|
394
|
+
conditions.push(`t.${db.escapeIdentifier(key)} IN (${placeholders})`);
|
|
395
|
+
params.push(...value.in);
|
|
396
|
+
} else if ('contains' in value) {
|
|
397
|
+
conditions.push(`t.${db.escapeIdentifier(key)} ILIKE $${paramIndex}`);
|
|
398
|
+
params.push(`%${value.contains}%`);
|
|
399
|
+
paramIndex++;
|
|
400
|
+
} else if ('equals' in value) {
|
|
401
|
+
conditions.push(`t.${db.escapeIdentifier(key)} = $${paramIndex}`);
|
|
402
|
+
params.push(value.equals);
|
|
403
|
+
paramIndex++;
|
|
404
|
+
}
|
|
405
|
+
} else {
|
|
406
|
+
// Valor simples
|
|
407
|
+
conditions.push(`t.${db.escapeIdentifier(key)} = $${paramIndex}`);
|
|
408
|
+
params.push(value);
|
|
409
|
+
paramIndex++;
|
|
410
|
+
}
|
|
153
411
|
}
|
|
412
|
+
|
|
413
|
+
return { conditions, params, nextIndex: paramIndex };
|
|
154
414
|
}
|
|
155
415
|
|
|
156
416
|
extractFieldNames(model: Record<string, any>): string[] {
|
package/tsconfig.json
CHANGED