bigal 15.3.0 → 15.5.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/CHANGELOG.md +12 -0
- package/README.md +149 -20
- package/dist/index.cjs +83 -10
- package/dist/index.d.cts +79 -1
- package/dist/index.d.mts +79 -1
- package/dist/index.d.ts +79 -1
- package/dist/index.mjs +83 -10
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# [15.5.0](https://github.com/bigalorm/bigal/compare/v15.4.0...v15.5.0) (2026-01-13)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
- Add toJSON() method for returning plain objects instead of class instances ([#271](https://github.com/bigalorm/bigal/issues/271)) ([3e2ee5d](https://github.com/bigalorm/bigal/commit/3e2ee5d803d705bc54bc8b08044f5848088563bb))
|
|
6
|
+
|
|
7
|
+
# [15.4.0](https://github.com/bigalorm/bigal/compare/v15.3.0...v15.4.0) (2026-01-08)
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
- Add withCount() for efficient pagination with total count ([#266](https://github.com/bigalorm/bigal/issues/266)) ([233221e](https://github.com/bigalorm/bigal/commit/233221e7902af8ca3a4b24d1f60f0857bcd7803f))
|
|
12
|
+
|
|
1
13
|
# [15.3.0](https://github.com/bigalorm/bigal/compare/v15.2.0...v15.3.0) (2026-01-08)
|
|
2
14
|
|
|
3
15
|
### Features
|
package/README.md
CHANGED
|
@@ -183,8 +183,8 @@ export function startup({
|
|
|
183
183
|
});
|
|
184
184
|
|
|
185
185
|
let categoryRepository: Repository<Category>;
|
|
186
|
-
let productRepository: Repository<
|
|
187
|
-
let storeRepository: Repository<
|
|
186
|
+
let productRepository: Repository<Product>;
|
|
187
|
+
let storeRepository: Repository<Store>;
|
|
188
188
|
for (const [modelName, repository] = Object.entries(repositoriesByName)) {
|
|
189
189
|
switch (modelName) {
|
|
190
190
|
case 'Category':
|
|
@@ -325,14 +325,109 @@ const item = await ProductRepository.find({
|
|
|
325
325
|
});
|
|
326
326
|
```
|
|
327
327
|
|
|
328
|
-
####
|
|
328
|
+
#### String matching operators
|
|
329
|
+
|
|
330
|
+
BigAl provides four string matching operators. All use case-insensitive matching (PostgreSQL `ILIKE`) and accept arrays for OR matching.
|
|
331
|
+
|
|
332
|
+
| Operator | Description | SQL Pattern |
|
|
333
|
+
| ------------ | --------------------------------------------- | ----------- |
|
|
334
|
+
| `like` | Raw ILIKE pattern with your own `%` wildcards | As provided |
|
|
335
|
+
| `contains` | Substring match anywhere in the string | `%value%` |
|
|
336
|
+
| `startsWith` | Matches strings starting with the value | `value%` |
|
|
337
|
+
| `endsWith` | Matches strings ending with the value | `%value` |
|
|
329
338
|
|
|
330
339
|
```ts
|
|
340
|
+
const items = await ProductRepository.find().where({
|
|
341
|
+
name: { contains: 'widget' },
|
|
342
|
+
});
|
|
343
|
+
// SQL: SELECT ... FROM product WHERE name ILIKE '%widget%'
|
|
344
|
+
|
|
345
|
+
const items = await ProductRepository.find().where({
|
|
346
|
+
name: { startsWith: 'Pro' },
|
|
347
|
+
});
|
|
348
|
+
// SQL: SELECT ... FROM product WHERE name ILIKE 'Pro%'
|
|
349
|
+
|
|
350
|
+
const items = await ProductRepository.find().where({
|
|
351
|
+
name: { endsWith: 'ter' },
|
|
352
|
+
});
|
|
353
|
+
// SQL: SELECT ... FROM product WHERE name ILIKE '%ter'
|
|
354
|
+
|
|
355
|
+
const items = await ProductRepository.find().where({
|
|
356
|
+
name: { like: 'Pro%Widget%' },
|
|
357
|
+
});
|
|
358
|
+
// SQL: SELECT ... FROM product WHERE name ILIKE 'Pro%Widget%'
|
|
359
|
+
|
|
360
|
+
// Arrays create OR conditions
|
|
331
361
|
const items = await PersonRepository.find().where({
|
|
332
|
-
firstName: {
|
|
333
|
-
|
|
334
|
-
|
|
362
|
+
firstName: { like: ['walter', 'Jess%'] },
|
|
363
|
+
});
|
|
364
|
+
// SQL: SELECT ... FROM person WHERE (first_name ILIKE 'walter' OR first_name ILIKE 'Jess%')
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
#### Comparison operators
|
|
368
|
+
|
|
369
|
+
For number and date fields, use comparison operators:
|
|
370
|
+
|
|
371
|
+
| Operator | Description |
|
|
372
|
+
| -------- | ------------------------ |
|
|
373
|
+
| `<` | Less than |
|
|
374
|
+
| `<=` | Less than or equal to |
|
|
375
|
+
| `>` | Greater than |
|
|
376
|
+
| `>=` | Greater than or equal to |
|
|
377
|
+
|
|
378
|
+
```ts
|
|
379
|
+
const items = await ProductRepository.find().where({
|
|
380
|
+
price: { '>=': 100 },
|
|
381
|
+
});
|
|
382
|
+
// SQL: SELECT ... FROM product WHERE price >= $1
|
|
383
|
+
|
|
384
|
+
// Multiple operators on same field create AND
|
|
385
|
+
const items = await ProductRepository.find().where({
|
|
386
|
+
createdAt: { '>=': startDate, '<': endDate },
|
|
387
|
+
});
|
|
388
|
+
// SQL: SELECT ... FROM product WHERE created_at >= $1 AND created_at < $2
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
#### Array values (OR conditions)
|
|
392
|
+
|
|
393
|
+
When you pass an array of values, BigAl creates an OR condition:
|
|
394
|
+
|
|
395
|
+
```ts
|
|
396
|
+
const items = await PersonRepository.find().where({
|
|
397
|
+
age: [22, 23, 24],
|
|
398
|
+
});
|
|
399
|
+
// SQL: SELECT ... FROM person WHERE age IN ($1, $2, $3)
|
|
400
|
+
|
|
401
|
+
const items = await ProductRepository.find().where({
|
|
402
|
+
name: { startsWith: ['Pro', 'Pre'] },
|
|
403
|
+
});
|
|
404
|
+
// SQL: SELECT ... FROM product WHERE (name ILIKE 'Pro%' OR name ILIKE 'Pre%')
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
#### Negation operator (`!`)
|
|
408
|
+
|
|
409
|
+
Use `!` to negate any condition:
|
|
410
|
+
|
|
411
|
+
```ts
|
|
412
|
+
const items = await ProductRepository.find().where({
|
|
413
|
+
status: { '!': 'discontinued' },
|
|
414
|
+
});
|
|
415
|
+
// SQL: SELECT ... FROM product WHERE status <> $1
|
|
416
|
+
|
|
417
|
+
const items = await ProductRepository.find().where({
|
|
418
|
+
status: { '!': ['discontinued', 'archived'] },
|
|
419
|
+
});
|
|
420
|
+
// SQL: SELECT ... FROM product WHERE status NOT IN ($1, $2)
|
|
421
|
+
|
|
422
|
+
const items = await ProductRepository.find().where({
|
|
423
|
+
name: { '!': { startsWith: 'Test' } },
|
|
335
424
|
});
|
|
425
|
+
// SQL: SELECT ... FROM product WHERE name NOT ILIKE 'Test%'
|
|
426
|
+
|
|
427
|
+
const items = await ProductRepository.find().where({
|
|
428
|
+
deletedAt: { '!': null },
|
|
429
|
+
});
|
|
430
|
+
// SQL: SELECT ... FROM product WHERE deleted_at IS NOT NULL
|
|
336
431
|
```
|
|
337
432
|
|
|
338
433
|
#### Example of an AND statement
|
|
@@ -392,22 +487,28 @@ Equivalent to:
|
|
|
392
487
|
select * from person where ((first_name = $1) OR (last_name = $2)) AND ((first_name = $3) OR (last_name = $4))
|
|
393
488
|
```
|
|
394
489
|
|
|
395
|
-
####
|
|
490
|
+
#### Sorting results
|
|
491
|
+
|
|
492
|
+
Use `.sort()` to order results. Two syntax options are available:
|
|
493
|
+
|
|
494
|
+
**String syntax** - Use `asc` or `desc` (comma-separated for multiple columns):
|
|
396
495
|
|
|
397
496
|
```ts
|
|
398
|
-
const items = await PersonRepository.find()
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
497
|
+
const items = await PersonRepository.find().where({ lastName: 'Smith' }).sort('age asc');
|
|
498
|
+
// SQL: SELECT ... FROM person WHERE last_name = $1 ORDER BY age ASC
|
|
499
|
+
|
|
500
|
+
const items = await PersonRepository.find().where({ lastName: 'Smith' }).sort('age asc, createdAt desc');
|
|
501
|
+
// SQL: SELECT ... FROM person WHERE last_name = $1 ORDER BY age ASC, created_at DESC
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
**Object syntax** - Use `1` for ascending, `-1` for descending:
|
|
505
|
+
|
|
506
|
+
```ts
|
|
507
|
+
const items = await PersonRepository.find().where({ lastName: 'Smith' }).sort({ age: 1 });
|
|
508
|
+
// SQL: SELECT ... FROM person WHERE last_name = $1 ORDER BY age ASC
|
|
509
|
+
|
|
510
|
+
const items = await PersonRepository.find().where({ lastName: 'Smith' }).sort({ age: 1, createdAt: -1 });
|
|
511
|
+
// SQL: SELECT ... FROM person WHERE last_name = $1 ORDER BY age ASC, created_at DESC
|
|
411
512
|
```
|
|
412
513
|
|
|
413
514
|
#### Limit number results returned
|
|
@@ -460,6 +561,34 @@ const items = await FooRepository.find()
|
|
|
460
561
|
.paginate(page, pageSize);
|
|
461
562
|
```
|
|
462
563
|
|
|
564
|
+
#### Page results with total count using `withCount`
|
|
565
|
+
|
|
566
|
+
Use `.withCount()` to get both paginated results and the total count of matching records in a single query. This uses PostgreSQL's `COUNT(*) OVER()` window function for efficient execution.
|
|
567
|
+
|
|
568
|
+
```ts
|
|
569
|
+
const { results, totalCount } = await ProductRepository.find()
|
|
570
|
+
.where({
|
|
571
|
+
store: storeId,
|
|
572
|
+
})
|
|
573
|
+
.sort('name')
|
|
574
|
+
.limit(10)
|
|
575
|
+
.skip(20)
|
|
576
|
+
.withCount();
|
|
577
|
+
|
|
578
|
+
// results: Product[] (10 items from offset 20)
|
|
579
|
+
// totalCount: number (total matching products, ignoring LIMIT/OFFSET)
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
This is useful for building paginated UIs where you need to display total pages:
|
|
583
|
+
|
|
584
|
+
```ts
|
|
585
|
+
const page = 3;
|
|
586
|
+
const pageSize = 25;
|
|
587
|
+
const { results, totalCount } = await ProductRepository.find().where({ isActive: true }).paginate({ page, limit: pageSize }).withCount();
|
|
588
|
+
|
|
589
|
+
const totalPages = Math.ceil(totalCount / pageSize);
|
|
590
|
+
```
|
|
591
|
+
|
|
463
592
|
#### Join related tables
|
|
464
593
|
|
|
465
594
|
Use `join()` for INNER JOIN or `leftJoin()` for LEFT JOIN to filter or sort by related table columns in a single query.
|
package/dist/index.cjs
CHANGED
|
@@ -445,13 +445,17 @@ function getSelectQueryAndParams({
|
|
|
445
445
|
sorts,
|
|
446
446
|
skip,
|
|
447
447
|
limit,
|
|
448
|
-
joins
|
|
448
|
+
joins,
|
|
449
|
+
includeCount
|
|
449
450
|
}) {
|
|
450
451
|
let query = "SELECT ";
|
|
451
452
|
query += getColumnsToSelect({
|
|
452
453
|
model,
|
|
453
454
|
select
|
|
454
455
|
});
|
|
456
|
+
if (includeCount) {
|
|
457
|
+
query += ',count(*) OVER() AS "__total_count__"';
|
|
458
|
+
}
|
|
455
459
|
query += ` FROM ${model.qualifiedTableName}`;
|
|
456
460
|
const params = [];
|
|
457
461
|
if (joins?.length) {
|
|
@@ -901,7 +905,7 @@ function buildJoinClauses({
|
|
|
901
905
|
if (alias !== relatedModel.tableName) {
|
|
902
906
|
joinSql += ` AS "${alias}"`;
|
|
903
907
|
}
|
|
904
|
-
joinSql += ` ON ${model.qualifiedTableName}."${column.name}"
|
|
908
|
+
joinSql += ` ON ${model.qualifiedTableName}."${column.name}"="${alias}"."${relatedPrimaryKey.name}"`;
|
|
905
909
|
if (join.on) {
|
|
906
910
|
for (const [propertyName, value] of Object.entries(join.on)) {
|
|
907
911
|
const onColumn = relatedModel.columnsByPropertyName[propertyName];
|
|
@@ -1957,6 +1961,7 @@ class ReadonlyRepository {
|
|
|
1957
1961
|
const manuallySetFields = [];
|
|
1958
1962
|
const sorts = sort ? this._convertSortsToOrderBy(sort) : [];
|
|
1959
1963
|
const joins = [];
|
|
1964
|
+
let returnAsPlainObjects = false;
|
|
1960
1965
|
const modelInstance = this;
|
|
1961
1966
|
return {
|
|
1962
1967
|
/**
|
|
@@ -2046,6 +2051,10 @@ class ReadonlyRepository {
|
|
|
2046
2051
|
});
|
|
2047
2052
|
return this;
|
|
2048
2053
|
},
|
|
2054
|
+
toJSON() {
|
|
2055
|
+
returnAsPlainObjects = true;
|
|
2056
|
+
return this;
|
|
2057
|
+
},
|
|
2049
2058
|
async then(resolve, reject) {
|
|
2050
2059
|
try {
|
|
2051
2060
|
if (typeof where === "string") {
|
|
@@ -2065,9 +2074,10 @@ class ReadonlyRepository {
|
|
|
2065
2074
|
const results = await pool.query(query, params);
|
|
2066
2075
|
const firstResult = results.rows[0];
|
|
2067
2076
|
if (firstResult) {
|
|
2068
|
-
const result = modelInstance._buildInstance(firstResult);
|
|
2077
|
+
const result = returnAsPlainObjects ? modelInstance._buildPlainObject(firstResult) : modelInstance._buildInstance(firstResult);
|
|
2069
2078
|
if (populates.length) {
|
|
2070
|
-
|
|
2079
|
+
const populatesWithFlag = populates.map((pop) => ({ ...pop, asPlainObjects: returnAsPlainObjects }));
|
|
2080
|
+
await modelInstance.populateFields([result], populatesWithFlag);
|
|
2071
2081
|
}
|
|
2072
2082
|
for (const manuallySetField of manuallySetFields) {
|
|
2073
2083
|
result[manuallySetField.propertyName] = manuallySetField.value;
|
|
@@ -2145,6 +2155,8 @@ ${stack ?? ""}`;
|
|
|
2145
2155
|
const populates = [];
|
|
2146
2156
|
const sorts = sort ? this._convertSortsToOrderBy(sort) : [];
|
|
2147
2157
|
const joins = [];
|
|
2158
|
+
let includeCount = false;
|
|
2159
|
+
let returnAsPlainObjects = false;
|
|
2148
2160
|
const modelInstance = this;
|
|
2149
2161
|
return {
|
|
2150
2162
|
/**
|
|
@@ -2255,6 +2267,14 @@ ${stack ?? ""}`;
|
|
|
2255
2267
|
const safePage = Math.max(page, 1);
|
|
2256
2268
|
return this.skip(safePage * paginateLimit - paginateLimit).limit(paginateLimit);
|
|
2257
2269
|
},
|
|
2270
|
+
withCount() {
|
|
2271
|
+
includeCount = true;
|
|
2272
|
+
return this;
|
|
2273
|
+
},
|
|
2274
|
+
toJSON() {
|
|
2275
|
+
returnAsPlainObjects = true;
|
|
2276
|
+
return this;
|
|
2277
|
+
},
|
|
2258
2278
|
async then(resolve, reject) {
|
|
2259
2279
|
try {
|
|
2260
2280
|
if (typeof where === "string") {
|
|
@@ -2268,13 +2288,29 @@ ${stack ?? ""}`;
|
|
|
2268
2288
|
sorts,
|
|
2269
2289
|
skip: skip ?? 0,
|
|
2270
2290
|
limit: limit ?? 0,
|
|
2271
|
-
joins
|
|
2291
|
+
joins,
|
|
2292
|
+
includeCount
|
|
2272
2293
|
});
|
|
2273
2294
|
const pool = poolOverride ?? modelInstance._readonlyPool;
|
|
2274
2295
|
const results = await pool.query(query, params);
|
|
2275
|
-
|
|
2296
|
+
let totalCount = 0;
|
|
2297
|
+
if (includeCount && results.rows.length > 0 && results.rows[0]?.__total_count__ !== void 0) {
|
|
2298
|
+
totalCount = Number(results.rows[0].__total_count__);
|
|
2299
|
+
}
|
|
2300
|
+
const rows = includeCount ? results.rows.map((row) => {
|
|
2301
|
+
const { __total_count__, ...rest } = row;
|
|
2302
|
+
return rest;
|
|
2303
|
+
}) : results.rows;
|
|
2304
|
+
const entities = returnAsPlainObjects ? modelInstance._buildPlainObjects(rows) : modelInstance._buildInstances(rows);
|
|
2276
2305
|
if (populates.length) {
|
|
2277
|
-
|
|
2306
|
+
const populatesWithFlag = populates.map((pop) => ({ ...pop, asPlainObjects: returnAsPlainObjects }));
|
|
2307
|
+
await modelInstance.populateFields(entities, populatesWithFlag);
|
|
2308
|
+
}
|
|
2309
|
+
if (includeCount) {
|
|
2310
|
+
return await resolve({
|
|
2311
|
+
results: entities,
|
|
2312
|
+
totalCount
|
|
2313
|
+
});
|
|
2278
2314
|
}
|
|
2279
2315
|
return await resolve(entities);
|
|
2280
2316
|
} catch (ex) {
|
|
@@ -2390,6 +2426,40 @@ ${stack ?? ""}`;
|
|
|
2390
2426
|
_buildInstances(rows) {
|
|
2391
2427
|
return rows.map((row) => this._buildInstance(row));
|
|
2392
2428
|
}
|
|
2429
|
+
_buildPlainObject(row) {
|
|
2430
|
+
const plainObject = { ...row };
|
|
2431
|
+
for (const name of this._floatProperties) {
|
|
2432
|
+
const originalValue = plainObject[name];
|
|
2433
|
+
if (originalValue != null && typeof originalValue === "string") {
|
|
2434
|
+
try {
|
|
2435
|
+
const value = Number(originalValue);
|
|
2436
|
+
if (Number.isFinite(value) && value.toString() === originalValue) {
|
|
2437
|
+
plainObject[name] = value;
|
|
2438
|
+
}
|
|
2439
|
+
} catch {
|
|
2440
|
+
}
|
|
2441
|
+
}
|
|
2442
|
+
}
|
|
2443
|
+
for (const name of this._intProperties) {
|
|
2444
|
+
const originalValue = plainObject[name];
|
|
2445
|
+
if (originalValue != null && typeof originalValue === "string") {
|
|
2446
|
+
try {
|
|
2447
|
+
const value = Number(originalValue);
|
|
2448
|
+
if (Number.isFinite(value) && value.toString() === originalValue) {
|
|
2449
|
+
const valueAsInt = Math.trunc(value);
|
|
2450
|
+
if (Number.isSafeInteger(valueAsInt)) {
|
|
2451
|
+
plainObject[name] = valueAsInt;
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
} catch {
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
return plainObject;
|
|
2459
|
+
}
|
|
2460
|
+
_buildPlainObjects(rows) {
|
|
2461
|
+
return rows.map((row) => this._buildPlainObject(row));
|
|
2462
|
+
}
|
|
2393
2463
|
_convertSortsToOrderBy(sorts) {
|
|
2394
2464
|
const result = [];
|
|
2395
2465
|
if (sorts) {
|
|
@@ -2506,12 +2576,13 @@ ${stack ?? ""}`;
|
|
|
2506
2576
|
[populateRepository.model.primaryKeyColumn.propertyName]: Array.from(populateIds),
|
|
2507
2577
|
...populate.where
|
|
2508
2578
|
};
|
|
2509
|
-
const
|
|
2579
|
+
const findQuery = populateRepository.find({
|
|
2510
2580
|
select: populate.select,
|
|
2511
2581
|
where: populateWhere,
|
|
2512
2582
|
sort: populate.sort,
|
|
2513
2583
|
pool: populate.pool
|
|
2514
2584
|
});
|
|
2585
|
+
const populateResults = populate.asPlainObjects ? await findQuery.toJSON() : await findQuery;
|
|
2515
2586
|
const populateResultsById = keyBy(populateResults, populateRepository.model.primaryKeyColumn.propertyName);
|
|
2516
2587
|
for (const entity of entities) {
|
|
2517
2588
|
entity[propertyName] = populateResultsById[entity[propertyName]];
|
|
@@ -2525,7 +2596,7 @@ ${stack ?? ""}`;
|
|
|
2525
2596
|
[column.via]: entityIds,
|
|
2526
2597
|
...populate.where
|
|
2527
2598
|
};
|
|
2528
|
-
const
|
|
2599
|
+
const findQuery = populateRepository.find({
|
|
2529
2600
|
select: populate.select,
|
|
2530
2601
|
where: populateWhere,
|
|
2531
2602
|
sort: populate.sort,
|
|
@@ -2533,6 +2604,7 @@ ${stack ?? ""}`;
|
|
|
2533
2604
|
limit: populate.limit,
|
|
2534
2605
|
pool: populate.pool
|
|
2535
2606
|
});
|
|
2607
|
+
const populateResults = populate.asPlainObjects ? await findQuery.toJSON() : await findQuery;
|
|
2536
2608
|
if (entities.length === 1) {
|
|
2537
2609
|
for (const entity of entities) {
|
|
2538
2610
|
entity[populate.propertyName] = populateResults;
|
|
@@ -2585,7 +2657,7 @@ ${stack ?? ""}`;
|
|
|
2585
2657
|
[populateModelPrimaryKeyPropertyName]: Array.from(populateIds),
|
|
2586
2658
|
...populate.where
|
|
2587
2659
|
};
|
|
2588
|
-
const
|
|
2660
|
+
const findQuery = populateRepository.find({
|
|
2589
2661
|
select: populate.select,
|
|
2590
2662
|
where: populateWhere,
|
|
2591
2663
|
sort: populate.sort,
|
|
@@ -2593,6 +2665,7 @@ ${stack ?? ""}`;
|
|
|
2593
2665
|
limit: populate.limit,
|
|
2594
2666
|
pool: populate.pool
|
|
2595
2667
|
});
|
|
2668
|
+
const populateResults = populate.asPlainObjects ? await findQuery.toJSON() : await findQuery;
|
|
2596
2669
|
const populateResultsById = keyBy(populateResults, populateModelPrimaryKeyPropertyName);
|
|
2597
2670
|
for (const entity of entities) {
|
|
2598
2671
|
const populatedItems = [];
|
package/dist/index.d.cts
CHANGED
|
@@ -85,6 +85,15 @@ type PickFunctions<T> = {
|
|
|
85
85
|
[K in keyof T as IncludeFunctions<T[K], K>]: T[K];
|
|
86
86
|
};
|
|
87
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Recursively converts entity types to plain object types.
|
|
90
|
+
* This is primarily for documentation/intent - at runtime, this strips the prototype chain.
|
|
91
|
+
* Preserves Date objects as-is since they're serializable by most frameworks.
|
|
92
|
+
*/
|
|
93
|
+
type PlainObject<T> = T extends Date ? Date : T extends (infer U)[] ? PlainObject<U>[] : T extends object ? {
|
|
94
|
+
[K in keyof T]: PlainObject<T[K]>;
|
|
95
|
+
} : T;
|
|
96
|
+
|
|
88
97
|
/**
|
|
89
98
|
* Changes all properties with Entity values to Primitive (string|number). Removes any properties that with values
|
|
90
99
|
* of Entity arrays
|
|
@@ -553,6 +562,16 @@ interface PopulateArgs<T extends Entity, K extends keyof T> {
|
|
|
553
562
|
pool?: PoolLike;
|
|
554
563
|
}
|
|
555
564
|
|
|
565
|
+
interface FindOneResultJSON<T extends Entity, TReturn, TJoins extends JoinInfo = never> extends PromiseLike<PlainObject<TReturn> | null> {
|
|
566
|
+
select<TKeys extends string & keyof T>(keys: TKeys[]): FindOneResultJSON<T, Pick<T, TKeys>, TJoins>;
|
|
567
|
+
where(args: JoinedWhereQuery<T, TJoins>): FindOneResultJSON<T, TReturn, TJoins>;
|
|
568
|
+
populate<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T, TPopulateType extends GetValueType<T[TProperty], Entity>, TPopulateSelectKeys extends string & keyof TPopulateType>(propertyName: TProperty, options?: PopulateArgs<TPopulateType, TPopulateSelectKeys>): FindOneResultJSON<T, Omit<TReturn, TProperty> & Populated<T, TProperty, TPopulateType, TPopulateSelectKeys>, TJoins>;
|
|
569
|
+
join<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias): FindOneResultJSON<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
570
|
+
leftJoin<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias, on?: WhereQuery<GetValueType<T[TProperty], Entity>>): FindOneResultJSON<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
571
|
+
sort(value?: JoinedSort<T, TJoins>): FindOneResultJSON<T, TReturn, TJoins>;
|
|
572
|
+
UNSAFE_withOriginalFieldType<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T>(propertyName: TProperty): FindOneResultJSON<T, Omit<TReturn, TProperty> & Pick<T, TProperty>, TJoins>;
|
|
573
|
+
UNSAFE_withFieldValue<TProperty extends string & keyof T, TValue extends T[TProperty]>(propertyName: TProperty, value: TValue): FindOneResultJSON<T, Omit<TReturn, TProperty> & PickAsType<T, TProperty, TValue>, TJoins>;
|
|
574
|
+
}
|
|
556
575
|
interface FindOneResult<T extends Entity, TReturn, TJoins extends JoinInfo = never> extends PromiseLike<TReturn | null> {
|
|
557
576
|
select<TKeys extends string & keyof T>(keys: TKeys[]): FindOneResult<T, Pick<T, TKeys>, TJoins>;
|
|
558
577
|
where(args: JoinedWhereQuery<T, TJoins>): FindOneResult<T, TReturn, TJoins>;
|
|
@@ -562,6 +581,11 @@ interface FindOneResult<T extends Entity, TReturn, TJoins extends JoinInfo = nev
|
|
|
562
581
|
sort(value?: JoinedSort<T, TJoins>): FindOneResult<T, TReturn, TJoins>;
|
|
563
582
|
UNSAFE_withOriginalFieldType<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T>(propertyName: TProperty): FindOneResult<T, Omit<TReturn, TProperty> & Pick<T, TProperty>, TJoins>;
|
|
564
583
|
UNSAFE_withFieldValue<TProperty extends string & keyof T, TValue extends T[TProperty]>(propertyName: TProperty, value: TValue): FindOneResult<T, Omit<TReturn, TProperty> & PickAsType<T, TProperty, TValue>, TJoins>;
|
|
584
|
+
/**
|
|
585
|
+
* Returns result as a plain object instead of an entity class instance.
|
|
586
|
+
* Useful for when data must be serializable.
|
|
587
|
+
*/
|
|
588
|
+
toJSON(): FindOneResultJSON<T, TReturn, TJoins>;
|
|
565
589
|
}
|
|
566
590
|
|
|
567
591
|
interface PaginateOptions {
|
|
@@ -569,6 +593,51 @@ interface PaginateOptions {
|
|
|
569
593
|
page: number;
|
|
570
594
|
}
|
|
571
595
|
|
|
596
|
+
interface FindWithCountResult<TReturn> {
|
|
597
|
+
results: TReturn[];
|
|
598
|
+
totalCount: number;
|
|
599
|
+
}
|
|
600
|
+
interface FindQueryWithCountJSON<T extends Entity, TReturn, TJoins extends JoinInfo = never> extends PromiseLike<FindWithCountResult<PlainObject<TReturn>>> {
|
|
601
|
+
select<TKeys extends string & keyof T>(keys: TKeys[]): FindQueryWithCountJSON<T, Pick<T, TKeys>, TJoins>;
|
|
602
|
+
where(args: JoinedWhereQuery<T, TJoins>): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
603
|
+
populate<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T, TPopulateType extends GetValueType<T[TProperty], Entity>, TPopulateSelectKeys extends string & keyof TPopulateType>(propertyName: TProperty, options?: PopulateArgs<TPopulateType, TPopulateSelectKeys>): FindQueryWithCountJSON<T, Omit<TReturn, TProperty> & Populated<T, TProperty, TPopulateType, TPopulateSelectKeys>, TJoins>;
|
|
604
|
+
join<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias): FindQueryWithCountJSON<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
605
|
+
leftJoin<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias, on?: WhereQuery<GetValueType<T[TProperty], Entity>>): FindQueryWithCountJSON<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
606
|
+
sort(value?: JoinedSort<T, TJoins>): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
607
|
+
limit(value: number): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
608
|
+
skip(value: number): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
609
|
+
paginate(options: PaginateOptions): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
610
|
+
}
|
|
611
|
+
interface FindQueryWithCount<T extends Entity, TReturn, TJoins extends JoinInfo = never> extends PromiseLike<FindWithCountResult<TReturn>> {
|
|
612
|
+
select<TKeys extends string & keyof T>(keys: TKeys[]): FindQueryWithCount<T, Pick<T, TKeys>, TJoins>;
|
|
613
|
+
where(args: JoinedWhereQuery<T, TJoins>): FindQueryWithCount<T, TReturn, TJoins>;
|
|
614
|
+
populate<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T, TPopulateType extends GetValueType<T[TProperty], Entity>, TPopulateSelectKeys extends string & keyof TPopulateType>(propertyName: TProperty, options?: PopulateArgs<TPopulateType, TPopulateSelectKeys>): FindQueryWithCount<T, Omit<TReturn, TProperty> & Populated<T, TProperty, TPopulateType, TPopulateSelectKeys>, TJoins>;
|
|
615
|
+
join<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias): FindQueryWithCount<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
616
|
+
leftJoin<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias, on?: WhereQuery<GetValueType<T[TProperty], Entity>>): FindQueryWithCount<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
617
|
+
sort(value?: JoinedSort<T, TJoins>): FindQueryWithCount<T, TReturn, TJoins>;
|
|
618
|
+
limit(value: number): FindQueryWithCount<T, TReturn, TJoins>;
|
|
619
|
+
skip(value: number): FindQueryWithCount<T, TReturn, TJoins>;
|
|
620
|
+
paginate(options: PaginateOptions): FindQueryWithCount<T, TReturn, TJoins>;
|
|
621
|
+
/**
|
|
622
|
+
* Returns results as plain objects instead of entity class instances.
|
|
623
|
+
* Useful for when data must be serializable.
|
|
624
|
+
*/
|
|
625
|
+
toJSON(): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
interface FindResultJSON<T extends Entity, TReturn, TJoins extends JoinInfo = never> extends PromiseLike<PlainObject<TReturn>[]> {
|
|
629
|
+
select<TKeys extends string & keyof T>(keys: TKeys[]): FindResultJSON<T, Pick<T, TKeys>, TJoins>;
|
|
630
|
+
where(args: JoinedWhereQuery<T, TJoins>): FindResultJSON<T, TReturn, TJoins>;
|
|
631
|
+
populate<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T, TPopulateType extends GetValueType<T[TProperty], Entity>, TPopulateSelectKeys extends string & keyof TPopulateType>(propertyName: TProperty, options?: PopulateArgs<TPopulateType, TPopulateSelectKeys>): FindResultJSON<T, Omit<TReturn, TProperty> & Populated<T, TProperty, TPopulateType, TPopulateSelectKeys>, TJoins>;
|
|
632
|
+
join<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias): FindResultJSON<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
633
|
+
leftJoin<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias, on?: WhereQuery<GetValueType<T[TProperty], Entity>>): FindResultJSON<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
634
|
+
sort(value?: JoinedSort<T, TJoins>): FindResultJSON<T, TReturn, TJoins>;
|
|
635
|
+
limit(value: number): FindResultJSON<T, TReturn, TJoins>;
|
|
636
|
+
skip(value: number): FindResultJSON<T, TReturn, TJoins>;
|
|
637
|
+
paginate(options: PaginateOptions): FindResultJSON<T, TReturn, TJoins>;
|
|
638
|
+
withCount(): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
639
|
+
UNSAFE_withOriginalFieldType<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T>(propertyName: TProperty): FindResultJSON<T, Omit<TReturn, TProperty> & Pick<T, TProperty>, TJoins>;
|
|
640
|
+
}
|
|
572
641
|
interface FindResult<T extends Entity, TReturn, TJoins extends JoinInfo = never> extends PromiseLike<TReturn[]> {
|
|
573
642
|
select<TKeys extends string & keyof T>(keys: TKeys[]): FindResult<T, Pick<T, TKeys>, TJoins>;
|
|
574
643
|
where(args: JoinedWhereQuery<T, TJoins>): FindResult<T, TReturn, TJoins>;
|
|
@@ -579,7 +648,13 @@ interface FindResult<T extends Entity, TReturn, TJoins extends JoinInfo = never>
|
|
|
579
648
|
limit(value: number): FindResult<T, TReturn, TJoins>;
|
|
580
649
|
skip(value: number): FindResult<T, TReturn, TJoins>;
|
|
581
650
|
paginate(options: PaginateOptions): FindResult<T, TReturn, TJoins>;
|
|
651
|
+
withCount(): FindQueryWithCount<T, TReturn, TJoins>;
|
|
582
652
|
UNSAFE_withOriginalFieldType<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T>(propertyName: TProperty): FindResult<T, Omit<TReturn, TProperty> & Pick<T, TProperty>, TJoins>;
|
|
653
|
+
/**
|
|
654
|
+
* Returns results as plain objects instead of entity class instances.
|
|
655
|
+
* Useful for when data must be serializable.
|
|
656
|
+
*/
|
|
657
|
+
toJSON(): FindResultJSON<T, TReturn, TJoins>;
|
|
583
658
|
}
|
|
584
659
|
|
|
585
660
|
interface IRepository<T extends Entity> extends IReadonlyRepository<T> {
|
|
@@ -791,6 +866,7 @@ interface Populate {
|
|
|
791
866
|
skip?: number;
|
|
792
867
|
limit?: number;
|
|
793
868
|
pool?: PoolLike;
|
|
869
|
+
asPlainObjects?: boolean;
|
|
794
870
|
}
|
|
795
871
|
declare class ReadonlyRepository<T extends Entity> implements IReadonlyRepository<T> {
|
|
796
872
|
private readonly _modelMetadata;
|
|
@@ -832,6 +908,8 @@ declare class ReadonlyRepository<T extends Entity> implements IReadonlyRepositor
|
|
|
832
908
|
count(args?: CountArgs<T> | WhereQuery<T>): CountResult<T>;
|
|
833
909
|
protected _buildInstance(row: Partial<QueryResult<T>>): QueryResult<T>;
|
|
834
910
|
protected _buildInstances(rows: Partial<QueryResult<T>>[]): QueryResult<T>[];
|
|
911
|
+
protected _buildPlainObject(row: Partial<QueryResult<T>>): QueryResult<T>;
|
|
912
|
+
protected _buildPlainObjects(rows: Partial<QueryResult<T>>[]): QueryResult<T>[];
|
|
835
913
|
protected _convertSortsToOrderBy(sorts: SortObject<T> | string): OrderBy<T>[];
|
|
836
914
|
protected populateFields(entities: QueryResult<T>[], populates: Populate[]): Promise<void>;
|
|
837
915
|
private populateSingleAssociation;
|
|
@@ -1029,4 +1107,4 @@ interface InitializeOptions extends IConnection {
|
|
|
1029
1107
|
declare function initialize({ models, pool, readonlyPool, connections, expose }: InitializeOptions): Record<string, IReadonlyRepository<Entity> | IRepository<Entity>>;
|
|
1030
1108
|
|
|
1031
1109
|
export { ColumnBaseMetadata, ColumnCollectionMetadata, ColumnModelMetadata, ColumnTypeMetadata, Entity, ModelMetadata, QueryError, ReadonlyRepository, Repository, ScalarSubquery, SubqueryBuilder, column, createDateColumn, getMetadataStorage, initialize, primaryColumn, subquery, table, updateDateColumn, versionColumn };
|
|
1032
|
-
export type { ClassLike, ColumnBaseMetadataOptions, ColumnCollectionMetadataOptions, ColumnMetadata, ColumnModelMetadataOptions, ColumnModifierMetadata, ColumnTypeMetadataOptions, Comparer, CountResult, CreateUpdateOptions, CreateUpdateParams, DeleteOptions, DestroyResult, DoNotReturnRecords, EntityFieldValue, EntityPrimitiveOrId, EntityStatic, ExcludeEntityCollections, ExcludeFunctions, FindArgs, FindOneArgs, FindOneResult, FindResult, GetValueType, IConnection, IReadonlyRepository, IRepository, IRepositoryOptions, IncludeFunctions, InitializeOptions, IsValueOfType, JoinDefinition, JoinInfo, JoinType, JoinedSort, JoinedWhereQuery, LiteralValues, ModelMetadataOptions, ModelRelationshipKeys, MultipleSortString, NegatableConstraint, NotEntity, NotEntityBrand, NumberOrDateConstraint, NumberOrDateConstraintWithSubquery, OmitEntityCollections, OmitFunctions, OrderBy, PaginateOptions, PickAsType, PickByValueType, PickFunctions, PoolLike, PoolQueryResult, PopulateArgs, Populated, QueryResult, QueryResultOptionalPopulated, QueryResultPopulated, QueryResultRow, ReturnSelect$1 as ReturnSelect, ScalarSubqueryConstraint, Sort, SortObject, SortObjectValue, SortString, StringConstraint, SubqueryBuilderLike, SubqueryInConstraint, WhereClauseValue, WhereQuery, WhereQueryStatement };
|
|
1110
|
+
export type { ClassLike, ColumnBaseMetadataOptions, ColumnCollectionMetadataOptions, ColumnMetadata, ColumnModelMetadataOptions, ColumnModifierMetadata, ColumnTypeMetadataOptions, Comparer, CountResult, CreateUpdateOptions, CreateUpdateParams, DeleteOptions, DestroyResult, DoNotReturnRecords, EntityFieldValue, EntityPrimitiveOrId, EntityStatic, ExcludeEntityCollections, ExcludeFunctions, FindArgs, FindOneArgs, FindOneResult, FindOneResultJSON, FindQueryWithCount, FindQueryWithCountJSON, FindResult, FindResultJSON, FindWithCountResult, GetValueType, IConnection, IReadonlyRepository, IRepository, IRepositoryOptions, IncludeFunctions, InitializeOptions, IsValueOfType, JoinDefinition, JoinInfo, JoinType, JoinedSort, JoinedWhereQuery, LiteralValues, ModelMetadataOptions, ModelRelationshipKeys, MultipleSortString, NegatableConstraint, NotEntity, NotEntityBrand, NumberOrDateConstraint, NumberOrDateConstraintWithSubquery, OmitEntityCollections, OmitFunctions, OrderBy, PaginateOptions, PickAsType, PickByValueType, PickFunctions, PlainObject, PoolLike, PoolQueryResult, PopulateArgs, Populated, QueryResult, QueryResultOptionalPopulated, QueryResultPopulated, QueryResultRow, ReturnSelect$1 as ReturnSelect, ScalarSubqueryConstraint, Sort, SortObject, SortObjectValue, SortString, StringConstraint, SubqueryBuilderLike, SubqueryInConstraint, WhereClauseValue, WhereQuery, WhereQueryStatement };
|
package/dist/index.d.mts
CHANGED
|
@@ -85,6 +85,15 @@ type PickFunctions<T> = {
|
|
|
85
85
|
[K in keyof T as IncludeFunctions<T[K], K>]: T[K];
|
|
86
86
|
};
|
|
87
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Recursively converts entity types to plain object types.
|
|
90
|
+
* This is primarily for documentation/intent - at runtime, this strips the prototype chain.
|
|
91
|
+
* Preserves Date objects as-is since they're serializable by most frameworks.
|
|
92
|
+
*/
|
|
93
|
+
type PlainObject<T> = T extends Date ? Date : T extends (infer U)[] ? PlainObject<U>[] : T extends object ? {
|
|
94
|
+
[K in keyof T]: PlainObject<T[K]>;
|
|
95
|
+
} : T;
|
|
96
|
+
|
|
88
97
|
/**
|
|
89
98
|
* Changes all properties with Entity values to Primitive (string|number). Removes any properties that with values
|
|
90
99
|
* of Entity arrays
|
|
@@ -553,6 +562,16 @@ interface PopulateArgs<T extends Entity, K extends keyof T> {
|
|
|
553
562
|
pool?: PoolLike;
|
|
554
563
|
}
|
|
555
564
|
|
|
565
|
+
interface FindOneResultJSON<T extends Entity, TReturn, TJoins extends JoinInfo = never> extends PromiseLike<PlainObject<TReturn> | null> {
|
|
566
|
+
select<TKeys extends string & keyof T>(keys: TKeys[]): FindOneResultJSON<T, Pick<T, TKeys>, TJoins>;
|
|
567
|
+
where(args: JoinedWhereQuery<T, TJoins>): FindOneResultJSON<T, TReturn, TJoins>;
|
|
568
|
+
populate<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T, TPopulateType extends GetValueType<T[TProperty], Entity>, TPopulateSelectKeys extends string & keyof TPopulateType>(propertyName: TProperty, options?: PopulateArgs<TPopulateType, TPopulateSelectKeys>): FindOneResultJSON<T, Omit<TReturn, TProperty> & Populated<T, TProperty, TPopulateType, TPopulateSelectKeys>, TJoins>;
|
|
569
|
+
join<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias): FindOneResultJSON<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
570
|
+
leftJoin<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias, on?: WhereQuery<GetValueType<T[TProperty], Entity>>): FindOneResultJSON<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
571
|
+
sort(value?: JoinedSort<T, TJoins>): FindOneResultJSON<T, TReturn, TJoins>;
|
|
572
|
+
UNSAFE_withOriginalFieldType<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T>(propertyName: TProperty): FindOneResultJSON<T, Omit<TReturn, TProperty> & Pick<T, TProperty>, TJoins>;
|
|
573
|
+
UNSAFE_withFieldValue<TProperty extends string & keyof T, TValue extends T[TProperty]>(propertyName: TProperty, value: TValue): FindOneResultJSON<T, Omit<TReturn, TProperty> & PickAsType<T, TProperty, TValue>, TJoins>;
|
|
574
|
+
}
|
|
556
575
|
interface FindOneResult<T extends Entity, TReturn, TJoins extends JoinInfo = never> extends PromiseLike<TReturn | null> {
|
|
557
576
|
select<TKeys extends string & keyof T>(keys: TKeys[]): FindOneResult<T, Pick<T, TKeys>, TJoins>;
|
|
558
577
|
where(args: JoinedWhereQuery<T, TJoins>): FindOneResult<T, TReturn, TJoins>;
|
|
@@ -562,6 +581,11 @@ interface FindOneResult<T extends Entity, TReturn, TJoins extends JoinInfo = nev
|
|
|
562
581
|
sort(value?: JoinedSort<T, TJoins>): FindOneResult<T, TReturn, TJoins>;
|
|
563
582
|
UNSAFE_withOriginalFieldType<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T>(propertyName: TProperty): FindOneResult<T, Omit<TReturn, TProperty> & Pick<T, TProperty>, TJoins>;
|
|
564
583
|
UNSAFE_withFieldValue<TProperty extends string & keyof T, TValue extends T[TProperty]>(propertyName: TProperty, value: TValue): FindOneResult<T, Omit<TReturn, TProperty> & PickAsType<T, TProperty, TValue>, TJoins>;
|
|
584
|
+
/**
|
|
585
|
+
* Returns result as a plain object instead of an entity class instance.
|
|
586
|
+
* Useful for when data must be serializable.
|
|
587
|
+
*/
|
|
588
|
+
toJSON(): FindOneResultJSON<T, TReturn, TJoins>;
|
|
565
589
|
}
|
|
566
590
|
|
|
567
591
|
interface PaginateOptions {
|
|
@@ -569,6 +593,51 @@ interface PaginateOptions {
|
|
|
569
593
|
page: number;
|
|
570
594
|
}
|
|
571
595
|
|
|
596
|
+
interface FindWithCountResult<TReturn> {
|
|
597
|
+
results: TReturn[];
|
|
598
|
+
totalCount: number;
|
|
599
|
+
}
|
|
600
|
+
interface FindQueryWithCountJSON<T extends Entity, TReturn, TJoins extends JoinInfo = never> extends PromiseLike<FindWithCountResult<PlainObject<TReturn>>> {
|
|
601
|
+
select<TKeys extends string & keyof T>(keys: TKeys[]): FindQueryWithCountJSON<T, Pick<T, TKeys>, TJoins>;
|
|
602
|
+
where(args: JoinedWhereQuery<T, TJoins>): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
603
|
+
populate<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T, TPopulateType extends GetValueType<T[TProperty], Entity>, TPopulateSelectKeys extends string & keyof TPopulateType>(propertyName: TProperty, options?: PopulateArgs<TPopulateType, TPopulateSelectKeys>): FindQueryWithCountJSON<T, Omit<TReturn, TProperty> & Populated<T, TProperty, TPopulateType, TPopulateSelectKeys>, TJoins>;
|
|
604
|
+
join<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias): FindQueryWithCountJSON<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
605
|
+
leftJoin<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias, on?: WhereQuery<GetValueType<T[TProperty], Entity>>): FindQueryWithCountJSON<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
606
|
+
sort(value?: JoinedSort<T, TJoins>): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
607
|
+
limit(value: number): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
608
|
+
skip(value: number): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
609
|
+
paginate(options: PaginateOptions): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
610
|
+
}
|
|
611
|
+
interface FindQueryWithCount<T extends Entity, TReturn, TJoins extends JoinInfo = never> extends PromiseLike<FindWithCountResult<TReturn>> {
|
|
612
|
+
select<TKeys extends string & keyof T>(keys: TKeys[]): FindQueryWithCount<T, Pick<T, TKeys>, TJoins>;
|
|
613
|
+
where(args: JoinedWhereQuery<T, TJoins>): FindQueryWithCount<T, TReturn, TJoins>;
|
|
614
|
+
populate<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T, TPopulateType extends GetValueType<T[TProperty], Entity>, TPopulateSelectKeys extends string & keyof TPopulateType>(propertyName: TProperty, options?: PopulateArgs<TPopulateType, TPopulateSelectKeys>): FindQueryWithCount<T, Omit<TReturn, TProperty> & Populated<T, TProperty, TPopulateType, TPopulateSelectKeys>, TJoins>;
|
|
615
|
+
join<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias): FindQueryWithCount<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
616
|
+
leftJoin<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias, on?: WhereQuery<GetValueType<T[TProperty], Entity>>): FindQueryWithCount<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
617
|
+
sort(value?: JoinedSort<T, TJoins>): FindQueryWithCount<T, TReturn, TJoins>;
|
|
618
|
+
limit(value: number): FindQueryWithCount<T, TReturn, TJoins>;
|
|
619
|
+
skip(value: number): FindQueryWithCount<T, TReturn, TJoins>;
|
|
620
|
+
paginate(options: PaginateOptions): FindQueryWithCount<T, TReturn, TJoins>;
|
|
621
|
+
/**
|
|
622
|
+
* Returns results as plain objects instead of entity class instances.
|
|
623
|
+
* Useful for when data must be serializable.
|
|
624
|
+
*/
|
|
625
|
+
toJSON(): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
interface FindResultJSON<T extends Entity, TReturn, TJoins extends JoinInfo = never> extends PromiseLike<PlainObject<TReturn>[]> {
|
|
629
|
+
select<TKeys extends string & keyof T>(keys: TKeys[]): FindResultJSON<T, Pick<T, TKeys>, TJoins>;
|
|
630
|
+
where(args: JoinedWhereQuery<T, TJoins>): FindResultJSON<T, TReturn, TJoins>;
|
|
631
|
+
populate<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T, TPopulateType extends GetValueType<T[TProperty], Entity>, TPopulateSelectKeys extends string & keyof TPopulateType>(propertyName: TProperty, options?: PopulateArgs<TPopulateType, TPopulateSelectKeys>): FindResultJSON<T, Omit<TReturn, TProperty> & Populated<T, TProperty, TPopulateType, TPopulateSelectKeys>, TJoins>;
|
|
632
|
+
join<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias): FindResultJSON<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
633
|
+
leftJoin<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias, on?: WhereQuery<GetValueType<T[TProperty], Entity>>): FindResultJSON<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
634
|
+
sort(value?: JoinedSort<T, TJoins>): FindResultJSON<T, TReturn, TJoins>;
|
|
635
|
+
limit(value: number): FindResultJSON<T, TReturn, TJoins>;
|
|
636
|
+
skip(value: number): FindResultJSON<T, TReturn, TJoins>;
|
|
637
|
+
paginate(options: PaginateOptions): FindResultJSON<T, TReturn, TJoins>;
|
|
638
|
+
withCount(): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
639
|
+
UNSAFE_withOriginalFieldType<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T>(propertyName: TProperty): FindResultJSON<T, Omit<TReturn, TProperty> & Pick<T, TProperty>, TJoins>;
|
|
640
|
+
}
|
|
572
641
|
interface FindResult<T extends Entity, TReturn, TJoins extends JoinInfo = never> extends PromiseLike<TReturn[]> {
|
|
573
642
|
select<TKeys extends string & keyof T>(keys: TKeys[]): FindResult<T, Pick<T, TKeys>, TJoins>;
|
|
574
643
|
where(args: JoinedWhereQuery<T, TJoins>): FindResult<T, TReturn, TJoins>;
|
|
@@ -579,7 +648,13 @@ interface FindResult<T extends Entity, TReturn, TJoins extends JoinInfo = never>
|
|
|
579
648
|
limit(value: number): FindResult<T, TReturn, TJoins>;
|
|
580
649
|
skip(value: number): FindResult<T, TReturn, TJoins>;
|
|
581
650
|
paginate(options: PaginateOptions): FindResult<T, TReturn, TJoins>;
|
|
651
|
+
withCount(): FindQueryWithCount<T, TReturn, TJoins>;
|
|
582
652
|
UNSAFE_withOriginalFieldType<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T>(propertyName: TProperty): FindResult<T, Omit<TReturn, TProperty> & Pick<T, TProperty>, TJoins>;
|
|
653
|
+
/**
|
|
654
|
+
* Returns results as plain objects instead of entity class instances.
|
|
655
|
+
* Useful for when data must be serializable.
|
|
656
|
+
*/
|
|
657
|
+
toJSON(): FindResultJSON<T, TReturn, TJoins>;
|
|
583
658
|
}
|
|
584
659
|
|
|
585
660
|
interface IRepository<T extends Entity> extends IReadonlyRepository<T> {
|
|
@@ -791,6 +866,7 @@ interface Populate {
|
|
|
791
866
|
skip?: number;
|
|
792
867
|
limit?: number;
|
|
793
868
|
pool?: PoolLike;
|
|
869
|
+
asPlainObjects?: boolean;
|
|
794
870
|
}
|
|
795
871
|
declare class ReadonlyRepository<T extends Entity> implements IReadonlyRepository<T> {
|
|
796
872
|
private readonly _modelMetadata;
|
|
@@ -832,6 +908,8 @@ declare class ReadonlyRepository<T extends Entity> implements IReadonlyRepositor
|
|
|
832
908
|
count(args?: CountArgs<T> | WhereQuery<T>): CountResult<T>;
|
|
833
909
|
protected _buildInstance(row: Partial<QueryResult<T>>): QueryResult<T>;
|
|
834
910
|
protected _buildInstances(rows: Partial<QueryResult<T>>[]): QueryResult<T>[];
|
|
911
|
+
protected _buildPlainObject(row: Partial<QueryResult<T>>): QueryResult<T>;
|
|
912
|
+
protected _buildPlainObjects(rows: Partial<QueryResult<T>>[]): QueryResult<T>[];
|
|
835
913
|
protected _convertSortsToOrderBy(sorts: SortObject<T> | string): OrderBy<T>[];
|
|
836
914
|
protected populateFields(entities: QueryResult<T>[], populates: Populate[]): Promise<void>;
|
|
837
915
|
private populateSingleAssociation;
|
|
@@ -1029,4 +1107,4 @@ interface InitializeOptions extends IConnection {
|
|
|
1029
1107
|
declare function initialize({ models, pool, readonlyPool, connections, expose }: InitializeOptions): Record<string, IReadonlyRepository<Entity> | IRepository<Entity>>;
|
|
1030
1108
|
|
|
1031
1109
|
export { ColumnBaseMetadata, ColumnCollectionMetadata, ColumnModelMetadata, ColumnTypeMetadata, Entity, ModelMetadata, QueryError, ReadonlyRepository, Repository, ScalarSubquery, SubqueryBuilder, column, createDateColumn, getMetadataStorage, initialize, primaryColumn, subquery, table, updateDateColumn, versionColumn };
|
|
1032
|
-
export type { ClassLike, ColumnBaseMetadataOptions, ColumnCollectionMetadataOptions, ColumnMetadata, ColumnModelMetadataOptions, ColumnModifierMetadata, ColumnTypeMetadataOptions, Comparer, CountResult, CreateUpdateOptions, CreateUpdateParams, DeleteOptions, DestroyResult, DoNotReturnRecords, EntityFieldValue, EntityPrimitiveOrId, EntityStatic, ExcludeEntityCollections, ExcludeFunctions, FindArgs, FindOneArgs, FindOneResult, FindResult, GetValueType, IConnection, IReadonlyRepository, IRepository, IRepositoryOptions, IncludeFunctions, InitializeOptions, IsValueOfType, JoinDefinition, JoinInfo, JoinType, JoinedSort, JoinedWhereQuery, LiteralValues, ModelMetadataOptions, ModelRelationshipKeys, MultipleSortString, NegatableConstraint, NotEntity, NotEntityBrand, NumberOrDateConstraint, NumberOrDateConstraintWithSubquery, OmitEntityCollections, OmitFunctions, OrderBy, PaginateOptions, PickAsType, PickByValueType, PickFunctions, PoolLike, PoolQueryResult, PopulateArgs, Populated, QueryResult, QueryResultOptionalPopulated, QueryResultPopulated, QueryResultRow, ReturnSelect$1 as ReturnSelect, ScalarSubqueryConstraint, Sort, SortObject, SortObjectValue, SortString, StringConstraint, SubqueryBuilderLike, SubqueryInConstraint, WhereClauseValue, WhereQuery, WhereQueryStatement };
|
|
1110
|
+
export type { ClassLike, ColumnBaseMetadataOptions, ColumnCollectionMetadataOptions, ColumnMetadata, ColumnModelMetadataOptions, ColumnModifierMetadata, ColumnTypeMetadataOptions, Comparer, CountResult, CreateUpdateOptions, CreateUpdateParams, DeleteOptions, DestroyResult, DoNotReturnRecords, EntityFieldValue, EntityPrimitiveOrId, EntityStatic, ExcludeEntityCollections, ExcludeFunctions, FindArgs, FindOneArgs, FindOneResult, FindOneResultJSON, FindQueryWithCount, FindQueryWithCountJSON, FindResult, FindResultJSON, FindWithCountResult, GetValueType, IConnection, IReadonlyRepository, IRepository, IRepositoryOptions, IncludeFunctions, InitializeOptions, IsValueOfType, JoinDefinition, JoinInfo, JoinType, JoinedSort, JoinedWhereQuery, LiteralValues, ModelMetadataOptions, ModelRelationshipKeys, MultipleSortString, NegatableConstraint, NotEntity, NotEntityBrand, NumberOrDateConstraint, NumberOrDateConstraintWithSubquery, OmitEntityCollections, OmitFunctions, OrderBy, PaginateOptions, PickAsType, PickByValueType, PickFunctions, PlainObject, PoolLike, PoolQueryResult, PopulateArgs, Populated, QueryResult, QueryResultOptionalPopulated, QueryResultPopulated, QueryResultRow, ReturnSelect$1 as ReturnSelect, ScalarSubqueryConstraint, Sort, SortObject, SortObjectValue, SortString, StringConstraint, SubqueryBuilderLike, SubqueryInConstraint, WhereClauseValue, WhereQuery, WhereQueryStatement };
|
package/dist/index.d.ts
CHANGED
|
@@ -85,6 +85,15 @@ type PickFunctions<T> = {
|
|
|
85
85
|
[K in keyof T as IncludeFunctions<T[K], K>]: T[K];
|
|
86
86
|
};
|
|
87
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Recursively converts entity types to plain object types.
|
|
90
|
+
* This is primarily for documentation/intent - at runtime, this strips the prototype chain.
|
|
91
|
+
* Preserves Date objects as-is since they're serializable by most frameworks.
|
|
92
|
+
*/
|
|
93
|
+
type PlainObject<T> = T extends Date ? Date : T extends (infer U)[] ? PlainObject<U>[] : T extends object ? {
|
|
94
|
+
[K in keyof T]: PlainObject<T[K]>;
|
|
95
|
+
} : T;
|
|
96
|
+
|
|
88
97
|
/**
|
|
89
98
|
* Changes all properties with Entity values to Primitive (string|number). Removes any properties that with values
|
|
90
99
|
* of Entity arrays
|
|
@@ -553,6 +562,16 @@ interface PopulateArgs<T extends Entity, K extends keyof T> {
|
|
|
553
562
|
pool?: PoolLike;
|
|
554
563
|
}
|
|
555
564
|
|
|
565
|
+
interface FindOneResultJSON<T extends Entity, TReturn, TJoins extends JoinInfo = never> extends PromiseLike<PlainObject<TReturn> | null> {
|
|
566
|
+
select<TKeys extends string & keyof T>(keys: TKeys[]): FindOneResultJSON<T, Pick<T, TKeys>, TJoins>;
|
|
567
|
+
where(args: JoinedWhereQuery<T, TJoins>): FindOneResultJSON<T, TReturn, TJoins>;
|
|
568
|
+
populate<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T, TPopulateType extends GetValueType<T[TProperty], Entity>, TPopulateSelectKeys extends string & keyof TPopulateType>(propertyName: TProperty, options?: PopulateArgs<TPopulateType, TPopulateSelectKeys>): FindOneResultJSON<T, Omit<TReturn, TProperty> & Populated<T, TProperty, TPopulateType, TPopulateSelectKeys>, TJoins>;
|
|
569
|
+
join<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias): FindOneResultJSON<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
570
|
+
leftJoin<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias, on?: WhereQuery<GetValueType<T[TProperty], Entity>>): FindOneResultJSON<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
571
|
+
sort(value?: JoinedSort<T, TJoins>): FindOneResultJSON<T, TReturn, TJoins>;
|
|
572
|
+
UNSAFE_withOriginalFieldType<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T>(propertyName: TProperty): FindOneResultJSON<T, Omit<TReturn, TProperty> & Pick<T, TProperty>, TJoins>;
|
|
573
|
+
UNSAFE_withFieldValue<TProperty extends string & keyof T, TValue extends T[TProperty]>(propertyName: TProperty, value: TValue): FindOneResultJSON<T, Omit<TReturn, TProperty> & PickAsType<T, TProperty, TValue>, TJoins>;
|
|
574
|
+
}
|
|
556
575
|
interface FindOneResult<T extends Entity, TReturn, TJoins extends JoinInfo = never> extends PromiseLike<TReturn | null> {
|
|
557
576
|
select<TKeys extends string & keyof T>(keys: TKeys[]): FindOneResult<T, Pick<T, TKeys>, TJoins>;
|
|
558
577
|
where(args: JoinedWhereQuery<T, TJoins>): FindOneResult<T, TReturn, TJoins>;
|
|
@@ -562,6 +581,11 @@ interface FindOneResult<T extends Entity, TReturn, TJoins extends JoinInfo = nev
|
|
|
562
581
|
sort(value?: JoinedSort<T, TJoins>): FindOneResult<T, TReturn, TJoins>;
|
|
563
582
|
UNSAFE_withOriginalFieldType<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T>(propertyName: TProperty): FindOneResult<T, Omit<TReturn, TProperty> & Pick<T, TProperty>, TJoins>;
|
|
564
583
|
UNSAFE_withFieldValue<TProperty extends string & keyof T, TValue extends T[TProperty]>(propertyName: TProperty, value: TValue): FindOneResult<T, Omit<TReturn, TProperty> & PickAsType<T, TProperty, TValue>, TJoins>;
|
|
584
|
+
/**
|
|
585
|
+
* Returns result as a plain object instead of an entity class instance.
|
|
586
|
+
* Useful for when data must be serializable.
|
|
587
|
+
*/
|
|
588
|
+
toJSON(): FindOneResultJSON<T, TReturn, TJoins>;
|
|
565
589
|
}
|
|
566
590
|
|
|
567
591
|
interface PaginateOptions {
|
|
@@ -569,6 +593,51 @@ interface PaginateOptions {
|
|
|
569
593
|
page: number;
|
|
570
594
|
}
|
|
571
595
|
|
|
596
|
+
interface FindWithCountResult<TReturn> {
|
|
597
|
+
results: TReturn[];
|
|
598
|
+
totalCount: number;
|
|
599
|
+
}
|
|
600
|
+
interface FindQueryWithCountJSON<T extends Entity, TReturn, TJoins extends JoinInfo = never> extends PromiseLike<FindWithCountResult<PlainObject<TReturn>>> {
|
|
601
|
+
select<TKeys extends string & keyof T>(keys: TKeys[]): FindQueryWithCountJSON<T, Pick<T, TKeys>, TJoins>;
|
|
602
|
+
where(args: JoinedWhereQuery<T, TJoins>): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
603
|
+
populate<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T, TPopulateType extends GetValueType<T[TProperty], Entity>, TPopulateSelectKeys extends string & keyof TPopulateType>(propertyName: TProperty, options?: PopulateArgs<TPopulateType, TPopulateSelectKeys>): FindQueryWithCountJSON<T, Omit<TReturn, TProperty> & Populated<T, TProperty, TPopulateType, TPopulateSelectKeys>, TJoins>;
|
|
604
|
+
join<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias): FindQueryWithCountJSON<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
605
|
+
leftJoin<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias, on?: WhereQuery<GetValueType<T[TProperty], Entity>>): FindQueryWithCountJSON<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
606
|
+
sort(value?: JoinedSort<T, TJoins>): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
607
|
+
limit(value: number): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
608
|
+
skip(value: number): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
609
|
+
paginate(options: PaginateOptions): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
610
|
+
}
|
|
611
|
+
interface FindQueryWithCount<T extends Entity, TReturn, TJoins extends JoinInfo = never> extends PromiseLike<FindWithCountResult<TReturn>> {
|
|
612
|
+
select<TKeys extends string & keyof T>(keys: TKeys[]): FindQueryWithCount<T, Pick<T, TKeys>, TJoins>;
|
|
613
|
+
where(args: JoinedWhereQuery<T, TJoins>): FindQueryWithCount<T, TReturn, TJoins>;
|
|
614
|
+
populate<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T, TPopulateType extends GetValueType<T[TProperty], Entity>, TPopulateSelectKeys extends string & keyof TPopulateType>(propertyName: TProperty, options?: PopulateArgs<TPopulateType, TPopulateSelectKeys>): FindQueryWithCount<T, Omit<TReturn, TProperty> & Populated<T, TProperty, TPopulateType, TPopulateSelectKeys>, TJoins>;
|
|
615
|
+
join<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias): FindQueryWithCount<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
616
|
+
leftJoin<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias, on?: WhereQuery<GetValueType<T[TProperty], Entity>>): FindQueryWithCount<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
617
|
+
sort(value?: JoinedSort<T, TJoins>): FindQueryWithCount<T, TReturn, TJoins>;
|
|
618
|
+
limit(value: number): FindQueryWithCount<T, TReturn, TJoins>;
|
|
619
|
+
skip(value: number): FindQueryWithCount<T, TReturn, TJoins>;
|
|
620
|
+
paginate(options: PaginateOptions): FindQueryWithCount<T, TReturn, TJoins>;
|
|
621
|
+
/**
|
|
622
|
+
* Returns results as plain objects instead of entity class instances.
|
|
623
|
+
* Useful for when data must be serializable.
|
|
624
|
+
*/
|
|
625
|
+
toJSON(): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
interface FindResultJSON<T extends Entity, TReturn, TJoins extends JoinInfo = never> extends PromiseLike<PlainObject<TReturn>[]> {
|
|
629
|
+
select<TKeys extends string & keyof T>(keys: TKeys[]): FindResultJSON<T, Pick<T, TKeys>, TJoins>;
|
|
630
|
+
where(args: JoinedWhereQuery<T, TJoins>): FindResultJSON<T, TReturn, TJoins>;
|
|
631
|
+
populate<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T, TPopulateType extends GetValueType<T[TProperty], Entity>, TPopulateSelectKeys extends string & keyof TPopulateType>(propertyName: TProperty, options?: PopulateArgs<TPopulateType, TPopulateSelectKeys>): FindResultJSON<T, Omit<TReturn, TProperty> & Populated<T, TProperty, TPopulateType, TPopulateSelectKeys>, TJoins>;
|
|
632
|
+
join<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias): FindResultJSON<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
633
|
+
leftJoin<TProperty extends ModelRelationshipKeys<T>, TAlias extends string = TProperty>(propertyName: TProperty, alias?: TAlias, on?: WhereQuery<GetValueType<T[TProperty], Entity>>): FindResultJSON<T, TReturn, JoinInfo<TProperty, TAlias, GetValueType<T[TProperty], Entity>> | TJoins>;
|
|
634
|
+
sort(value?: JoinedSort<T, TJoins>): FindResultJSON<T, TReturn, TJoins>;
|
|
635
|
+
limit(value: number): FindResultJSON<T, TReturn, TJoins>;
|
|
636
|
+
skip(value: number): FindResultJSON<T, TReturn, TJoins>;
|
|
637
|
+
paginate(options: PaginateOptions): FindResultJSON<T, TReturn, TJoins>;
|
|
638
|
+
withCount(): FindQueryWithCountJSON<T, TReturn, TJoins>;
|
|
639
|
+
UNSAFE_withOriginalFieldType<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T>(propertyName: TProperty): FindResultJSON<T, Omit<TReturn, TProperty> & Pick<T, TProperty>, TJoins>;
|
|
640
|
+
}
|
|
572
641
|
interface FindResult<T extends Entity, TReturn, TJoins extends JoinInfo = never> extends PromiseLike<TReturn[]> {
|
|
573
642
|
select<TKeys extends string & keyof T>(keys: TKeys[]): FindResult<T, Pick<T, TKeys>, TJoins>;
|
|
574
643
|
where(args: JoinedWhereQuery<T, TJoins>): FindResult<T, TReturn, TJoins>;
|
|
@@ -579,7 +648,13 @@ interface FindResult<T extends Entity, TReturn, TJoins extends JoinInfo = never>
|
|
|
579
648
|
limit(value: number): FindResult<T, TReturn, TJoins>;
|
|
580
649
|
skip(value: number): FindResult<T, TReturn, TJoins>;
|
|
581
650
|
paginate(options: PaginateOptions): FindResult<T, TReturn, TJoins>;
|
|
651
|
+
withCount(): FindQueryWithCount<T, TReturn, TJoins>;
|
|
582
652
|
UNSAFE_withOriginalFieldType<TProperty extends string & keyof PickByValueType<T, Entity> & keyof T>(propertyName: TProperty): FindResult<T, Omit<TReturn, TProperty> & Pick<T, TProperty>, TJoins>;
|
|
653
|
+
/**
|
|
654
|
+
* Returns results as plain objects instead of entity class instances.
|
|
655
|
+
* Useful for when data must be serializable.
|
|
656
|
+
*/
|
|
657
|
+
toJSON(): FindResultJSON<T, TReturn, TJoins>;
|
|
583
658
|
}
|
|
584
659
|
|
|
585
660
|
interface IRepository<T extends Entity> extends IReadonlyRepository<T> {
|
|
@@ -791,6 +866,7 @@ interface Populate {
|
|
|
791
866
|
skip?: number;
|
|
792
867
|
limit?: number;
|
|
793
868
|
pool?: PoolLike;
|
|
869
|
+
asPlainObjects?: boolean;
|
|
794
870
|
}
|
|
795
871
|
declare class ReadonlyRepository<T extends Entity> implements IReadonlyRepository<T> {
|
|
796
872
|
private readonly _modelMetadata;
|
|
@@ -832,6 +908,8 @@ declare class ReadonlyRepository<T extends Entity> implements IReadonlyRepositor
|
|
|
832
908
|
count(args?: CountArgs<T> | WhereQuery<T>): CountResult<T>;
|
|
833
909
|
protected _buildInstance(row: Partial<QueryResult<T>>): QueryResult<T>;
|
|
834
910
|
protected _buildInstances(rows: Partial<QueryResult<T>>[]): QueryResult<T>[];
|
|
911
|
+
protected _buildPlainObject(row: Partial<QueryResult<T>>): QueryResult<T>;
|
|
912
|
+
protected _buildPlainObjects(rows: Partial<QueryResult<T>>[]): QueryResult<T>[];
|
|
835
913
|
protected _convertSortsToOrderBy(sorts: SortObject<T> | string): OrderBy<T>[];
|
|
836
914
|
protected populateFields(entities: QueryResult<T>[], populates: Populate[]): Promise<void>;
|
|
837
915
|
private populateSingleAssociation;
|
|
@@ -1029,4 +1107,4 @@ interface InitializeOptions extends IConnection {
|
|
|
1029
1107
|
declare function initialize({ models, pool, readonlyPool, connections, expose }: InitializeOptions): Record<string, IReadonlyRepository<Entity> | IRepository<Entity>>;
|
|
1030
1108
|
|
|
1031
1109
|
export { ColumnBaseMetadata, ColumnCollectionMetadata, ColumnModelMetadata, ColumnTypeMetadata, Entity, ModelMetadata, QueryError, ReadonlyRepository, Repository, ScalarSubquery, SubqueryBuilder, column, createDateColumn, getMetadataStorage, initialize, primaryColumn, subquery, table, updateDateColumn, versionColumn };
|
|
1032
|
-
export type { ClassLike, ColumnBaseMetadataOptions, ColumnCollectionMetadataOptions, ColumnMetadata, ColumnModelMetadataOptions, ColumnModifierMetadata, ColumnTypeMetadataOptions, Comparer, CountResult, CreateUpdateOptions, CreateUpdateParams, DeleteOptions, DestroyResult, DoNotReturnRecords, EntityFieldValue, EntityPrimitiveOrId, EntityStatic, ExcludeEntityCollections, ExcludeFunctions, FindArgs, FindOneArgs, FindOneResult, FindResult, GetValueType, IConnection, IReadonlyRepository, IRepository, IRepositoryOptions, IncludeFunctions, InitializeOptions, IsValueOfType, JoinDefinition, JoinInfo, JoinType, JoinedSort, JoinedWhereQuery, LiteralValues, ModelMetadataOptions, ModelRelationshipKeys, MultipleSortString, NegatableConstraint, NotEntity, NotEntityBrand, NumberOrDateConstraint, NumberOrDateConstraintWithSubquery, OmitEntityCollections, OmitFunctions, OrderBy, PaginateOptions, PickAsType, PickByValueType, PickFunctions, PoolLike, PoolQueryResult, PopulateArgs, Populated, QueryResult, QueryResultOptionalPopulated, QueryResultPopulated, QueryResultRow, ReturnSelect$1 as ReturnSelect, ScalarSubqueryConstraint, Sort, SortObject, SortObjectValue, SortString, StringConstraint, SubqueryBuilderLike, SubqueryInConstraint, WhereClauseValue, WhereQuery, WhereQueryStatement };
|
|
1110
|
+
export type { ClassLike, ColumnBaseMetadataOptions, ColumnCollectionMetadataOptions, ColumnMetadata, ColumnModelMetadataOptions, ColumnModifierMetadata, ColumnTypeMetadataOptions, Comparer, CountResult, CreateUpdateOptions, CreateUpdateParams, DeleteOptions, DestroyResult, DoNotReturnRecords, EntityFieldValue, EntityPrimitiveOrId, EntityStatic, ExcludeEntityCollections, ExcludeFunctions, FindArgs, FindOneArgs, FindOneResult, FindOneResultJSON, FindQueryWithCount, FindQueryWithCountJSON, FindResult, FindResultJSON, FindWithCountResult, GetValueType, IConnection, IReadonlyRepository, IRepository, IRepositoryOptions, IncludeFunctions, InitializeOptions, IsValueOfType, JoinDefinition, JoinInfo, JoinType, JoinedSort, JoinedWhereQuery, LiteralValues, ModelMetadataOptions, ModelRelationshipKeys, MultipleSortString, NegatableConstraint, NotEntity, NotEntityBrand, NumberOrDateConstraint, NumberOrDateConstraintWithSubquery, OmitEntityCollections, OmitFunctions, OrderBy, PaginateOptions, PickAsType, PickByValueType, PickFunctions, PlainObject, PoolLike, PoolQueryResult, PopulateArgs, Populated, QueryResult, QueryResultOptionalPopulated, QueryResultPopulated, QueryResultRow, ReturnSelect$1 as ReturnSelect, ScalarSubqueryConstraint, Sort, SortObject, SortObjectValue, SortString, StringConstraint, SubqueryBuilderLike, SubqueryInConstraint, WhereClauseValue, WhereQuery, WhereQueryStatement };
|
package/dist/index.mjs
CHANGED
|
@@ -443,13 +443,17 @@ function getSelectQueryAndParams({
|
|
|
443
443
|
sorts,
|
|
444
444
|
skip,
|
|
445
445
|
limit,
|
|
446
|
-
joins
|
|
446
|
+
joins,
|
|
447
|
+
includeCount
|
|
447
448
|
}) {
|
|
448
449
|
let query = "SELECT ";
|
|
449
450
|
query += getColumnsToSelect({
|
|
450
451
|
model,
|
|
451
452
|
select
|
|
452
453
|
});
|
|
454
|
+
if (includeCount) {
|
|
455
|
+
query += ',count(*) OVER() AS "__total_count__"';
|
|
456
|
+
}
|
|
453
457
|
query += ` FROM ${model.qualifiedTableName}`;
|
|
454
458
|
const params = [];
|
|
455
459
|
if (joins?.length) {
|
|
@@ -899,7 +903,7 @@ function buildJoinClauses({
|
|
|
899
903
|
if (alias !== relatedModel.tableName) {
|
|
900
904
|
joinSql += ` AS "${alias}"`;
|
|
901
905
|
}
|
|
902
|
-
joinSql += ` ON ${model.qualifiedTableName}."${column.name}"
|
|
906
|
+
joinSql += ` ON ${model.qualifiedTableName}."${column.name}"="${alias}"."${relatedPrimaryKey.name}"`;
|
|
903
907
|
if (join.on) {
|
|
904
908
|
for (const [propertyName, value] of Object.entries(join.on)) {
|
|
905
909
|
const onColumn = relatedModel.columnsByPropertyName[propertyName];
|
|
@@ -1955,6 +1959,7 @@ class ReadonlyRepository {
|
|
|
1955
1959
|
const manuallySetFields = [];
|
|
1956
1960
|
const sorts = sort ? this._convertSortsToOrderBy(sort) : [];
|
|
1957
1961
|
const joins = [];
|
|
1962
|
+
let returnAsPlainObjects = false;
|
|
1958
1963
|
const modelInstance = this;
|
|
1959
1964
|
return {
|
|
1960
1965
|
/**
|
|
@@ -2044,6 +2049,10 @@ class ReadonlyRepository {
|
|
|
2044
2049
|
});
|
|
2045
2050
|
return this;
|
|
2046
2051
|
},
|
|
2052
|
+
toJSON() {
|
|
2053
|
+
returnAsPlainObjects = true;
|
|
2054
|
+
return this;
|
|
2055
|
+
},
|
|
2047
2056
|
async then(resolve, reject) {
|
|
2048
2057
|
try {
|
|
2049
2058
|
if (typeof where === "string") {
|
|
@@ -2063,9 +2072,10 @@ class ReadonlyRepository {
|
|
|
2063
2072
|
const results = await pool.query(query, params);
|
|
2064
2073
|
const firstResult = results.rows[0];
|
|
2065
2074
|
if (firstResult) {
|
|
2066
|
-
const result = modelInstance._buildInstance(firstResult);
|
|
2075
|
+
const result = returnAsPlainObjects ? modelInstance._buildPlainObject(firstResult) : modelInstance._buildInstance(firstResult);
|
|
2067
2076
|
if (populates.length) {
|
|
2068
|
-
|
|
2077
|
+
const populatesWithFlag = populates.map((pop) => ({ ...pop, asPlainObjects: returnAsPlainObjects }));
|
|
2078
|
+
await modelInstance.populateFields([result], populatesWithFlag);
|
|
2069
2079
|
}
|
|
2070
2080
|
for (const manuallySetField of manuallySetFields) {
|
|
2071
2081
|
result[manuallySetField.propertyName] = manuallySetField.value;
|
|
@@ -2143,6 +2153,8 @@ ${stack ?? ""}`;
|
|
|
2143
2153
|
const populates = [];
|
|
2144
2154
|
const sorts = sort ? this._convertSortsToOrderBy(sort) : [];
|
|
2145
2155
|
const joins = [];
|
|
2156
|
+
let includeCount = false;
|
|
2157
|
+
let returnAsPlainObjects = false;
|
|
2146
2158
|
const modelInstance = this;
|
|
2147
2159
|
return {
|
|
2148
2160
|
/**
|
|
@@ -2253,6 +2265,14 @@ ${stack ?? ""}`;
|
|
|
2253
2265
|
const safePage = Math.max(page, 1);
|
|
2254
2266
|
return this.skip(safePage * paginateLimit - paginateLimit).limit(paginateLimit);
|
|
2255
2267
|
},
|
|
2268
|
+
withCount() {
|
|
2269
|
+
includeCount = true;
|
|
2270
|
+
return this;
|
|
2271
|
+
},
|
|
2272
|
+
toJSON() {
|
|
2273
|
+
returnAsPlainObjects = true;
|
|
2274
|
+
return this;
|
|
2275
|
+
},
|
|
2256
2276
|
async then(resolve, reject) {
|
|
2257
2277
|
try {
|
|
2258
2278
|
if (typeof where === "string") {
|
|
@@ -2266,13 +2286,29 @@ ${stack ?? ""}`;
|
|
|
2266
2286
|
sorts,
|
|
2267
2287
|
skip: skip ?? 0,
|
|
2268
2288
|
limit: limit ?? 0,
|
|
2269
|
-
joins
|
|
2289
|
+
joins,
|
|
2290
|
+
includeCount
|
|
2270
2291
|
});
|
|
2271
2292
|
const pool = poolOverride ?? modelInstance._readonlyPool;
|
|
2272
2293
|
const results = await pool.query(query, params);
|
|
2273
|
-
|
|
2294
|
+
let totalCount = 0;
|
|
2295
|
+
if (includeCount && results.rows.length > 0 && results.rows[0]?.__total_count__ !== void 0) {
|
|
2296
|
+
totalCount = Number(results.rows[0].__total_count__);
|
|
2297
|
+
}
|
|
2298
|
+
const rows = includeCount ? results.rows.map((row) => {
|
|
2299
|
+
const { __total_count__, ...rest } = row;
|
|
2300
|
+
return rest;
|
|
2301
|
+
}) : results.rows;
|
|
2302
|
+
const entities = returnAsPlainObjects ? modelInstance._buildPlainObjects(rows) : modelInstance._buildInstances(rows);
|
|
2274
2303
|
if (populates.length) {
|
|
2275
|
-
|
|
2304
|
+
const populatesWithFlag = populates.map((pop) => ({ ...pop, asPlainObjects: returnAsPlainObjects }));
|
|
2305
|
+
await modelInstance.populateFields(entities, populatesWithFlag);
|
|
2306
|
+
}
|
|
2307
|
+
if (includeCount) {
|
|
2308
|
+
return await resolve({
|
|
2309
|
+
results: entities,
|
|
2310
|
+
totalCount
|
|
2311
|
+
});
|
|
2276
2312
|
}
|
|
2277
2313
|
return await resolve(entities);
|
|
2278
2314
|
} catch (ex) {
|
|
@@ -2388,6 +2424,40 @@ ${stack ?? ""}`;
|
|
|
2388
2424
|
_buildInstances(rows) {
|
|
2389
2425
|
return rows.map((row) => this._buildInstance(row));
|
|
2390
2426
|
}
|
|
2427
|
+
_buildPlainObject(row) {
|
|
2428
|
+
const plainObject = { ...row };
|
|
2429
|
+
for (const name of this._floatProperties) {
|
|
2430
|
+
const originalValue = plainObject[name];
|
|
2431
|
+
if (originalValue != null && typeof originalValue === "string") {
|
|
2432
|
+
try {
|
|
2433
|
+
const value = Number(originalValue);
|
|
2434
|
+
if (Number.isFinite(value) && value.toString() === originalValue) {
|
|
2435
|
+
plainObject[name] = value;
|
|
2436
|
+
}
|
|
2437
|
+
} catch {
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
for (const name of this._intProperties) {
|
|
2442
|
+
const originalValue = plainObject[name];
|
|
2443
|
+
if (originalValue != null && typeof originalValue === "string") {
|
|
2444
|
+
try {
|
|
2445
|
+
const value = Number(originalValue);
|
|
2446
|
+
if (Number.isFinite(value) && value.toString() === originalValue) {
|
|
2447
|
+
const valueAsInt = Math.trunc(value);
|
|
2448
|
+
if (Number.isSafeInteger(valueAsInt)) {
|
|
2449
|
+
plainObject[name] = valueAsInt;
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
2452
|
+
} catch {
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
return plainObject;
|
|
2457
|
+
}
|
|
2458
|
+
_buildPlainObjects(rows) {
|
|
2459
|
+
return rows.map((row) => this._buildPlainObject(row));
|
|
2460
|
+
}
|
|
2391
2461
|
_convertSortsToOrderBy(sorts) {
|
|
2392
2462
|
const result = [];
|
|
2393
2463
|
if (sorts) {
|
|
@@ -2504,12 +2574,13 @@ ${stack ?? ""}`;
|
|
|
2504
2574
|
[populateRepository.model.primaryKeyColumn.propertyName]: Array.from(populateIds),
|
|
2505
2575
|
...populate.where
|
|
2506
2576
|
};
|
|
2507
|
-
const
|
|
2577
|
+
const findQuery = populateRepository.find({
|
|
2508
2578
|
select: populate.select,
|
|
2509
2579
|
where: populateWhere,
|
|
2510
2580
|
sort: populate.sort,
|
|
2511
2581
|
pool: populate.pool
|
|
2512
2582
|
});
|
|
2583
|
+
const populateResults = populate.asPlainObjects ? await findQuery.toJSON() : await findQuery;
|
|
2513
2584
|
const populateResultsById = keyBy(populateResults, populateRepository.model.primaryKeyColumn.propertyName);
|
|
2514
2585
|
for (const entity of entities) {
|
|
2515
2586
|
entity[propertyName] = populateResultsById[entity[propertyName]];
|
|
@@ -2523,7 +2594,7 @@ ${stack ?? ""}`;
|
|
|
2523
2594
|
[column.via]: entityIds,
|
|
2524
2595
|
...populate.where
|
|
2525
2596
|
};
|
|
2526
|
-
const
|
|
2597
|
+
const findQuery = populateRepository.find({
|
|
2527
2598
|
select: populate.select,
|
|
2528
2599
|
where: populateWhere,
|
|
2529
2600
|
sort: populate.sort,
|
|
@@ -2531,6 +2602,7 @@ ${stack ?? ""}`;
|
|
|
2531
2602
|
limit: populate.limit,
|
|
2532
2603
|
pool: populate.pool
|
|
2533
2604
|
});
|
|
2605
|
+
const populateResults = populate.asPlainObjects ? await findQuery.toJSON() : await findQuery;
|
|
2534
2606
|
if (entities.length === 1) {
|
|
2535
2607
|
for (const entity of entities) {
|
|
2536
2608
|
entity[populate.propertyName] = populateResults;
|
|
@@ -2583,7 +2655,7 @@ ${stack ?? ""}`;
|
|
|
2583
2655
|
[populateModelPrimaryKeyPropertyName]: Array.from(populateIds),
|
|
2584
2656
|
...populate.where
|
|
2585
2657
|
};
|
|
2586
|
-
const
|
|
2658
|
+
const findQuery = populateRepository.find({
|
|
2587
2659
|
select: populate.select,
|
|
2588
2660
|
where: populateWhere,
|
|
2589
2661
|
sort: populate.sort,
|
|
@@ -2591,6 +2663,7 @@ ${stack ?? ""}`;
|
|
|
2591
2663
|
limit: populate.limit,
|
|
2592
2664
|
pool: populate.pool
|
|
2593
2665
|
});
|
|
2666
|
+
const populateResults = populate.asPlainObjects ? await findQuery.toJSON() : await findQuery;
|
|
2594
2667
|
const populateResultsById = keyBy(populateResults, populateModelPrimaryKeyPropertyName);
|
|
2595
2668
|
for (const entity of entities) {
|
|
2596
2669
|
const populatedItems = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bigal",
|
|
3
|
-
"version": "15.
|
|
3
|
+
"version": "15.5.0",
|
|
4
4
|
"description": "A fast and lightweight orm for postgres and node.js, written in typescript.",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@types/node": ">=20",
|
|
47
47
|
"chai": "6.2.2",
|
|
48
48
|
"eslint": "9.39.2",
|
|
49
|
-
"eslint-config-decent": "3.1.
|
|
49
|
+
"eslint-config-decent": "3.1.93",
|
|
50
50
|
"husky": "9.1.7",
|
|
51
51
|
"lint-staged": "16.2.7",
|
|
52
52
|
"markdownlint-cli": "0.47.0",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"prettier": "3.7.4",
|
|
57
57
|
"semantic-release": "25.0.2",
|
|
58
58
|
"strict-event-emitter-types": "2.0.0",
|
|
59
|
-
"postgres-pool": "11.0.
|
|
59
|
+
"postgres-pool": "11.0.2",
|
|
60
60
|
"ts-mockito": "2.6.1",
|
|
61
61
|
"ts-node": "10.9.2",
|
|
62
62
|
"typescript": "5.9.3",
|