mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
implemented partial persist
This commit is contained in:
parent
2984c4dc2c
commit
540ffffafc
@ -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)
|
||||
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -60,7 +60,7 @@ export class EverythingEntity {
|
||||
jsonColumn: any;
|
||||
|
||||
@Column()
|
||||
alsoJson: Object;
|
||||
alsoJson: any;
|
||||
|
||||
@Column("simple_array")
|
||||
simpleArrayColumn: string[];
|
||||
|
||||
@ -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]);
|
||||
});
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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("---------------------------");
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
/**
|
||||
* Same as Partial<T> but goes deeper and makes Partial<T> all its properties and sub-properties.
|
||||
*/
|
||||
export type DeepPartial<T> = {
|
||||
readonly [P in keyof T]?: DeepPartial<T[P]>;
|
||||
[P in keyof T]?: DeepPartial<T[P]>;
|
||||
};
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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 ? <Object> maybeEntity : <Object> 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.
|
||||
*/
|
||||
|
||||
@ -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: Entity): Promise<Entity>;
|
||||
persist<Entity>(entity: Entity, options?: PersistOptions): Promise<Entity>;
|
||||
|
||||
/**
|
||||
* Persists (saves) all given entities in the database.
|
||||
* If entities do not exist in the database then inserts, otherwise updates.
|
||||
*/
|
||||
persist<Entity>(targetOrEntity: Function, entity: Entity): Promise<Entity>;
|
||||
persist<Entity>(targetOrEntity: Function, entity: Entity, options?: PersistOptions): Promise<Entity>;
|
||||
|
||||
/**
|
||||
* Persists (saves) all given entities in the database.
|
||||
* If entities do not exist in the database then inserts, otherwise updates.
|
||||
*/
|
||||
persist<Entity>(targetOrEntity: string, entity: Entity): Promise<Entity>;
|
||||
persist<Entity>(targetOrEntity: string, entity: Entity, options?: PersistOptions): Promise<Entity>;
|
||||
|
||||
/**
|
||||
* Persists (saves) all given entities in the database.
|
||||
* If entities do not exist in the database then inserts, otherwise updates.
|
||||
*/
|
||||
persist<Entity>(entities: Entity[]): Promise<Entity[]>;
|
||||
persist<Entity>(entities: Entity[], options?: PersistOptions): Promise<Entity[]>;
|
||||
|
||||
/**
|
||||
* Persists (saves) all given entities in the database.
|
||||
* If entities do not exist in the database then inserts, otherwise updates.
|
||||
*/
|
||||
persist<Entity>(targetOrEntity: Function, entities: Entity[]): Promise<Entity[]>;
|
||||
persist<Entity>(targetOrEntity: Function, entities: Entity[], options?: PersistOptions): Promise<Entity[]>;
|
||||
|
||||
/**
|
||||
* Persists (saves) all given entities in the database.
|
||||
* If entities do not exist in the database then inserts, otherwise updates.
|
||||
*/
|
||||
persist<Entity>(targetOrEntity: string, entities: Entity[]): Promise<Entity[]>;
|
||||
persist<Entity>(targetOrEntity: string, entities: Entity[], options?: PersistOptions): Promise<Entity[]>;
|
||||
|
||||
/**
|
||||
* Persists (saves) a given entity in the database.
|
||||
*/
|
||||
persist<Entity>(targetOrEntity: (Entity|Entity[])|Function|string, maybeEntity?: Entity|Entity[]): Promise<Entity|Entity[]> {
|
||||
persist<Entity>(targetOrEntity: (Entity|Entity[])|Function|string, maybeEntity?: Entity|Entity[], options?: PersistOptions): Promise<Entity|Entity[]> {
|
||||
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<Entity|Entity[]>(target).persist(entity);
|
||||
return this.getRepository<Entity|Entity[]>(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<Entity[]>(target[0].constructor).persist(entity as Entity[]);
|
||||
return this.getRepository<Entity[]>(target[0].constructor).persist(entity as Entity[], options);
|
||||
} else {
|
||||
return this.getRepository<Entity>(target.constructor).persist(entity as Entity);
|
||||
return this.getRepository<Entity>(target.constructor).persist(entity as Entity, options);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates entity partially. Entity can be found by a given conditions.
|
||||
*/
|
||||
async update<Entity>(target: Function|string, conditions: Partial<Entity>, partialEntity: DeepPartial<Entity>, options?: PersistOptions): Promise<void>;
|
||||
|
||||
/**
|
||||
* Updates entity partially. Entity can be found by a given find options.
|
||||
*/
|
||||
async update<Entity>(target: Function|string, findOptions: FindOneOptions<Entity>, partialEntity: DeepPartial<Entity>, options?: PersistOptions): Promise<void>;
|
||||
|
||||
/**
|
||||
* Updates entity partially. Entity can be found by a given conditions.
|
||||
*/
|
||||
async update<Entity>(target: Function|string, conditionsOrFindOptions: Partial<Entity>|FindOneOptions<Entity>, partialEntity: DeepPartial<Entity>, options?: PersistOptions): Promise<void> {
|
||||
return this.getRepository<Entity|Entity[]>(target as any)
|
||||
.update(conditionsOrFindOptions as any, partialEntity, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates entity partially. Entity will be found by a given id.
|
||||
*/
|
||||
async updateById<Entity>(target: Function|string, id: any, partialEntity: DeepPartial<Entity>, options?: PersistOptions): Promise<void> {
|
||||
return this.getRepository<Entity|Entity[]>(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<Entity>(targetOrEntity: Function, entity: Entity): Promise<Entity>;
|
||||
remove<Entity>(targetOrEntity: Function, entity: Entity, options?: RemoveOptions): Promise<Entity>;
|
||||
|
||||
/**
|
||||
* Removes a given entity from the database.
|
||||
*/
|
||||
remove<Entity>(targetOrEntity: string, entity: Entity): Promise<Entity>;
|
||||
remove<Entity>(targetOrEntity: string, entity: Entity, options?: RemoveOptions): Promise<Entity>;
|
||||
|
||||
/**
|
||||
* Removes a given entity from the database.
|
||||
*/
|
||||
remove<Entity>(entity: Entity[]): Promise<Entity>;
|
||||
remove<Entity>(entity: Entity[], options?: RemoveOptions): Promise<Entity>;
|
||||
|
||||
/**
|
||||
* Removes a given entity from the database.
|
||||
*/
|
||||
remove<Entity>(targetOrEntity: Function, entity: Entity[]): Promise<Entity[]>;
|
||||
remove<Entity>(targetOrEntity: Function, entity: Entity[], options?: RemoveOptions): Promise<Entity[]>;
|
||||
|
||||
/**
|
||||
* Removes a given entity from the database.
|
||||
*/
|
||||
remove<Entity>(targetOrEntity: string, entity: Entity[]): Promise<Entity[]>;
|
||||
remove<Entity>(targetOrEntity: string, entity: Entity[], options?: RemoveOptions): Promise<Entity[]>;
|
||||
|
||||
/**
|
||||
* Removes a given entity from the database.
|
||||
*/
|
||||
remove<Entity>(targetOrEntity: (Entity|Entity[])|Function|string, maybeEntity?: Entity|Entity[]): Promise<Entity|Entity[]> {
|
||||
remove<Entity>(targetOrEntity: (Entity|Entity[])|Function|string, maybeEntity?: Entity|Entity[], options?: RemoveOptions): Promise<Entity|Entity[]> {
|
||||
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<Entity|Entity[]>(target).remove(entity);
|
||||
return this.getRepository<Entity|Entity[]>(target).remove(entity, options);
|
||||
} else {
|
||||
// todo: throw exception if constructor in target is not set
|
||||
if (target instanceof Array) {
|
||||
return this.getRepository<Entity[]>(target[0].constructor).remove(entity as Entity[]);
|
||||
return this.getRepository<Entity[]>(target[0].constructor).remove(entity as Entity[], options);
|
||||
} else {
|
||||
return this.getRepository<Entity>(target.constructor).remove(entity as Entity);
|
||||
return this.getRepository<Entity>(target.constructor).remove(entity as Entity, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes entity by a given entity id.
|
||||
*/
|
||||
async removeById(targetOrEntity: Function|string, id: any, options?: RemoveOptions): Promise<void> {
|
||||
return this.getRepository(targetOrEntity as any).removeById(id, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts entities that match given options.
|
||||
*/
|
||||
|
||||
12
src/repository/PersistOptions.ts
Normal file
12
src/repository/PersistOptions.ts
Normal file
@ -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;
|
||||
|
||||
}
|
||||
12
src/repository/RemoveOptions.ts
Normal file
12
src/repository/RemoveOptions.ts
Normal file
@ -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;
|
||||
|
||||
}
|
||||
@ -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<Entity extends ObjectLiteral> {
|
||||
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<Entity extends ObjectLiteral> {
|
||||
* Creates a new entity instance or instances.
|
||||
* Can copy properties from the given object into new entities.
|
||||
*/
|
||||
create(plainEntityLikeOrPlainEntityLikes?: DeepPartial<Entity>|Partial<Entity>[]): Entity|Entity[] {
|
||||
create(plainEntityLikeOrPlainEntityLikes?: DeepPartial<Entity>|DeepPartial<Entity>[]): Entity|Entity[] {
|
||||
|
||||
if (!plainEntityLikeOrPlainEntityLikes)
|
||||
return this.metadata.create();
|
||||
@ -130,20 +139,18 @@ export class Repository<Entity extends ObjectLiteral> {
|
||||
* 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<Entity[]>;
|
||||
async persist(entities: Entity[], options?: PersistOptions): Promise<Entity[]>;
|
||||
|
||||
/**
|
||||
* 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<Entity>;
|
||||
async persist(entity: Entity, options?: PersistOptions): Promise<Entity>;
|
||||
|
||||
/**
|
||||
* Persists one or many given entities.
|
||||
*
|
||||
* todo: use Partial<Entity> instead, and make sure it works properly
|
||||
*/
|
||||
async persist(entityOrEntities: Entity|Entity[]): Promise<Entity|Entity[]> {
|
||||
async persist(entityOrEntities: Entity|Entity[], options?: PersistOptions): Promise<Entity|Entity[]> {
|
||||
|
||||
// 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<Entity extends ObjectLiteral> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates entity partially. Entity can be found by a given conditions.
|
||||
*/
|
||||
async update(conditions: Partial<Entity>, partialEntity: DeepPartial<Entity>, options?: PersistOptions): Promise<void>;
|
||||
|
||||
/**
|
||||
* Updates entity partially. Entity can be found by a given find options.
|
||||
*/
|
||||
async update(findOptions: FindOneOptions<Entity>, partialEntity: DeepPartial<Entity>, options?: PersistOptions): Promise<void>;
|
||||
|
||||
/**
|
||||
* Updates entity partially. Entity can be found by a given conditions.
|
||||
*/
|
||||
async update(conditionsOrFindOptions: Partial<Entity>|FindOneOptions<Entity>, partialEntity: DeepPartial<Entity>, options?: PersistOptions): Promise<void> {
|
||||
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<Entity>, options?: PersistOptions): Promise<void> {
|
||||
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<Entity[]>;
|
||||
async remove(entities: Entity[], options?: RemoveOptions): Promise<Entity[]>;
|
||||
|
||||
/**
|
||||
* Removes a given entity from the database.
|
||||
*/
|
||||
async remove(entity: Entity): Promise<Entity>;
|
||||
async remove(entity: Entity, options?: RemoveOptions): Promise<Entity>;
|
||||
|
||||
/**
|
||||
* Removes one or many given entities.
|
||||
*/
|
||||
async remove(entityOrEntities: Entity|Entity[]): Promise<Entity|Entity[]> {
|
||||
async remove(entityOrEntities: Entity|Entity[], options?: RemoveOptions): Promise<Entity|Entity[]> {
|
||||
|
||||
// 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<Entity extends ObjectLiteral> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes entity by a given entity id.
|
||||
*/
|
||||
async removeById(id: any, options?: RemoveOptions): Promise<void> {
|
||||
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<Entity extends ObjectLiteral> {
|
||||
/**
|
||||
* Counts entities that match given conditions.
|
||||
*/
|
||||
count(conditions?: Partial<Entity>): Promise<number>;
|
||||
count(conditions?: DeepPartial<Entity>): Promise<number>;
|
||||
|
||||
/**
|
||||
* Counts entities that match given find options or conditions.
|
||||
*/
|
||||
count(optionsOrConditions?: FindManyOptions<Entity>|Partial<Entity>): Promise<number> {
|
||||
count(optionsOrConditions?: FindManyOptions<Entity>|DeepPartial<Entity>): Promise<number> {
|
||||
const qb = this.createQueryBuilder(FindOptionsUtils.extractFindManyOptionsAlias(optionsOrConditions) || this.metadata.table.name);
|
||||
return FindOptionsUtils.applyFindManyOptionsOrConditionsToQueryBuilder(qb, optionsOrConditions).getCount();
|
||||
}
|
||||
@ -238,12 +290,12 @@ export class Repository<Entity extends ObjectLiteral> {
|
||||
/**
|
||||
* Finds entities that match given conditions.
|
||||
*/
|
||||
find(conditions?: Partial<Entity>): Promise<Entity[]>;
|
||||
find(conditions?: DeepPartial<Entity>): Promise<Entity[]>;
|
||||
|
||||
/**
|
||||
* Finds entities that match given find options or conditions.
|
||||
*/
|
||||
find(optionsOrConditions?: FindManyOptions<Entity>|Partial<Entity>): Promise<Entity[]> {
|
||||
find(optionsOrConditions?: FindManyOptions<Entity>|DeepPartial<Entity>): Promise<Entity[]> {
|
||||
const qb = this.createQueryBuilder(FindOptionsUtils.extractFindManyOptionsAlias(optionsOrConditions) || this.metadata.table.name);
|
||||
return FindOptionsUtils.applyFindManyOptionsOrConditionsToQueryBuilder(qb, optionsOrConditions).getMany();
|
||||
}
|
||||
@ -260,14 +312,14 @@ export class Repository<Entity extends ObjectLiteral> {
|
||||
* Also counts all entities that match given conditions,
|
||||
* but ignores pagination settings (from and take options).
|
||||
*/
|
||||
findAndCount(conditions?: Partial<Entity>): Promise<[ Entity[], number ]>;
|
||||
findAndCount(conditions?: DeepPartial<Entity>): 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<Entity>|Partial<Entity>): Promise<[ Entity[], number ]> {
|
||||
findAndCount(optionsOrConditions?: FindManyOptions<Entity>|DeepPartial<Entity>): 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<Entity extends ObjectLiteral> {
|
||||
* Finds entities by ids.
|
||||
* Optionally conditions can be applied.
|
||||
*/
|
||||
findByIds(ids: any[], conditions?: Partial<Entity>): Promise<Entity[]>;
|
||||
findByIds(ids: any[], conditions?: DeepPartial<Entity>): Promise<Entity[]>;
|
||||
|
||||
/**
|
||||
* Finds entities by ids.
|
||||
* Optionally find options can be applied.
|
||||
*/
|
||||
findByIds(ids: any[], optionsOrConditions?: FindManyOptions<Entity>|Partial<Entity>): Promise<Entity[]> {
|
||||
findByIds(ids: any[], optionsOrConditions?: FindManyOptions<Entity>|DeepPartial<Entity>): Promise<Entity[]> {
|
||||
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<Entity extends ObjectLiteral> {
|
||||
/**
|
||||
* Finds first entity that matches given conditions.
|
||||
*/
|
||||
findOne(conditions?: Partial<Entity>): Promise<Entity|undefined>;
|
||||
findOne(conditions?: DeepPartial<Entity>): Promise<Entity|undefined>;
|
||||
|
||||
/**
|
||||
* Finds first entity that matches given conditions.
|
||||
*/
|
||||
findOne(optionsOrConditions?: FindOneOptions<Entity>|Partial<Entity>): Promise<Entity|undefined> {
|
||||
findOne(optionsOrConditions?: FindOneOptions<Entity>|DeepPartial<Entity>): Promise<Entity|undefined> {
|
||||
const qb = this.createQueryBuilder(FindOptionsUtils.extractFindOneOptionsAlias(optionsOrConditions) || this.metadata.table.name);
|
||||
return FindOptionsUtils.applyFindOneOptionsOrConditionsToQueryBuilder(qb, optionsOrConditions).getOne();
|
||||
}
|
||||
@ -323,13 +375,13 @@ export class Repository<Entity extends ObjectLiteral> {
|
||||
* Finds entity by given id.
|
||||
* Optionally conditions can be applied.
|
||||
*/
|
||||
findOneById(id: any, conditions?: Partial<Entity>): Promise<Entity|undefined>;
|
||||
findOneById(id: any, conditions?: DeepPartial<Entity>): Promise<Entity|undefined>;
|
||||
|
||||
/**
|
||||
* Finds entity by given id.
|
||||
* Optionally find options or conditions can be applied.
|
||||
*/
|
||||
findOneById(id: any, optionsOrConditions?: FindOneOptions<Entity>|Partial<Entity>): Promise<Entity|undefined> {
|
||||
findOneById(id: any, optionsOrConditions?: FindOneOptions<Entity>|DeepPartial<Entity>): Promise<Entity|undefined> {
|
||||
const qb = this.createQueryBuilder(FindOptionsUtils.extractFindOneOptionsAlias(optionsOrConditions) || this.metadata.table.name);
|
||||
return FindOptionsUtils.applyFindOneOptionsOrConditionsToQueryBuilder(qb, optionsOrConditions)
|
||||
.andWhereInIds([id])
|
||||
|
||||
@ -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";
|
||||
|
||||
@ -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[];
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
}
|
||||
31
test/functional/persistence/partial-persist/entity/Post.ts
Normal file
31
test/functional/persistence/partial-persist/entity/Post.ts
Normal file
@ -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[];
|
||||
|
||||
}
|
||||
141
test/functional/persistence/partial-persist/partial-persist.ts
Normal file
141
test/functional/persistence/partial-persist/partial-persist.ts
Normal file
@ -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);
|
||||
|
||||
})));
|
||||
|
||||
});
|
||||
@ -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;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -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 () {
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user