typeorm 0.3.29 → 0.3.31
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/README.md +2 -2
- package/browser/data-source/BaseDataSourceOptions.d.ts +7 -20
- package/browser/data-source/BaseDataSourceOptions.js.map +1 -1
- package/browser/driver/cockroachdb/CockroachQueryRunner.js +4 -4
- package/browser/driver/cockroachdb/CockroachQueryRunner.js.map +1 -1
- package/browser/driver/sqlserver/SqlServerQueryRunner.js +4 -2
- package/browser/driver/sqlserver/SqlServerQueryRunner.js.map +1 -1
- package/browser/driver/types/InvalidFindOptionsWhereBehavior.d.ts +15 -0
- package/browser/driver/types/InvalidFindOptionsWhereBehavior.js +3 -0
- package/browser/driver/types/InvalidFindOptionsWhereBehavior.js.map +1 -0
- package/browser/entity-manager/EntityManager.d.ts +23 -0
- package/browser/entity-manager/EntityManager.js +79 -102
- package/browser/entity-manager/EntityManager.js.map +1 -1
- package/browser/find-options/operator/JsonContains.d.ts +1 -1
- package/browser/find-options/operator/JsonContains.js.map +1 -1
- package/browser/metadata/types/ClosureTreeOptions.d.ts +1 -0
- package/browser/metadata/types/ClosureTreeOptions.js.map +1 -1
- package/browser/metadata-builder/ClosureJunctionEntityMetadataBuilder.js +6 -2
- package/browser/metadata-builder/ClosureJunctionEntityMetadataBuilder.js.map +1 -1
- package/browser/persistence/SubjectChangedColumnsComputer.js +6 -2
- package/browser/persistence/SubjectChangedColumnsComputer.js.map +1 -1
- package/browser/persistence/SubjectExecutor.js +0 -8
- package/browser/persistence/SubjectExecutor.js.map +1 -1
- package/browser/query-builder/QueryBuilder.js +24 -24
- package/browser/query-builder/QueryBuilder.js.map +1 -1
- package/browser/query-builder/SelectQueryBuilder.d.ts +6 -6
- package/browser/query-builder/SelectQueryBuilder.js +27 -22
- package/browser/query-builder/SelectQueryBuilder.js.map +1 -1
- package/browser/repository/TreeRepository.js +2 -2
- package/browser/repository/TreeRepository.js.map +1 -1
- package/browser/util/OrmUtils.d.ts +21 -1
- package/browser/util/OrmUtils.js +74 -1
- package/browser/util/OrmUtils.js.map +1 -1
- package/commands/MigrationGenerateCommand.d.ts +6 -0
- package/commands/MigrationGenerateCommand.js +13 -2
- package/commands/MigrationGenerateCommand.js.map +1 -1
- package/data-source/BaseDataSourceOptions.d.ts +7 -20
- package/data-source/BaseDataSourceOptions.js.map +1 -1
- package/driver/cockroachdb/CockroachQueryRunner.js +4 -4
- package/driver/cockroachdb/CockroachQueryRunner.js.map +1 -1
- package/driver/sqlserver/SqlServerQueryRunner.js +4 -2
- package/driver/sqlserver/SqlServerQueryRunner.js.map +1 -1
- package/driver/types/InvalidFindOptionsWhereBehavior.d.ts +15 -0
- package/driver/types/InvalidFindOptionsWhereBehavior.js +4 -0
- package/driver/types/InvalidFindOptionsWhereBehavior.js.map +1 -0
- package/entity-manager/EntityManager.d.ts +23 -0
- package/entity-manager/EntityManager.js +79 -102
- package/entity-manager/EntityManager.js.map +1 -1
- package/find-options/operator/JsonContains.d.ts +1 -1
- package/find-options/operator/JsonContains.js.map +1 -1
- package/metadata/types/ClosureTreeOptions.d.ts +1 -0
- package/metadata/types/ClosureTreeOptions.js.map +1 -1
- package/metadata-builder/ClosureJunctionEntityMetadataBuilder.js +6 -2
- package/metadata-builder/ClosureJunctionEntityMetadataBuilder.js.map +1 -1
- package/package.json +23 -24
- package/persistence/SubjectChangedColumnsComputer.js +6 -2
- package/persistence/SubjectChangedColumnsComputer.js.map +1 -1
- package/persistence/SubjectExecutor.js +0 -8
- package/persistence/SubjectExecutor.js.map +1 -1
- package/query-builder/QueryBuilder.js +24 -24
- package/query-builder/QueryBuilder.js.map +1 -1
- package/query-builder/SelectQueryBuilder.d.ts +6 -6
- package/query-builder/SelectQueryBuilder.js +27 -22
- package/query-builder/SelectQueryBuilder.js.map +1 -1
- package/repository/TreeRepository.js +2 -2
- package/repository/TreeRepository.js.map +1 -1
- package/util/OrmUtils.d.ts +21 -1
- package/util/OrmUtils.js +74 -1
- package/util/OrmUtils.js.map +1 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type InvalidFindOptionsWhereBehavior = {
|
|
2
|
+
/**
|
|
3
|
+
* How to handle null values in where conditions.
|
|
4
|
+
* - 'ignore': Skip null properties (default)
|
|
5
|
+
* - 'sql-null': Transform null to SQL NULL
|
|
6
|
+
* - 'throw': Throw an error when null is encountered
|
|
7
|
+
*/
|
|
8
|
+
readonly null?: "ignore" | "sql-null" | "throw";
|
|
9
|
+
/**
|
|
10
|
+
* How to handle undefined values in where conditions.
|
|
11
|
+
* - 'ignore': Skip undefined properties (default)
|
|
12
|
+
* - 'throw': Throw an error when undefined is encountered
|
|
13
|
+
*/
|
|
14
|
+
readonly undefined?: "ignore" | "throw";
|
|
15
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/driver/types/InvalidFindOptionsWhereBehavior.ts"],"names":[],"mappings":"","file":"InvalidFindOptionsWhereBehavior.js","sourcesContent":["export type InvalidFindOptionsWhereBehavior = {\n /**\n * How to handle null values in where conditions.\n * - 'ignore': Skip null properties (default)\n * - 'sql-null': Transform null to SQL NULL\n * - 'throw': Throw an error when null is encountered\n */\n readonly null?: \"ignore\" | \"sql-null\" | \"throw\"\n\n /**\n * How to handle undefined values in where conditions.\n * - 'ignore': Skip undefined properties (default)\n * - 'throw': Throw an error when undefined is encountered\n */\n readonly undefined?: \"ignore\" | \"throw\"\n}\n"],"sourceRoot":"../.."}
|
|
@@ -212,6 +212,23 @@ export declare class EntityManager {
|
|
|
212
212
|
*/
|
|
213
213
|
insert<Entity extends ObjectLiteral>(target: EntityTarget<Entity>, entity: QueryDeepPartialEntity<Entity> | QueryDeepPartialEntity<Entity>[]): Promise<InsertResult>;
|
|
214
214
|
upsert<Entity extends ObjectLiteral>(target: EntityTarget<Entity>, entityOrEntities: QueryDeepPartialEntity<Entity> | QueryDeepPartialEntity<Entity>[], conflictPathsOrOptions: string[] | UpsertOptions<Entity>): Promise<InsertResult>;
|
|
215
|
+
/**
|
|
216
|
+
* Shared by update/delete/softDelete/restore. Object criteria is normalized
|
|
217
|
+
* via {@link OrmUtils.normalizeWhereCriteria}, then rejected if it would
|
|
218
|
+
* produce no predicate and therefore render as an always-true `WHERE 1=1` —
|
|
219
|
+
* an empty object or array, an empty OR-branch, a bare primitive inside an
|
|
220
|
+
* OR-array, or a keyless object. Primitive id criteria is returned untouched
|
|
221
|
+
* for `whereInIds` (rejected only when wholly empty).
|
|
222
|
+
*
|
|
223
|
+
* @param criteria the raw criteria passed to the operation
|
|
224
|
+
* @param methodName the calling method, used in the error message
|
|
225
|
+
* @returns the criteria to build with, and whether to execute it via
|
|
226
|
+
* `whereInIds` (primitive) or `where` (object)
|
|
227
|
+
*/
|
|
228
|
+
protected normalizeAndValidateWhereCriteria(criteria: any, methodName: string): {
|
|
229
|
+
criteria: any;
|
|
230
|
+
isPrimitive: boolean;
|
|
231
|
+
};
|
|
215
232
|
/**
|
|
216
233
|
* Updates entity partially. Entity can be found by a given condition(s).
|
|
217
234
|
* Unlike save method executes a primitive operation without cascades, relations and other operations included.
|
|
@@ -372,6 +389,12 @@ export declare class EntityManager {
|
|
|
372
389
|
* Decrements some column by provided value of the entities matched given conditions.
|
|
373
390
|
*/
|
|
374
391
|
decrement<Entity extends ObjectLiteral>(entityClass: EntityTarget<Entity>, conditions: any, propertyPath: string, value: number | string): Promise<UpdateResult>;
|
|
392
|
+
/**
|
|
393
|
+
* Shared implementation of {@link increment} and {@link decrement}: builds a
|
|
394
|
+
* `column = column +/- value` UPDATE and delegates execution to {@link update},
|
|
395
|
+
* so the criteria handling stays aligned with the other write methods.
|
|
396
|
+
*/
|
|
397
|
+
protected incrementOrDecrementBy<Entity extends ObjectLiteral>(operation: "increment" | "decrement", entityClass: EntityTarget<Entity>, conditions: any, propertyPath: string, value: number | string): Promise<UpdateResult>;
|
|
375
398
|
/**
|
|
376
399
|
* Gets repository for the given entity class or name.
|
|
377
400
|
* If single database connection mode is used, then repository is obtained from the
|
|
@@ -339,6 +339,51 @@ class EntityManager {
|
|
|
339
339
|
}
|
|
340
340
|
return qb.execute();
|
|
341
341
|
}
|
|
342
|
+
/**
|
|
343
|
+
* Shared by update/delete/softDelete/restore. Object criteria is normalized
|
|
344
|
+
* via {@link OrmUtils.normalizeWhereCriteria}, then rejected if it would
|
|
345
|
+
* produce no predicate and therefore render as an always-true `WHERE 1=1` —
|
|
346
|
+
* an empty object or array, an empty OR-branch, a bare primitive inside an
|
|
347
|
+
* OR-array, or a keyless object. Primitive id criteria is returned untouched
|
|
348
|
+
* for `whereInIds` (rejected only when wholly empty).
|
|
349
|
+
*
|
|
350
|
+
* @param criteria the raw criteria passed to the operation
|
|
351
|
+
* @param methodName the calling method, used in the error message
|
|
352
|
+
* @returns the criteria to build with, and whether to execute it via
|
|
353
|
+
* `whereInIds` (primitive) or `where` (object)
|
|
354
|
+
*/
|
|
355
|
+
normalizeAndValidateWhereCriteria(criteria, methodName) {
|
|
356
|
+
const rejectEmpty = () => {
|
|
357
|
+
throw new error_1.TypeORMError(`Empty criteria(s) are not allowed for the ${methodName} method.`);
|
|
358
|
+
};
|
|
359
|
+
if (OrmUtils_1.OrmUtils.isPrimitiveCriteria(criteria)) {
|
|
360
|
+
if (OrmUtils_1.OrmUtils.isCriteriaNullOrEmpty(criteria))
|
|
361
|
+
rejectEmpty();
|
|
362
|
+
return { criteria, isPrimitive: true };
|
|
363
|
+
}
|
|
364
|
+
const normalizedCriteria = OrmUtils_1.OrmUtils.normalizeWhereCriteria(criteria, this.connection.options.invalidWhereValuesBehavior);
|
|
365
|
+
// On the object-criteria path, `.where()` builds a predicate only from
|
|
366
|
+
// an object's own keys. Anything else yields an empty predicate list
|
|
367
|
+
// that renders as an always-true `1=1`, so a criterion is unsafe unless
|
|
368
|
+
// it is a non-empty object. This must reject:
|
|
369
|
+
// - primitives (a bare number/string in a mixed OR-array like
|
|
370
|
+
// `[1, { id: 2 }]` — `.where(1)` produces no predicate),
|
|
371
|
+
// - empty plain objects (`{}`), empty arrays (`[]`), and
|
|
372
|
+
// - empty non-plain objects, e.g. an empty entity instance
|
|
373
|
+
// (`new Post()`), which isCriteriaNullOrEmpty does not catch.
|
|
374
|
+
// Value-type criteria (Date, Buffer) execute via the primitive branch
|
|
375
|
+
// and never reach here.
|
|
376
|
+
const rendersNoPredicate = (value) => value === null ||
|
|
377
|
+
typeof value !== "object" ||
|
|
378
|
+
Object.keys(value).length === 0;
|
|
379
|
+
const isEmpty = Array.isArray(normalizedCriteria)
|
|
380
|
+
? normalizedCriteria.length === 0 ||
|
|
381
|
+
normalizedCriteria.some(rendersNoPredicate)
|
|
382
|
+
: rendersNoPredicate(normalizedCriteria);
|
|
383
|
+
if (isEmpty)
|
|
384
|
+
rejectEmpty();
|
|
385
|
+
return { criteria: normalizedCriteria, isPrimitive: false };
|
|
386
|
+
}
|
|
342
387
|
/**
|
|
343
388
|
* Updates entity partially. Entity can be found by a given condition(s).
|
|
344
389
|
* Unlike save method executes a primitive operation without cascades, relations and other operations included.
|
|
@@ -346,31 +391,19 @@ class EntityManager {
|
|
|
346
391
|
* Does not check if entity exist in the database.
|
|
347
392
|
* Condition(s) cannot be empty.
|
|
348
393
|
*/
|
|
349
|
-
update(target, criteria, partialEntity, options) {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
if (OrmUtils_1.OrmUtils.isPrimitiveCriteria(criteria)) {
|
|
355
|
-
const qb = this.createQueryBuilder()
|
|
356
|
-
.update(target)
|
|
357
|
-
.set(partialEntity)
|
|
358
|
-
.whereInIds(criteria);
|
|
359
|
-
if (options?.returning !== undefined) {
|
|
360
|
-
qb.returning(options.returning);
|
|
361
|
-
}
|
|
362
|
-
return qb.execute();
|
|
394
|
+
async update(target, criteria, partialEntity, options) {
|
|
395
|
+
const { criteria: whereCriteria, isPrimitive } = this.normalizeAndValidateWhereCriteria(criteria, "update");
|
|
396
|
+
const qb = this.createQueryBuilder().update(target).set(partialEntity);
|
|
397
|
+
if (isPrimitive) {
|
|
398
|
+
qb.whereInIds(whereCriteria);
|
|
363
399
|
}
|
|
364
400
|
else {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
if (options?.returning !== undefined) {
|
|
370
|
-
qb.returning(options.returning);
|
|
371
|
-
}
|
|
372
|
-
return qb.execute();
|
|
401
|
+
qb.where(whereCriteria);
|
|
402
|
+
}
|
|
403
|
+
if (options?.returning !== undefined) {
|
|
404
|
+
qb.returning(options.returning);
|
|
373
405
|
}
|
|
406
|
+
return qb.execute();
|
|
374
407
|
}
|
|
375
408
|
/**
|
|
376
409
|
* Updates all entities of target type, setting fields from supplied partial entity.
|
|
@@ -393,25 +426,10 @@ class EntityManager {
|
|
|
393
426
|
* Does not check if entity exist in the database.
|
|
394
427
|
* Condition(s) cannot be empty.
|
|
395
428
|
*/
|
|
396
|
-
delete(targetOrEntity, criteria) {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
}
|
|
401
|
-
if (OrmUtils_1.OrmUtils.isPrimitiveCriteria(criteria)) {
|
|
402
|
-
return this.createQueryBuilder()
|
|
403
|
-
.delete()
|
|
404
|
-
.from(targetOrEntity)
|
|
405
|
-
.whereInIds(criteria)
|
|
406
|
-
.execute();
|
|
407
|
-
}
|
|
408
|
-
else {
|
|
409
|
-
return this.createQueryBuilder()
|
|
410
|
-
.delete()
|
|
411
|
-
.from(targetOrEntity)
|
|
412
|
-
.where(criteria)
|
|
413
|
-
.execute();
|
|
414
|
-
}
|
|
429
|
+
async delete(targetOrEntity, criteria) {
|
|
430
|
+
const { criteria: whereCriteria, isPrimitive } = this.normalizeAndValidateWhereCriteria(criteria, "delete");
|
|
431
|
+
const qb = this.createQueryBuilder().delete().from(targetOrEntity);
|
|
432
|
+
return (isPrimitive ? qb.whereInIds(whereCriteria) : qb.where(whereCriteria)).execute();
|
|
415
433
|
}
|
|
416
434
|
/**
|
|
417
435
|
* Deletes all entities of target type.
|
|
@@ -430,25 +448,10 @@ class EntityManager {
|
|
|
430
448
|
* Does not check if entity exist in the database.
|
|
431
449
|
* Condition(s) cannot be empty.
|
|
432
450
|
*/
|
|
433
|
-
softDelete(targetOrEntity, criteria) {
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
}
|
|
438
|
-
if (OrmUtils_1.OrmUtils.isPrimitiveCriteria(criteria)) {
|
|
439
|
-
return this.createQueryBuilder()
|
|
440
|
-
.softDelete()
|
|
441
|
-
.from(targetOrEntity)
|
|
442
|
-
.whereInIds(criteria)
|
|
443
|
-
.execute();
|
|
444
|
-
}
|
|
445
|
-
else {
|
|
446
|
-
return this.createQueryBuilder()
|
|
447
|
-
.softDelete()
|
|
448
|
-
.from(targetOrEntity)
|
|
449
|
-
.where(criteria)
|
|
450
|
-
.execute();
|
|
451
|
-
}
|
|
451
|
+
async softDelete(targetOrEntity, criteria) {
|
|
452
|
+
const { criteria: whereCriteria, isPrimitive } = this.normalizeAndValidateWhereCriteria(criteria, "softDelete");
|
|
453
|
+
const qb = this.createQueryBuilder().softDelete().from(targetOrEntity);
|
|
454
|
+
return (isPrimitive ? qb.whereInIds(whereCriteria) : qb.where(whereCriteria)).execute();
|
|
452
455
|
}
|
|
453
456
|
/**
|
|
454
457
|
* Restores entities by a given condition(s).
|
|
@@ -457,25 +460,10 @@ class EntityManager {
|
|
|
457
460
|
* Does not check if entity exist in the database.
|
|
458
461
|
* Condition(s) cannot be empty.
|
|
459
462
|
*/
|
|
460
|
-
restore(targetOrEntity, criteria) {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
}
|
|
465
|
-
if (OrmUtils_1.OrmUtils.isPrimitiveCriteria(criteria)) {
|
|
466
|
-
return this.createQueryBuilder()
|
|
467
|
-
.restore()
|
|
468
|
-
.from(targetOrEntity)
|
|
469
|
-
.whereInIds(criteria)
|
|
470
|
-
.execute();
|
|
471
|
-
}
|
|
472
|
-
else {
|
|
473
|
-
return this.createQueryBuilder()
|
|
474
|
-
.restore()
|
|
475
|
-
.from(targetOrEntity)
|
|
476
|
-
.where(criteria)
|
|
477
|
-
.execute();
|
|
478
|
-
}
|
|
463
|
+
async restore(targetOrEntity, criteria) {
|
|
464
|
+
const { criteria: whereCriteria, isPrimitive } = this.normalizeAndValidateWhereCriteria(criteria, "restore");
|
|
465
|
+
const qb = this.createQueryBuilder().restore().from(targetOrEntity);
|
|
466
|
+
return (isPrimitive ? qb.whereInIds(whereCriteria) : qb.where(whereCriteria)).execute();
|
|
479
467
|
}
|
|
480
468
|
/**
|
|
481
469
|
* Checks whether any entity exists with the given options.
|
|
@@ -717,45 +705,34 @@ class EntityManager {
|
|
|
717
705
|
* Increments some column by provided value of the entities matched given conditions.
|
|
718
706
|
*/
|
|
719
707
|
async increment(entityClass, conditions, propertyPath, value) {
|
|
720
|
-
|
|
721
|
-
const column = metadata.findColumnWithPropertyPath(propertyPath);
|
|
722
|
-
if (!column)
|
|
723
|
-
throw new error_1.TypeORMError(`Column ${propertyPath} was not found in ${metadata.targetName} entity.`);
|
|
724
|
-
if (isNaN(Number(value)))
|
|
725
|
-
throw new error_1.TypeORMError(`Value "${value}" is not a number.`);
|
|
726
|
-
// convert possible embedded path "social.likes" into object { social: { like: () => value } }
|
|
727
|
-
const values = propertyPath
|
|
728
|
-
.split(".")
|
|
729
|
-
.reduceRight((value, key) => ({ [key]: value }), () => this.connection.driver.escape(column.databaseName) +
|
|
730
|
-
" + " +
|
|
731
|
-
value);
|
|
732
|
-
return this.createQueryBuilder(entityClass, "entity")
|
|
733
|
-
.update(entityClass)
|
|
734
|
-
.set(values)
|
|
735
|
-
.where(conditions)
|
|
736
|
-
.execute();
|
|
708
|
+
return this.incrementOrDecrementBy("increment", entityClass, conditions, propertyPath, value);
|
|
737
709
|
}
|
|
738
710
|
/**
|
|
739
711
|
* Decrements some column by provided value of the entities matched given conditions.
|
|
740
712
|
*/
|
|
741
713
|
async decrement(entityClass, conditions, propertyPath, value) {
|
|
714
|
+
return this.incrementOrDecrementBy("decrement", entityClass, conditions, propertyPath, value);
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* Shared implementation of {@link increment} and {@link decrement}: builds a
|
|
718
|
+
* `column = column +/- value` UPDATE and delegates execution to {@link update},
|
|
719
|
+
* so the criteria handling stays aligned with the other write methods.
|
|
720
|
+
*/
|
|
721
|
+
incrementOrDecrementBy(operation, entityClass, conditions, propertyPath, value) {
|
|
742
722
|
const metadata = this.connection.getMetadata(entityClass);
|
|
743
723
|
const column = metadata.findColumnWithPropertyPath(propertyPath);
|
|
744
724
|
if (!column)
|
|
745
725
|
throw new error_1.TypeORMError(`Column ${propertyPath} was not found in ${metadata.targetName} entity.`);
|
|
746
726
|
if (isNaN(Number(value)))
|
|
747
727
|
throw new error_1.TypeORMError(`Value "${value}" is not a number.`);
|
|
728
|
+
const operator = operation === "increment" ? "+" : "-";
|
|
748
729
|
// convert possible embedded path "social.likes" into object { social: { like: () => value } }
|
|
749
730
|
const values = propertyPath
|
|
750
731
|
.split(".")
|
|
751
732
|
.reduceRight((value, key) => ({ [key]: value }), () => this.connection.driver.escape(column.databaseName) +
|
|
752
|
-
|
|
733
|
+
` ${operator} ` +
|
|
753
734
|
value);
|
|
754
|
-
return this.
|
|
755
|
-
.update(entityClass)
|
|
756
|
-
.set(values)
|
|
757
|
-
.where(conditions)
|
|
758
|
-
.execute();
|
|
735
|
+
return this.update(entityClass, conditions, values);
|
|
759
736
|
}
|
|
760
737
|
/**
|
|
761
738
|
* Gets repository for the given entity class or name.
|