diff --git a/CHANGELOG.md b/CHANGELOG.md index 5088b4b28..069c00ccc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,12 +22,13 @@ each for its own `findOne*` or `find*` methods ### NEW FEATURES * added `mongodb` support -* entity now can be saved partially within `persist` method +* entity now can be saved partially within `update` method * added prefix support to embeddeds ### BUG FIXES * fixes [#285](https://github.com/typeorm/typeorm/issues/285) - issue when cli commands rise `CannotCloseNotConnectedError` +* fixes [#309](https://github.com/typeorm/typeorm/issues/309) - issue when `andHaving` didn't work without calling `having` on `QueryBuilder` # 0.0.9 (latest) diff --git a/sample/sample11-all-types-entity/app.ts b/sample/sample11-all-types-entity/app.ts index 1294f7558..3421ef21d 100644 --- a/sample/sample11-all-types-entity/app.ts +++ b/sample/sample11-all-types-entity/app.ts @@ -86,7 +86,7 @@ createConnection(options).then(connection => { .then(entity => { console.log("Entity is loaded: ", entity); console.log("Now remove it"); - return postRepository.remove(entity); + return postRepository.remove(entity!); }) .then(entity => { console.log("Entity has been removed"); diff --git a/sample/sample11-all-types-entity/entity/EverythingEntity.ts b/sample/sample11-all-types-entity/entity/EverythingEntity.ts index a9dbb6829..4f8479b86 100644 --- a/sample/sample11-all-types-entity/entity/EverythingEntity.ts +++ b/sample/sample11-all-types-entity/entity/EverythingEntity.ts @@ -60,7 +60,7 @@ export class EverythingEntity { jsonColumn: any; @Column() - alsoJson: Object; + alsoJson: any; @Column("simple_array") simpleArrayColumn: string[]; diff --git a/sample/sample18-lazy-relations/app.ts b/sample/sample18-lazy-relations/app.ts index 93dc37d65..f09da2a57 100644 --- a/sample/sample18-lazy-relations/app.ts +++ b/sample/sample18-lazy-relations/app.ts @@ -49,12 +49,12 @@ createConnection(options).then(connection => { return authorRepository.persist(author); }) - .then(author => { + .then((author: any) => { // temporary console.log("Author with a new post has been saved. Lets try to update post in the author"); - - return author.posts.then(posts => { - posts[0].title = "should be updated second post"; - return authorRepository.persist(author); + + return author.posts!.then((posts: any) => { // temporary + posts![0]!.title = "should be updated second post"; + return authorRepository.persist(author!); }); }) .then(updatedAuthor => { @@ -97,8 +97,8 @@ createConnection(options).then(connection => { .then(posts => { console.log("Post with categories are loaded: ", posts); console.log("Lets remove one of the categories: "); - return posts[0].categories.then(categories => { - categories.splice(0, 1); + return posts[0].categories.then((categories: any) => { // temporary + categories!.splice(0, 1); // console.log(posts[0]); return postRepository.persist(posts[0]); }); diff --git a/sample/sample23-nested-joins/app.ts b/sample/sample23-nested-joins/app.ts index aca581136..c0569972b 100644 --- a/sample/sample23-nested-joins/app.ts +++ b/sample/sample23-nested-joins/app.ts @@ -78,9 +78,9 @@ createConnection(options).then(connection => { console.log("Lets update a post - return old author back:"); console.log("updating with: ", author); - loadedPost.title = "Umed's post"; - loadedPost.author = author; - return postRepository.persist(loadedPost); + loadedPost!.title = "Umed's post"; + loadedPost!.author = author; + return postRepository.persist(loadedPost!); }) .then(updatedPost => { return postRepository diff --git a/sample/sample26-embedded-tables/app.ts b/sample/sample26-embedded-tables/app.ts index 4eb3c7bf3..94db3c021 100644 --- a/sample/sample26-embedded-tables/app.ts +++ b/sample/sample26-embedded-tables/app.ts @@ -44,10 +44,10 @@ createConnection(options).then(connection => { .then(loadedQuestion => { console.log("question has been loaded: ", loadedQuestion); - loadedQuestion.counters.commentCount = 7; - loadedQuestion.counters.metadata = "#updated question"; + loadedQuestion!.counters.commentCount = 7; + loadedQuestion!.counters.metadata = "#updated question"; - return questionRepository.persist(loadedQuestion); + return questionRepository.persist(loadedQuestion!); }) .then(updatedQuestion => { console.log("question has been updated: ", updatedQuestion); diff --git a/sample/sample5-subscribers/app.ts b/sample/sample5-subscribers/app.ts index 5cef5f1ab..24e4229f7 100644 --- a/sample/sample5-subscribers/app.ts +++ b/sample/sample5-subscribers/app.ts @@ -52,15 +52,15 @@ createConnection(options).then(connection => { .createQueryBuilder("p") .leftJoinAndSelect("p.author", "author") .leftJoinAndSelect("p.categories", "categories") - .where("p.id = :id", { id: loadedPost.id }) + .where("p.id = :id", { id: loadedPost!.id }) .getOne(); }) .then(loadedPost => { console.log("---------------------------"); console.log("load finished. Now lets update entity"); - loadedPost.text = "post updated"; - loadedPost.author.name = "Bakha"; - return postRepository.persist(loadedPost); + loadedPost!.text = "post updated"; + loadedPost!.author.name = "Bakha"; + return postRepository.persist(loadedPost!); }) .then(loadedPost => { console.log("---------------------------"); diff --git a/sample/sample9-entity-listeners/app.ts b/sample/sample9-entity-listeners/app.ts index 37fcbb231..d84392cdf 100644 --- a/sample/sample9-entity-listeners/app.ts +++ b/sample/sample9-entity-listeners/app.ts @@ -44,22 +44,22 @@ createConnection(options).then(connection => { return postRepository.findOneById(post.id); }) .then(loadedPost => { - console.log("post is loaded. Its uid is " + loadedPost.uid); + console.log("post is loaded. Its uid is " + loadedPost!.uid); console.log("Lets now load it with relations."); console.log("---------------------------"); return postRepository .createQueryBuilder("p") .leftJoinAndSelect("p.author", "author") .leftJoinAndSelect("p.categories", "categories") - .where("p.id = :id", { id: loadedPost.id }) + .where("p.id = :id", { id: loadedPost!.id }) .getOne(); }) .then(loadedPost => { console.log("load finished. Now lets update entity"); console.log("---------------------------"); - loadedPost.text = "post updated"; - loadedPost.author.name = "Bakha"; - return postRepository.persist(loadedPost); + loadedPost!.text = "post updated"; + loadedPost!.author.name = "Bakha"; + return postRepository.persist(loadedPost!); }) .then(loadedPost => { console.log("update finished. Now lets remove entity"); diff --git a/src/common/DeepPartial.ts b/src/common/DeepPartial.ts index 6ff37013b..32bcf5186 100644 --- a/src/common/DeepPartial.ts +++ b/src/common/DeepPartial.ts @@ -1,3 +1,6 @@ +/** + * Same as Partial but goes deeper and makes Partial all its properties and sub-properties. + */ export type DeepPartial = { - readonly [P in keyof T]?: DeepPartial; + [P in keyof T]?: DeepPartial; }; diff --git a/src/decorator/columns/PrimaryGeneratedColumn.ts b/src/decorator/columns/PrimaryGeneratedColumn.ts index 8c31127f2..778d0ab23 100644 --- a/src/decorator/columns/PrimaryGeneratedColumn.ts +++ b/src/decorator/columns/PrimaryGeneratedColumn.ts @@ -4,6 +4,8 @@ import {getMetadataArgsStorage} from "../../index"; import {PrimaryColumnCannotBeNullableError} from "../error/PrimaryColumnCannotBeNullableError"; import {ColumnMetadataArgs} from "../../metadata-args/ColumnMetadataArgs"; +// todo: add overloads for PrimaryGeneratedColumn(generationType: "sequence"|"uuid" = "sequence", options?: ColumnOptions) + /** * Column decorator is used to mark a specific class property as a table column. * Only properties decorated with this decorator will be persisted to the database when entity be saved. diff --git a/src/entity-manager/BaseEntityManager.ts b/src/entity-manager/BaseEntityManager.ts index 9c200cf22..f1cdcaf5a 100644 --- a/src/entity-manager/BaseEntityManager.ts +++ b/src/entity-manager/BaseEntityManager.ts @@ -174,22 +174,41 @@ export abstract class BaseEntityManager { /** * Checks if entity has an id. */ - hasId(entity: Object): boolean; + hasId(entity: any): boolean; /** * Checks if entity of given schema name has an id. */ - hasId(target: string, entity: Object): boolean; + hasId(target: string, entity: any): boolean; /** * Checks if entity has an id by its Function type or schema name. */ - hasId(targetOrEntity: Object|string, maybeEntity?: Object): boolean { + hasId(targetOrEntity: any|string, maybeEntity?: any): boolean { const target = arguments.length === 2 ? targetOrEntity : targetOrEntity.constructor; - const entity = arguments.length === 2 ? maybeEntity : targetOrEntity; + const entity = arguments.length === 2 ? maybeEntity : targetOrEntity; return this.getRepository(target as any).hasId(entity); } + /** + * Gets entity mixed id. + */ + getId(entity: any): any; + + /** + * Gets entity mixed id. + */ + getId(target: string, entity: any): any; + + /** + * Gets entity mixed id. + */ + getId(targetOrEntity: any|string, maybeEntity?: any): any { + const target = arguments.length === 2 ? targetOrEntity : targetOrEntity.constructor; + const entity = arguments.length === 2 ? maybeEntity : targetOrEntity; + return this.getRepository(target as any).getId(entity); + } + /** * Creates a new query builder that can be used to build an sql query. */ diff --git a/src/entity-manager/EntityManager.ts b/src/entity-manager/EntityManager.ts index 32d751705..a4151c956 100644 --- a/src/entity-manager/EntityManager.ts +++ b/src/entity-manager/EntityManager.ts @@ -6,6 +6,9 @@ import {QueryRunnerProviderAlreadyReleasedError} from "../query-runner/error/Que import {QueryRunnerProvider} from "../query-runner/QueryRunnerProvider"; import {ObjectLiteral} from "../common/ObjectLiteral"; import {FindOneOptions} from "../find-options/FindOneOptions"; +import {DeepPartial} from "../common/DeepPartial"; +import {RemoveOptions} from "../repository/RemoveOptions"; +import {PersistOptions} from "../repository/PersistOptions"; /** * Entity manager supposed to work with any entity, automatically find its repository and call its methods, @@ -29,60 +32,87 @@ export class EntityManager extends BaseEntityManager { * Persists (saves) all given entities in the database. * If entities do not exist in the database then inserts, otherwise updates. */ - persist(entity: Entity): Promise; + persist(entity: Entity, options?: PersistOptions): Promise; /** * Persists (saves) all given entities in the database. * If entities do not exist in the database then inserts, otherwise updates. */ - persist(targetOrEntity: Function, entity: Entity): Promise; + persist(targetOrEntity: Function, entity: Entity, options?: PersistOptions): Promise; /** * Persists (saves) all given entities in the database. * If entities do not exist in the database then inserts, otherwise updates. */ - persist(targetOrEntity: string, entity: Entity): Promise; + persist(targetOrEntity: string, entity: Entity, options?: PersistOptions): Promise; /** * Persists (saves) all given entities in the database. * If entities do not exist in the database then inserts, otherwise updates. */ - persist(entities: Entity[]): Promise; + persist(entities: Entity[], options?: PersistOptions): Promise; /** * Persists (saves) all given entities in the database. * If entities do not exist in the database then inserts, otherwise updates. */ - persist(targetOrEntity: Function, entities: Entity[]): Promise; + persist(targetOrEntity: Function, entities: Entity[], options?: PersistOptions): Promise; /** * Persists (saves) all given entities in the database. * If entities do not exist in the database then inserts, otherwise updates. */ - persist(targetOrEntity: string, entities: Entity[]): Promise; + persist(targetOrEntity: string, entities: Entity[], options?: PersistOptions): Promise; /** * Persists (saves) a given entity in the database. */ - persist(targetOrEntity: (Entity|Entity[])|Function|string, maybeEntity?: Entity|Entity[]): Promise { + persist(targetOrEntity: (Entity|Entity[])|Function|string, maybeEntity?: Entity|Entity[], options?: PersistOptions): Promise { const target = arguments.length === 2 ? maybeEntity as Entity|Entity[] : targetOrEntity as Function|string; const entity = arguments.length === 2 ? maybeEntity as Entity|Entity[] : targetOrEntity as Entity|Entity[]; return Promise.resolve().then(() => { // we MUST call "fake" resolve here to make sure all properties of lazily loaded properties are resolved. if (typeof target === "string") { - return this.getRepository(target).persist(entity); + return this.getRepository(target).persist(entity, options); } else { + // todo: throw exception if constructor in target is not set if (target instanceof Array) { if (target.length === 0) return Promise.resolve(target); - return this.getRepository(target[0].constructor).persist(entity as Entity[]); + return this.getRepository(target[0].constructor).persist(entity as Entity[], options); } else { - return this.getRepository(target.constructor).persist(entity as Entity); + return this.getRepository(target.constructor).persist(entity as Entity, options); } } }); } + /** + * Updates entity partially. Entity can be found by a given conditions. + */ + async update(target: Function|string, conditions: Partial, partialEntity: DeepPartial, options?: PersistOptions): Promise; + + /** + * Updates entity partially. Entity can be found by a given find options. + */ + async update(target: Function|string, findOptions: FindOneOptions, partialEntity: DeepPartial, options?: PersistOptions): Promise; + + /** + * Updates entity partially. Entity can be found by a given conditions. + */ + async update(target: Function|string, conditionsOrFindOptions: Partial|FindOneOptions, partialEntity: DeepPartial, options?: PersistOptions): Promise { + return this.getRepository(target as any) + .update(conditionsOrFindOptions as any, partialEntity, options); + } + + /** + * Updates entity partially. Entity will be found by a given id. + */ + async updateById(target: Function|string, id: any, partialEntity: DeepPartial, options?: PersistOptions): Promise { + return this.getRepository(target as any) + .updateById(id, partialEntity, options); + } + /** * Removes a given entity from the database. */ @@ -91,45 +121,53 @@ export class EntityManager extends BaseEntityManager { /** * Removes a given entity from the database. */ - remove(targetOrEntity: Function, entity: Entity): Promise; + remove(targetOrEntity: Function, entity: Entity, options?: RemoveOptions): Promise; /** * Removes a given entity from the database. */ - remove(targetOrEntity: string, entity: Entity): Promise; + remove(targetOrEntity: string, entity: Entity, options?: RemoveOptions): Promise; /** * Removes a given entity from the database. */ - remove(entity: Entity[]): Promise; + remove(entity: Entity[], options?: RemoveOptions): Promise; /** * Removes a given entity from the database. */ - remove(targetOrEntity: Function, entity: Entity[]): Promise; + remove(targetOrEntity: Function, entity: Entity[], options?: RemoveOptions): Promise; /** * Removes a given entity from the database. */ - remove(targetOrEntity: string, entity: Entity[]): Promise; + remove(targetOrEntity: string, entity: Entity[], options?: RemoveOptions): Promise; /** * Removes a given entity from the database. */ - remove(targetOrEntity: (Entity|Entity[])|Function|string, maybeEntity?: Entity|Entity[]): Promise { + remove(targetOrEntity: (Entity|Entity[])|Function|string, maybeEntity?: Entity|Entity[], options?: RemoveOptions): Promise { const target = arguments.length === 2 ? maybeEntity as Entity|Entity[] : targetOrEntity as Function|string; const entity = arguments.length === 2 ? maybeEntity as Entity|Entity[] : targetOrEntity as Entity|Entity[]; if (typeof target === "string") { - return this.getRepository(target).remove(entity); + return this.getRepository(target).remove(entity, options); } else { + // todo: throw exception if constructor in target is not set if (target instanceof Array) { - return this.getRepository(target[0].constructor).remove(entity as Entity[]); + return this.getRepository(target[0].constructor).remove(entity as Entity[], options); } else { - return this.getRepository(target.constructor).remove(entity as Entity); + return this.getRepository(target.constructor).remove(entity as Entity, options); } } } + /** + * Removes entity by a given entity id. + */ + async removeById(targetOrEntity: Function|string, id: any, options?: RemoveOptions): Promise { + return this.getRepository(targetOrEntity as any).removeById(id, options); + } + /** * Counts entities that match given options. */ diff --git a/src/repository/PersistOptions.ts b/src/repository/PersistOptions.ts new file mode 100644 index 000000000..5868115cd --- /dev/null +++ b/src/repository/PersistOptions.ts @@ -0,0 +1,12 @@ +/** + * Special options passed to Repository#persist method. + */ +export interface PersistOptions { + + /** + * Additional data to be passed with persist method. + * This data can be used in subscribers then. + */ + data?: any; + +} \ No newline at end of file diff --git a/src/repository/RemoveOptions.ts b/src/repository/RemoveOptions.ts new file mode 100644 index 000000000..122ba6392 --- /dev/null +++ b/src/repository/RemoveOptions.ts @@ -0,0 +1,12 @@ +/** + * Special options passed to Repository#remove method. + */ +export interface RemoveOptions { + + /** + * Additional data to be passed with remove method. + * This data can be used in subscribers then. + */ + data?: any; + +} \ No newline at end of file diff --git a/src/repository/Repository.ts b/src/repository/Repository.ts index cb8837d53..64ed006a4 100644 --- a/src/repository/Repository.ts +++ b/src/repository/Repository.ts @@ -11,6 +11,8 @@ import {SubjectOperationExecutor} from "../persistence/SubjectOperationExecutor" import {SubjectBuilder} from "../persistence/SubjectBuilder"; import {FindOneOptions} from "../find-options/FindOneOptions"; import {DeepPartial} from "../common/DeepPartial"; +import {PersistOptions} from "./PersistOptions"; +import {RemoveOptions} from "./RemoveOptions"; /** * Repository is supposed to work with your entity objects. Find entities, insert, update, delete, etc. @@ -57,6 +59,13 @@ export class Repository { return this.metadata.hasId(entity); } + /** + * Gets entity mixed id. + */ + getId(entity: Entity): any { + return this.metadata.getEntityIdMixedMap(entity); + } + /** * Creates a new query builder that can be used to build a sql query. */ @@ -87,7 +96,7 @@ export class Repository { * Creates a new entity instance or instances. * Can copy properties from the given object into new entities. */ - create(plainEntityLikeOrPlainEntityLikes?: DeepPartial|Partial[]): Entity|Entity[] { + create(plainEntityLikeOrPlainEntityLikes?: DeepPartial|DeepPartial[]): Entity|Entity[] { if (!plainEntityLikeOrPlainEntityLikes) return this.metadata.create(); @@ -130,20 +139,18 @@ export class Repository { * Persists (saves) all given entities in the database. * If entities do not exist in the database then inserts, otherwise updates. */ - async persist(entities: Entity[]): Promise; + async persist(entities: Entity[], options?: PersistOptions): Promise; /** * Persists (saves) a given entity in the database. * If entity does not exist in the database then inserts, otherwise updates. */ - async persist(entity: Entity): Promise; + async persist(entity: Entity, options?: PersistOptions): Promise; /** * Persists one or many given entities. - * - * todo: use Partial instead, and make sure it works properly */ - async persist(entityOrEntities: Entity|Entity[]): Promise { + async persist(entityOrEntities: Entity|Entity[], options?: PersistOptions): Promise { // if for some reason non empty entity was passed then return it back without having to do anything if (!entityOrEntities) @@ -171,20 +178,54 @@ export class Repository { } } + /** + * Updates entity partially. Entity can be found by a given conditions. + */ + async update(conditions: Partial, partialEntity: DeepPartial, options?: PersistOptions): Promise; + + /** + * Updates entity partially. Entity can be found by a given find options. + */ + async update(findOptions: FindOneOptions, partialEntity: DeepPartial, options?: PersistOptions): Promise; + + /** + * Updates entity partially. Entity can be found by a given conditions. + */ + async update(conditionsOrFindOptions: Partial|FindOneOptions, partialEntity: DeepPartial, options?: PersistOptions): Promise { + const entity = await this.findOne(conditionsOrFindOptions as any); // this is temporary, in the future can be refactored to perform better + if (!entity) + throw new Error(`Cannot find entity to update by a given criteria`); + + Object.assign(entity, partialEntity); + await this.persist(entity, options); + } + + /** + * Updates entity partially. Entity will be found by a given id. + */ + async updateById(id: any, partialEntity: DeepPartial, options?: PersistOptions): Promise { + const entity = await this.findOneById(id as any); // this is temporary, in the future can be refactored to perform better + if (!entity) + throw new Error(`Cannot find entity to update by a id`); + + Object.assign(entity, partialEntity); + await this.persist(entity, options); + } + /** * Removes a given entities from the database. */ - async remove(entities: Entity[]): Promise; + async remove(entities: Entity[], options?: RemoveOptions): Promise; /** * Removes a given entity from the database. */ - async remove(entity: Entity): Promise; + async remove(entity: Entity, options?: RemoveOptions): Promise; /** * Removes one or many given entities. */ - async remove(entityOrEntities: Entity|Entity[]): Promise { + async remove(entityOrEntities: Entity|Entity[], options?: RemoveOptions): Promise { // if for some reason non empty entity was passed then return it back without having to do anything if (!entityOrEntities) @@ -212,6 +253,17 @@ export class Repository { } } + /** + * Removes entity by a given entity id. + */ + async removeById(id: any, options?: RemoveOptions): Promise { + const entity = await this.findOneById(id); // this is temporary, in the future can be refactored to perform better + if (!entity) + throw new Error(`Cannot find entity to remove by a given id`); + + await this.remove(entity, options); + } + /** * Counts entities that match given options. */ @@ -220,12 +272,12 @@ export class Repository { /** * Counts entities that match given conditions. */ - count(conditions?: Partial): Promise; + count(conditions?: DeepPartial): Promise; /** * Counts entities that match given find options or conditions. */ - count(optionsOrConditions?: FindManyOptions|Partial): Promise { + count(optionsOrConditions?: FindManyOptions|DeepPartial): Promise { const qb = this.createQueryBuilder(FindOptionsUtils.extractFindManyOptionsAlias(optionsOrConditions) || this.metadata.table.name); return FindOptionsUtils.applyFindManyOptionsOrConditionsToQueryBuilder(qb, optionsOrConditions).getCount(); } @@ -238,12 +290,12 @@ export class Repository { /** * Finds entities that match given conditions. */ - find(conditions?: Partial): Promise; + find(conditions?: DeepPartial): Promise; /** * Finds entities that match given find options or conditions. */ - find(optionsOrConditions?: FindManyOptions|Partial): Promise { + find(optionsOrConditions?: FindManyOptions|DeepPartial): Promise { const qb = this.createQueryBuilder(FindOptionsUtils.extractFindManyOptionsAlias(optionsOrConditions) || this.metadata.table.name); return FindOptionsUtils.applyFindManyOptionsOrConditionsToQueryBuilder(qb, optionsOrConditions).getMany(); } @@ -260,14 +312,14 @@ export class Repository { * Also counts all entities that match given conditions, * but ignores pagination settings (from and take options). */ - findAndCount(conditions?: Partial): Promise<[ Entity[], number ]>; + findAndCount(conditions?: DeepPartial): Promise<[ Entity[], number ]>; /** * Finds entities that match given find options or conditions. * Also counts all entities that match given conditions, * but ignores pagination settings (from and take options). */ - findAndCount(optionsOrConditions?: FindManyOptions|Partial): Promise<[ Entity[], number ]> { + findAndCount(optionsOrConditions?: FindManyOptions|DeepPartial): Promise<[ Entity[], number ]> { const qb = this.createQueryBuilder(FindOptionsUtils.extractFindManyOptionsAlias(optionsOrConditions) || this.metadata.table.name); return FindOptionsUtils.applyFindManyOptionsOrConditionsToQueryBuilder(qb, optionsOrConditions).getManyAndCount(); } @@ -282,13 +334,13 @@ export class Repository { * Finds entities by ids. * Optionally conditions can be applied. */ - findByIds(ids: any[], conditions?: Partial): Promise; + findByIds(ids: any[], conditions?: DeepPartial): Promise; /** * Finds entities by ids. * Optionally find options can be applied. */ - findByIds(ids: any[], optionsOrConditions?: FindManyOptions|Partial): Promise { + findByIds(ids: any[], optionsOrConditions?: FindManyOptions|DeepPartial): Promise { const qb = this.createQueryBuilder(FindOptionsUtils.extractFindManyOptionsAlias(optionsOrConditions) || this.metadata.table.name); return FindOptionsUtils.applyFindManyOptionsOrConditionsToQueryBuilder(qb, optionsOrConditions) .andWhereInIds(ids) @@ -303,12 +355,12 @@ export class Repository { /** * Finds first entity that matches given conditions. */ - findOne(conditions?: Partial): Promise; + findOne(conditions?: DeepPartial): Promise; /** * Finds first entity that matches given conditions. */ - findOne(optionsOrConditions?: FindOneOptions|Partial): Promise { + findOne(optionsOrConditions?: FindOneOptions|DeepPartial): Promise { const qb = this.createQueryBuilder(FindOptionsUtils.extractFindOneOptionsAlias(optionsOrConditions) || this.metadata.table.name); return FindOptionsUtils.applyFindOneOptionsOrConditionsToQueryBuilder(qb, optionsOrConditions).getOne(); } @@ -323,13 +375,13 @@ export class Repository { * Finds entity by given id. * Optionally conditions can be applied. */ - findOneById(id: any, conditions?: Partial): Promise; + findOneById(id: any, conditions?: DeepPartial): Promise; /** * Finds entity by given id. * Optionally find options or conditions can be applied. */ - findOneById(id: any, optionsOrConditions?: FindOneOptions|Partial): Promise { + findOneById(id: any, optionsOrConditions?: FindOneOptions|DeepPartial): Promise { const qb = this.createQueryBuilder(FindOptionsUtils.extractFindOneOptionsAlias(optionsOrConditions) || this.metadata.table.name); return FindOptionsUtils.applyFindOneOptionsOrConditionsToQueryBuilder(qb, optionsOrConditions) .andWhereInIds([id]) diff --git a/test/functional/persistence/one-to-many/persistence-one-to-many.ts b/test/functional/persistence/one-to-many/persistence-one-to-many.ts index 800f4b624..b8bf6332e 100644 --- a/test/functional/persistence/one-to-many/persistence-one-to-many.ts +++ b/test/functional/persistence/one-to-many/persistence-one-to-many.ts @@ -35,11 +35,11 @@ describe("persistence > one-to-many", function() { let newCategory = categoryRepository.create(); newCategory.name = "Animals"; - newCategory = await categoryRepository.persist(newCategory); + await categoryRepository.persist(newCategory); let newPost = postRepository.create(); newPost.title = "All about animals"; - newPost = await postRepository.persist(newPost); + await postRepository.persist(newPost); newPost.categories = [newCategory]; await postRepository.persist(newPost); @@ -67,7 +67,7 @@ describe("persistence > one-to-many", function() { let newCategory = categoryRepository.create(); newCategory.name = "Animals"; - newCategory = await categoryRepository.persist(newCategory); + await categoryRepository.persist(newCategory); let newPost = postRepository.create(); newPost.title = "All about animals"; @@ -97,11 +97,11 @@ describe("persistence > one-to-many", function() { let firstNewCategory = categoryRepository.create(); firstNewCategory.name = "Animals"; - firstNewCategory = await categoryRepository.persist(firstNewCategory); + await categoryRepository.persist(firstNewCategory); let secondNewCategory = categoryRepository.create(); secondNewCategory.name = "Insects"; - secondNewCategory = await categoryRepository.persist(secondNewCategory); + await categoryRepository.persist(secondNewCategory); let newPost = postRepository.create(); newPost.title = "All about animals"; @@ -137,11 +137,11 @@ describe("persistence > one-to-many", function() { let firstNewCategory = categoryRepository.create(); firstNewCategory.name = "Animals"; - firstNewCategory = await categoryRepository.persist(firstNewCategory); + await categoryRepository.persist(firstNewCategory); let secondNewCategory = categoryRepository.create(); secondNewCategory.name = "Insects"; - secondNewCategory = await categoryRepository.persist(secondNewCategory); + await categoryRepository.persist(secondNewCategory); let newPost = postRepository.create(); newPost.title = "All about animals"; @@ -175,11 +175,11 @@ describe("persistence > one-to-many", function() { let firstNewCategory = categoryRepository.create(); firstNewCategory.name = "Animals"; - firstNewCategory = await categoryRepository.persist(firstNewCategory); + await categoryRepository.persist(firstNewCategory); let secondNewCategory = categoryRepository.create(); secondNewCategory.name = "Insects"; - secondNewCategory = await categoryRepository.persist(secondNewCategory); + await categoryRepository.persist(secondNewCategory); let newPost = postRepository.create(); newPost.title = "All about animals"; diff --git a/test/functional/persistence/partial-persist/entity/Category.ts b/test/functional/persistence/partial-persist/entity/Category.ts new file mode 100644 index 000000000..a983dde42 --- /dev/null +++ b/test/functional/persistence/partial-persist/entity/Category.ts @@ -0,0 +1,22 @@ +import {Entity} from "../../../../../src/decorator/entity/Entity"; +import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/PrimaryGeneratedColumn"; +import {Post} from "./Post"; +import {Column} from "../../../../../src/decorator/columns/Column"; +import {ManyToMany} from "../../../../../src/decorator/relations/ManyToMany"; + +@Entity() +export class Category { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + name: string; + + @Column() + position: number; + + @ManyToMany(type => Post, post => post.categories) + posts: Post[]; + +} \ No newline at end of file diff --git a/test/functional/persistence/partial-persist/entity/Counters.ts b/test/functional/persistence/partial-persist/entity/Counters.ts new file mode 100644 index 000000000..128de4869 --- /dev/null +++ b/test/functional/persistence/partial-persist/entity/Counters.ts @@ -0,0 +1,16 @@ +import {EmbeddableEntity} from "../../../../../src/decorator/entity/EmbeddableEntity"; +import {Column} from "../../../../../src/decorator/columns/Column"; + +@EmbeddableEntity() +export class Counters { + + @Column() + stars: number; + + @Column() + commentCount: number; + + @Column() + metadata: string; + +} \ No newline at end of file diff --git a/test/functional/persistence/partial-persist/entity/Post.ts b/test/functional/persistence/partial-persist/entity/Post.ts new file mode 100644 index 000000000..e9968d340 --- /dev/null +++ b/test/functional/persistence/partial-persist/entity/Post.ts @@ -0,0 +1,31 @@ +import {Category} from "./Category"; +import {Entity} from "../../../../../src/decorator/entity/Entity"; +import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/PrimaryGeneratedColumn"; +import {Column} from "../../../../../src/decorator/columns/Column"; +import {ManyToMany} from "../../../../../src/decorator/relations/ManyToMany"; +import {JoinTable} from "../../../../../src/decorator/relations/JoinTable"; +import {Embedded} from "../../../../../src/decorator/Embedded"; +import {Counters} from "./Counters"; + +@Entity() +export class Post { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + title: string; + + @Column() + description: string; + + @Embedded(type => Counters) + counters: Counters; + + @ManyToMany(type => Category, category => category.posts, { + cascadeUpdate: true + }) + @JoinTable() + categories: Category[]; + +} \ No newline at end of file diff --git a/test/functional/persistence/partial-persist/partial-persist.ts b/test/functional/persistence/partial-persist/partial-persist.ts new file mode 100644 index 000000000..3f7a04baf --- /dev/null +++ b/test/functional/persistence/partial-persist/partial-persist.ts @@ -0,0 +1,141 @@ +import "reflect-metadata"; +import {createTestingConnections, closeTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils"; +import {Connection} from "../../../../src/connection/Connection"; +import {Post} from "./entity/Post"; +import {Category} from "./entity/Category"; +import {expect} from "chai"; +import {Counters} from "./entity/Counters"; + +describe("persistence > partial persist", () => { + + // ------------------------------------------------------------------------- + // Configuration + // ------------------------------------------------------------------------- + + let connections: Connection[]; + before(async () => connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + schemaCreate: true, + dropSchemaOnConnection: true + })); + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + // ------------------------------------------------------------------------- + // Specifications + // ------------------------------------------------------------------------- + + it("should persist partial entities without data loose", () => Promise.all(connections.map(async connection => { + + const postRepository = connection.getRepository(Post); + const categoryRepository = connection.getRepository(Category); + + // save a new category + const newCategory = new Category(); + newCategory.name = "Animals"; + newCategory.position = 999; + await categoryRepository.persist(newCategory); + + // save a new post + const newPost = new Post(); + newPost.title = "All about animals"; + newPost.description = "Description of the post about animals"; + newPost.categories = [newCategory]; + newPost.counters = new Counters(); + newPost.counters.stars = 5; + newPost.counters.commentCount = 2; + newPost.counters.metadata = "Animals Metadata"; + await postRepository.persist(newPost); + + // load a post + const loadedPost = await postRepository.findOneById(1, { + join: { + alias: "post", + leftJoinAndSelect: { + categories: "post.categories" + } + } + }); + + expect(loadedPost!).not.to.be.empty; + expect(loadedPost!.categories).not.to.be.empty; + loadedPost!.title.should.be.equal("All about animals"); + loadedPost!.description.should.be.equal("Description of the post about animals"); + loadedPost!.categories[0].name.should.be.equal("Animals"); + loadedPost!.categories[0].position.should.be.equal(999); + loadedPost!.counters.metadata.should.be.equal("Animals Metadata"); + loadedPost!.counters.stars.should.be.equal(5); + loadedPost!.counters.commentCount.should.be.equal(2); + + // now update partially + await postRepository.update({ title: "All about animals" }, { title: "All about bears" }); + + // now check if update worked as expected, title is updated and all other columns are not touched + const loadedPostAfterTitleUpdate = await postRepository.findOneById(1, { + join: { + alias: "post", + leftJoinAndSelect: { + categories: "post.categories" + } + } + }); + + expect(loadedPostAfterTitleUpdate!).not.to.be.empty; + expect(loadedPostAfterTitleUpdate!.categories).not.to.be.empty; + loadedPostAfterTitleUpdate!.title.should.be.equal("All about bears"); + loadedPostAfterTitleUpdate!.description.should.be.equal("Description of the post about animals"); + loadedPostAfterTitleUpdate!.categories[0].name.should.be.equal("Animals"); + loadedPostAfterTitleUpdate!.categories[0].position.should.be.equal(999); + loadedPostAfterTitleUpdate!.counters.metadata.should.be.equal("Animals Metadata"); + loadedPostAfterTitleUpdate!.counters.stars.should.be.equal(5); + loadedPostAfterTitleUpdate!.counters.commentCount.should.be.equal(2); + + // now update in partial embeddable column + await postRepository.update({ id: 1 }, { counters: { stars: 10 } }); + + // now check if update worked as expected, stars counter is updated and all other columns are not touched + const loadedPostAfterStarsUpdate = await postRepository.findOneById(1, { + join: { + alias: "post", + leftJoinAndSelect: { + categories: "post.categories" + } + } + }); + + expect(loadedPostAfterStarsUpdate!).not.to.be.empty; + expect(loadedPostAfterStarsUpdate!.categories).not.to.be.empty; + loadedPostAfterStarsUpdate!.title.should.be.equal("All about bears"); + loadedPostAfterStarsUpdate!.description.should.be.equal("Description of the post about animals"); + loadedPostAfterStarsUpdate!.categories[0].name.should.be.equal("Animals"); + loadedPostAfterStarsUpdate!.categories[0].position.should.be.equal(999); + loadedPostAfterStarsUpdate!.counters.metadata.should.be.equal("Animals Metadata"); + loadedPostAfterStarsUpdate!.counters.stars.should.be.equal(10); + loadedPostAfterStarsUpdate!.counters.commentCount.should.be.equal(2); + + // now update in relational column + await postRepository.updateById(1, { categories: [{ id: 1, name: "Bears" }] }); + + // now check if update worked as expected, name of category is updated and all other columns are not touched + const loadedPostAfterCategoryUpdate = await postRepository.findOneById(1, { + join: { + alias: "post", + leftJoinAndSelect: { + categories: "post.categories" + } + } + }); + + expect(loadedPostAfterCategoryUpdate!).not.to.be.empty; + expect(loadedPostAfterCategoryUpdate!.categories).not.to.be.empty; + loadedPostAfterCategoryUpdate!.title.should.be.equal("All about bears"); + loadedPostAfterCategoryUpdate!.description.should.be.equal("Description of the post about animals"); + loadedPostAfterCategoryUpdate!.categories[0].name.should.be.equal("Bears"); + loadedPostAfterCategoryUpdate!.categories[0].position.should.be.equal(999); + loadedPostAfterCategoryUpdate!.counters.metadata.should.be.equal("Animals Metadata"); + loadedPostAfterCategoryUpdate!.counters.stars.should.be.equal(10); + loadedPostAfterCategoryUpdate!.counters.commentCount.should.be.equal(2); + + }))); + +}); diff --git a/test/integration/sample2-one-to-one.ts b/test/integration/sample2-one-to-one.ts index 10b6c2de3..f9ce60fab 100644 --- a/test/integration/sample2-one-to-one.ts +++ b/test/integration/sample2-one-to-one.ts @@ -65,7 +65,7 @@ describe("one-to-one", function() { newPost.text = "Hello post"; newPost.title = "this is post title"; newPost.details = details; - return postRepository.persist(newPost).then(post => savedPost = post); + return postRepository.persist(newPost).then(post => savedPost = post as Post); }); it("should return the same post instance after its created", function () { @@ -185,7 +185,7 @@ describe("one-to-one", function() { newPost.title = "this is post title"; newPost.category = category; - return postRepository.persist(newPost).then(post => savedPost = post); + return postRepository.persist(newPost).then(post => savedPost = post as Post); }); it("should return the same post instance after its created", function () { @@ -264,13 +264,13 @@ describe("one-to-one", function() { return postRepository .persist(newPost) - .then(post => savedPost = post); + .then(post => savedPost = post as Post); }); it("should ignore updates in the model and do not update the db when entity is updated", function () { newPost.details.comment = "i am updated comment"; return postRepository.persist(newPost).then(updatedPost => { - updatedPost.details.comment.should.be.equal("i am updated comment"); + updatedPost.details!.comment!.should.be.equal("i am updated comment"); return postRepository .createQueryBuilder("post") .leftJoinAndSelect("post.details", "details") @@ -278,7 +278,7 @@ describe("one-to-one", function() { .setParameter("id", updatedPost.id) .getOne(); }).then(updatedPostReloaded => { - updatedPostReloaded.details.comment.should.be.equal("this is post"); + updatedPostReloaded!.details.comment.should.be.equal("this is post"); }); }); // todo: also check that updates throw exception in strict cascades mode }); @@ -302,7 +302,7 @@ describe("one-to-one", function() { return postRepository .persist(newPost) - .then(post => savedPost = post); + .then(post => savedPost = post as Post); }); it("should ignore updates in the model and do not update the db when entity is updated", function () { @@ -315,7 +315,7 @@ describe("one-to-one", function() { .setParameter("id", updatedPost.id) .getOne(); }).then(updatedPostReloaded => { - updatedPostReloaded.details.comment.should.be.equal("this is post"); + updatedPostReloaded!.details.comment.should.be.equal("this is post"); }); }); }); @@ -337,12 +337,12 @@ describe("one-to-one", function() { return postImageRepository .persist(newImage) .then(image => { - savedImage = image; - newPost.image = image; + savedImage = image as PostImage; + newPost.image = image as PostImage; return postRepository.persist(newPost); }).then(post => { - newPost = post; + newPost = post as Post; return postRepository .createQueryBuilder("post") .leftJoinAndSelect("post.image", "image") @@ -351,8 +351,8 @@ describe("one-to-one", function() { .getOne(); }).then(loadedPost => { - loadedPost.image.url = "new-logo.png"; - return postRepository.persist(loadedPost); + loadedPost!.image.url = "new-logo.png"; + return postRepository.persist(loadedPost!); }).then(() => { return postRepository @@ -363,7 +363,7 @@ describe("one-to-one", function() { .getOne(); }).then(reloadedPost => { - reloadedPost.image.url.should.be.equal("new-logo.png"); + reloadedPost!.image.url.should.be.equal("new-logo.png"); }); }); @@ -386,12 +386,12 @@ describe("one-to-one", function() { return postMetadataRepository .persist(newMetadata) .then(metadata => { - savedMetadata = metadata; - newPost.metadata = metadata; + savedMetadata = metadata as PostMetadata; + newPost.metadata = metadata as PostMetadata; return postRepository.persist(newPost); }).then(post => { - newPost = post; + newPost = post as Post; return postRepository .createQueryBuilder("post") .leftJoinAndSelect("post.metadata", "metadata") @@ -400,8 +400,8 @@ describe("one-to-one", function() { .getOne(); }).then(loadedPost => { - loadedPost.metadata = null; - return postRepository.persist(loadedPost); + loadedPost!.metadata = null; + return postRepository.persist(loadedPost!); }).then(() => { return postRepository @@ -412,7 +412,7 @@ describe("one-to-one", function() { .getOne(); }).then(reloadedPost => { - expect(reloadedPost.metadata).to.not.exist; + expect(reloadedPost!.metadata).to.not.exist; }); }); diff --git a/test/integration/sample3-many-to-one.ts b/test/integration/sample3-many-to-one.ts index b7820e67c..e0a437054 100644 --- a/test/integration/sample3-many-to-one.ts +++ b/test/integration/sample3-many-to-one.ts @@ -65,7 +65,7 @@ describe("many-to-one", function() { newPost.text = "Hello post"; newPost.title = "this is post title"; newPost.details = details; - return postRepository.persist(newPost).then(post => savedPost = post); + return postRepository.persist(newPost).then(post => savedPost = post as Post); }); it("should return the same post instance after its created", function () { @@ -188,7 +188,7 @@ describe("many-to-one", function() { newPost.title = "this is post title"; newPost.category = category; - return postRepository.persist(newPost).then(post => savedPost = post); + return postRepository.persist(newPost).then(post => savedPost = post as Post); }); it("should return the same post instance after its created", function () { @@ -267,13 +267,13 @@ describe("many-to-one", function() { return postRepository .persist(newPost) - .then(post => savedPost = post); + .then(post => savedPost = post as Post); }); it("should ignore updates in the model and do not update the db when entity is updated", function () { newPost.details.comment = "i am updated comment"; return postRepository.persist(newPost).then(updatedPost => { - updatedPost.details.comment.should.be.equal("i am updated comment"); + updatedPost.details!.comment!.should.be.equal("i am updated comment"); return postRepository .createQueryBuilder("post") .leftJoinAndSelect("post.details", "details") @@ -281,7 +281,7 @@ describe("many-to-one", function() { .setParameter("id", updatedPost.id) .getOne(); }).then(updatedPostReloaded => { - updatedPostReloaded.details.comment.should.be.equal("this is post"); + updatedPostReloaded!.details.comment.should.be.equal("this is post"); }); }); // todo: also check that updates throw exception in strict cascades mode }); @@ -305,7 +305,7 @@ describe("many-to-one", function() { return postRepository .persist(newPost) - .then(post => savedPost = post); + .then(post => savedPost = post as Post); }); it("should ignore updates in the model and do not update the db when entity is updated", function () { @@ -318,7 +318,7 @@ describe("many-to-one", function() { .setParameter("id", updatedPost.id) .getOne(); }).then(updatedPostReloaded => { - updatedPostReloaded.details.comment.should.be.equal("this is post"); + updatedPostReloaded!.details.comment.should.be.equal("this is post"); }); }); }); @@ -340,12 +340,12 @@ describe("many-to-one", function() { return postImageRepository .persist(newImage) .then(image => { - savedImage = image; - newPost.image = image; + savedImage = image as PostImage; + newPost.image = image as PostImage; return postRepository.persist(newPost); }).then(post => { - newPost = post; + newPost = post as Post; return postRepository .createQueryBuilder("post") .leftJoinAndSelect("post.image", "image") @@ -354,8 +354,8 @@ describe("many-to-one", function() { .getOne(); }).then(loadedPost => { - loadedPost.image.url = "new-logo.png"; - return postRepository.persist(loadedPost); + loadedPost!.image.url = "new-logo.png"; + return postRepository.persist(loadedPost!); }).then(() => { return postRepository @@ -366,7 +366,7 @@ describe("many-to-one", function() { .getOne(); }).then(reloadedPost => { - reloadedPost.image.url.should.be.equal("new-logo.png"); + reloadedPost!.image.url.should.be.equal("new-logo.png"); }); }); @@ -389,12 +389,12 @@ describe("many-to-one", function() { return postMetadataRepository .persist(newMetadata) .then(metadata => { - savedMetadata = metadata; - newPost.metadata = metadata; + savedMetadata = metadata as PostMetadata; + newPost.metadata = metadata as PostMetadata; return postRepository.persist(newPost); }).then(post => { - newPost = post; + newPost = post as Post; return postRepository .createQueryBuilder("post") .leftJoinAndSelect("post.metadata", "metadata") @@ -403,8 +403,8 @@ describe("many-to-one", function() { .getOne(); }).then(loadedPost => { - loadedPost.metadata = null; - return postRepository.persist(loadedPost); + loadedPost!.metadata = null; + return postRepository.persist(loadedPost!); }).then(() => { return postRepository @@ -415,7 +415,7 @@ describe("many-to-one", function() { .getOne(); }).then(reloadedPost => { - expect(reloadedPost.metadata).to.be.empty; + expect(reloadedPost!.metadata).to.be.empty; }); }); @@ -436,7 +436,7 @@ describe("many-to-one", function() { details.posts = []; details.posts.push(newPost); - return postDetailsRepository.persist(details).then(details => savedDetails = details); + return postDetailsRepository.persist(details).then(details => savedDetails = details as PostDetails); }); it("should return the same post instance after its created", function () { diff --git a/test/integration/sample4-many-to-many.ts b/test/integration/sample4-many-to-many.ts index c505a3ae7..13cf5b498 100644 --- a/test/integration/sample4-many-to-many.ts +++ b/test/integration/sample4-many-to-many.ts @@ -65,7 +65,7 @@ describe("many-to-many", function() { newPost.details = []; newPost.details.push(details); - return postRepository.persist(newPost).then(post => savedPost = post); + return postRepository.persist(newPost).then(post => savedPost = post as Post); }); it("should return the same post instance after its created", function () { @@ -190,7 +190,7 @@ describe("many-to-many", function() { newPost.categories = []; newPost.categories.push(category); - return postRepository.persist(newPost).then(post => savedPost = post); + return postRepository.persist(newPost).then(post => savedPost = post as Post); }); it("should return the same post instance after its created", function () { @@ -271,13 +271,13 @@ describe("many-to-many", function() { return postRepository .persist(newPost) - .then(post => savedPost = post); + .then(post => savedPost = post as Post); }); it("should ignore updates in the model and do not update the db when entity is updated", function () { newPost.details[0].comment = "i am updated comment"; - return postRepository.persist(newPost).then(updatedPost => { - updatedPost.details[0].comment.should.be.equal("i am updated comment"); + return postRepository.persist(newPost).then((updatedPost: any) => { // temporary + updatedPost!.details![0]!.comment!.should.be.equal("i am updated comment"); return postRepository .createQueryBuilder("post") .leftJoinAndSelect("post.details", "details") @@ -285,7 +285,7 @@ describe("many-to-many", function() { .setParameter("id", updatedPost.id) .getOne(); }).then(updatedPostReloaded => { - updatedPostReloaded.details[0].comment.should.be.equal("this is post"); + updatedPostReloaded!.details[0].comment.should.be.equal("this is post"); }); }); // todo: also check that updates throw exception in strict cascades mode }); @@ -310,7 +310,7 @@ describe("many-to-many", function() { return postRepository .persist(newPost) - .then(post => savedPost = post); + .then(post => savedPost = post as Post); }); it("should remove relation however should not remove details itself", function () { @@ -323,7 +323,7 @@ describe("many-to-many", function() { .setParameter("id", updatedPost.id) .getOne(); }).then(updatedPostReloaded => { - expect(updatedPostReloaded.details).to.be.empty; + expect(updatedPostReloaded!.details).to.be.empty; return postDetailsRepository .createQueryBuilder("details") @@ -355,13 +355,13 @@ describe("many-to-many", function() { return postImageRepository .persist(newImage) .then(image => { - savedImage = image; + savedImage = image as PostImage; newPost.images = []; - newPost.images.push(image); + newPost.images.push(image as PostImage); return postRepository.persist(newPost); }).then(post => { - newPost = post; + newPost = post as Post; return postRepository .createQueryBuilder("post") .leftJoinAndSelect("post.images", "images") @@ -370,8 +370,8 @@ describe("many-to-many", function() { .getOne(); }).then(loadedPost => { - loadedPost.images[0].url = "new-logo.png"; - return postRepository.persist(loadedPost); + loadedPost!.images[0].url = "new-logo.png"; + return postRepository.persist(loadedPost!); }).then(() => { return postRepository @@ -382,7 +382,7 @@ describe("many-to-many", function() { .getOne(); }).then(reloadedPost => { - reloadedPost.images[0].url.should.be.equal("new-logo.png"); + reloadedPost!.images[0].url.should.be.equal("new-logo.png"); }); }); @@ -405,13 +405,13 @@ describe("many-to-many", function() { return postMetadataRepository .persist(newMetadata) .then(metadata => { - savedMetadata = metadata; + savedMetadata = metadata as PostMetadata; newPost.metadatas = []; - newPost.metadatas.push(metadata); + newPost.metadatas.push(metadata as PostMetadata); return postRepository.persist(newPost); }).then(post => { - newPost = post; + newPost = post as Post; return postRepository .createQueryBuilder("post") .leftJoinAndSelect("post.metadatas", "metadatas") @@ -420,8 +420,8 @@ describe("many-to-many", function() { .getOne(); }).then(loadedPost => { - loadedPost.metadatas = []; - return postRepository.persist(loadedPost); + loadedPost!.metadatas = []; + return postRepository.persist(loadedPost as Post); }).then(() => { return postRepository @@ -432,7 +432,7 @@ describe("many-to-many", function() { .getOne(); }).then(reloadedPost => { - expect(reloadedPost.metadatas).to.be.empty; + expect(reloadedPost!.metadatas).to.be.empty; }); }); @@ -453,7 +453,7 @@ describe("many-to-many", function() { details.posts = []; details.posts.push(newPost); - return postDetailsRepository.persist(details).then(details => savedDetails = details); + return postDetailsRepository.persist(details).then(details => savedDetails = details as PostDetails); }); it("should return the same post instance after its created", function () { @@ -526,7 +526,7 @@ describe("many-to-many", function() { return postRepository .persist(newPost) // first save .then(savedPost => { - savedPostId = savedPost.id; + savedPostId = (savedPost as Post).id; savedDetailsId = details.id; return postRepository.remove(newPost); }); // now remove newly saved