mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
more experiments over new persistent mechanizm
This commit is contained in:
parent
dfecec0fc9
commit
651eb8dd22
@ -561,6 +561,23 @@ export class EntityMetadata {
|
||||
return hasAllIds ? map : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
createSimpleIdMap(id: any): ObjectLiteral {
|
||||
const map: ObjectLiteral = {};
|
||||
if (this.parentEntityMetadata) {
|
||||
this.primaryColumnsWithParentIdColumns.forEach(column => {
|
||||
map[column.propertyName] = id;
|
||||
});
|
||||
|
||||
} else {
|
||||
this.primaryColumns.forEach(column => {
|
||||
map[column.propertyName] = id;
|
||||
});
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* todo: undefined entities should not go there??
|
||||
* todo: shouldnt be entity ObjectLiteral here?
|
||||
|
||||
@ -545,17 +545,17 @@ export class DatabaseEntityLoader<Entity extends ObjectLiteral> {
|
||||
.findRelationIds(relation, persistedSubject.entity, inverseEntityRelationIds);
|
||||
|
||||
// now from all entities in the persisted entity find only those which aren't found in the db
|
||||
const newRelationIds = inverseEntityRelationIds.filter(inverseEntityRelationId => {
|
||||
/*const newRelationIds = inverseEntityRelationIds.filter(inverseEntityRelationId => {
|
||||
return !existInverseEntityRelationIds.find(relationId => inverseEntityRelationId === relationId);
|
||||
});
|
||||
/*const persistedEntities = value.filter(val => {
|
||||
const relationValue = relation.getInverseEntityRelationId(val);
|
||||
return !existInverseEntityRelationIds.find(relationId => relationValue === relationId);
|
||||
});*/ // todo: remove later if not necessary
|
||||
});*/
|
||||
const persistedEntities = value.filter(val => {
|
||||
const relationValue = relation.getInverseEntityRelationId(val);
|
||||
return !relationValue || !existInverseEntityRelationIds.find(relationId => relationValue === relationId);
|
||||
}); // todo: remove later if not necessary
|
||||
|
||||
// finally create a new junction insert operation and push it to the array of such operations
|
||||
if (newRelationIds.length > 0) {
|
||||
const operation = new NewJunctionInsertOperation(relation, persistedSubject, newRelationIds);
|
||||
if (persistedEntities.length > 0) {
|
||||
const operation = new NewJunctionInsertOperation(relation, persistedSubject, persistedEntities);
|
||||
junctionInsertOperations.push(operation);
|
||||
}
|
||||
});
|
||||
|
||||
@ -50,6 +50,8 @@ export class PersistSubjectExecutor {
|
||||
throw new Error(`Removed entity "${removeInUpdates.entityTarget}" is also scheduled for update operation. ` +
|
||||
`Make sure you are not updating and removing same object (note that update or remove may be executed by cascade operations).`);
|
||||
|
||||
// todo: there is nothing to update in inserted entity too
|
||||
|
||||
try {
|
||||
|
||||
// broadcast events before we start updating
|
||||
@ -64,7 +66,7 @@ export class PersistSubjectExecutor {
|
||||
await this.executeInsertOperations(insertSubjects);
|
||||
// await this.executeInsertClosureTableOperations(insertSubjects);
|
||||
// await this.executeUpdateTreeLevelOperations(insertSubjects);
|
||||
// await this.executeInsertJunctionsOperations(junctionInsertOperations, insertSubjects);
|
||||
await this.executeInsertJunctionsOperations(junctionInsertOperations, insertSubjects);
|
||||
// await this.executeRemoveJunctionsOperations(junctionRemoveOperations);
|
||||
// await this.executeRemoveRelationOperations(persistOperation); // todo: can we add these operations into list of updated?
|
||||
// await this.executeUpdateRelationsOperations(persistOperation); // todo: merge these operations with update operations?
|
||||
@ -132,6 +134,79 @@ export class PersistSubjectExecutor {
|
||||
|
||||
await Promise.all(firstInsertSubjects.map(subject => this.insert(subject, [])));
|
||||
await Promise.all(secondInsertSubjects.map(subject => this.insert(subject, firstInsertSubjects)));
|
||||
|
||||
const updatePromises: Promise<any>[] = [];
|
||||
insertSubjects.forEach(subject => {
|
||||
|
||||
// we need to update relation ids of the newly inserted objects (where we inserted NULLs in relations)
|
||||
const updateOptions: ObjectLiteral = {};
|
||||
subject.metadata.relationsWithJoinColumns.forEach(relation => {
|
||||
const referencedColumn = relation.joinColumn.referencedColumn;
|
||||
|
||||
insertSubjects.forEach(insertedSubject => {
|
||||
if (subject.entity[relation.propertyName] === insertedSubject.entity) {
|
||||
|
||||
if (referencedColumn.isGenerated)
|
||||
updateOptions[relation.name] = insertedSubject.newlyGeneratedId;
|
||||
|
||||
// todo: implement other special referenced column types (update date, create date, version, discriminator column, etc.)
|
||||
}
|
||||
});
|
||||
});
|
||||
if (Object.keys(updateOptions).length > 0) {
|
||||
const conditions = subject.metadata.getEntityIdMap(subject.entity) || subject.metadata.createSimpleIdMap(subject.newlyGeneratedId);
|
||||
const updatePromise = this.queryRunner.update(subject.metadata.table.name, updateOptions, conditions);
|
||||
updatePromises.push(updatePromise);
|
||||
}
|
||||
|
||||
// we need to update relation ids if newly inserted objects are used from inverse side in one-to-many inverse relation
|
||||
subject.metadata.oneToManyRelations.forEach(relation => {
|
||||
const referencedColumn = relation.inverseRelation.joinColumn.referencedColumn;
|
||||
const value = subject.entity[relation.propertyName];
|
||||
|
||||
if (value instanceof Array) {
|
||||
value.forEach(subValue => {
|
||||
insertSubjects.forEach(insertedSubject => {
|
||||
if (subValue === insertedSubject.entity) {
|
||||
|
||||
if (referencedColumn.isGenerated) {
|
||||
const conditions = insertedSubject.metadata.getEntityIdMap(insertedSubject.entity) || insertedSubject.metadata.createSimpleIdMap(insertedSubject.newlyGeneratedId);
|
||||
const updateOptions = { [relation.inverseRelation.joinColumn.name]: subject.newlyGeneratedId };
|
||||
const updatePromise = this.queryRunner.update(relation.inverseRelation.entityMetadata.table.name, updateOptions, conditions);
|
||||
updatePromises.push(updatePromise);
|
||||
}
|
||||
|
||||
// todo: implement other special referenced column types (update date, create date, version, discriminator column, etc.)
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// we also need to update relation ids if newly inserted objects are used from inverse side in one-to-one inverse relation
|
||||
subject.metadata.oneToOneRelations.filter(relation => !relation.isOwning).forEach(relation => {
|
||||
const referencedColumn = relation.inverseRelation.joinColumn.referencedColumn;
|
||||
insertSubjects.forEach(insertedSubject => {
|
||||
if (subject.entity[relation.propertyName] === insertedSubject.entity) {
|
||||
|
||||
if (referencedColumn.isGenerated) {
|
||||
const conditions = insertedSubject.metadata.getEntityIdMap(insertedSubject.entity) || insertedSubject.metadata.createSimpleIdMap(insertedSubject.newlyGeneratedId);
|
||||
const updateOptions = { [relation.inverseRelation.joinColumn.name]: subject.newlyGeneratedId };
|
||||
const updatePromise = this.queryRunner.update(relation.inverseRelation.entityMetadata.table.name, updateOptions, conditions);
|
||||
updatePromises.push(updatePromise);
|
||||
}
|
||||
|
||||
// todo: implement other special referenced column types (update date, create date, version, discriminator column, etc.)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
await Promise.all(updatePromises);
|
||||
|
||||
// todo: make sure to search in all insertSubjects during updating too if updated entity uses links to the newly persisted entity
|
||||
}
|
||||
|
||||
/**
|
||||
@ -656,7 +731,7 @@ export class PersistSubjectExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
private insertJunctions(junctionOperation: NewJunctionInsertOperation, insertOperations: Subject[]) {
|
||||
/*private insertJunctions(junctionOperation: NewJunctionInsertOperation, insertOperations: Subject[]) {
|
||||
// I think here we can only support to work only with single primary key entities
|
||||
|
||||
const metadata1 = this.connection.entityMetadatas.findByTarget(junctionOperation.entity1Target);
|
||||
@ -688,13 +763,56 @@ export class PersistSubjectExecutor {
|
||||
|
||||
let values: any[];
|
||||
// order may differ, find solution (column.table to compare with entity metadata table?)
|
||||
if (metadata1.table === junctionMetadata.foreignKeys[0].referencedTable) {
|
||||
if (metadata1.table === junctionOperation.metadata.foreignKeys[0].referencedTable) {
|
||||
values = [id1, id2];
|
||||
} else {
|
||||
values = [id2, id1];
|
||||
}
|
||||
|
||||
return this.queryRunner.insert(junctionMetadata.table.name, this.zipObject(columns, values));
|
||||
return this.queryRunner.insert(junctionOperation.metadata.table.name, this.zipObject(columns, values));
|
||||
}*/
|
||||
|
||||
private async insertJunctions(junctionOperation: NewJunctionInsertOperation, insertSubjects: Subject[]): Promise<void> {
|
||||
// I think here we can only support to work only with single primary key entities
|
||||
|
||||
const relation = junctionOperation.relation;
|
||||
const joinTable = relation.isOwning ? relation.joinTable : relation.inverseRelation.joinTable;
|
||||
const firstColumn = relation.isOwning ? joinTable.referencedColumn : joinTable.inverseReferencedColumn;
|
||||
const secondColumn = relation.isOwning ? joinTable.inverseReferencedColumn : joinTable.referencedColumn;
|
||||
|
||||
let ownId = junctionOperation.relation.getOwnEntityRelationId(junctionOperation.subject.entity);
|
||||
if (!ownId) {
|
||||
if (firstColumn.isGenerated) {
|
||||
ownId = junctionOperation.subject.newlyGeneratedId;
|
||||
}
|
||||
// todo: implement other special referenced column types (update date, create date, version, discriminator column, etc.)
|
||||
}
|
||||
|
||||
if (!ownId)
|
||||
throw new Error(`Cannot insert object of ${junctionOperation.subject.entityTarget} type. Looks like its not persisted yet, or cascades are not set on the relation.`); // todo: better error message
|
||||
|
||||
const promises = junctionOperation.junctionEntities.map(newBindEntity => {
|
||||
|
||||
let relationId = junctionOperation.relation.getInverseEntityRelationId(newBindEntity);
|
||||
if (!relationId) {
|
||||
const insertSubject = insertSubjects.find(subject => subject.entity === newBindEntity);
|
||||
if (insertSubject) {
|
||||
if (secondColumn.isGenerated) {
|
||||
relationId = insertSubject.newlyGeneratedId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!relationId)
|
||||
throw new Error(`Cannot insert object of ${relation.inverseRelation.entityTarget} type. Looks like its not persisted yet, or cascades are not set on the relation.`); // todo: better error message
|
||||
|
||||
const columns = relation.junctionEntityMetadata.columns.map(column => column.name);
|
||||
const values = relation.isOwning ? [ownId, relationId] : [relationId, ownId];
|
||||
|
||||
return this.queryRunner.insert(relation.junctionEntityMetadata.table.name, this.zipObject(columns, values));
|
||||
});
|
||||
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
private removeJunctions(junctionOperation: JunctionRemoveOperation) {
|
||||
|
||||
@ -1,17 +1,13 @@
|
||||
import {RelationMetadata} from "../../metadata/RelationMetadata";
|
||||
import {EntityMetadata} from "../../metadata/EntityMetadata";
|
||||
import {Subject} from "../subject/Subject";
|
||||
import {ObjectLiteral} from "../../common/ObjectLiteral";
|
||||
|
||||
export class NewJunctionInsertOperation {
|
||||
|
||||
// todo: we can send subjects instead of entities and junction entities if needed
|
||||
constructor(public relation: RelationMetadata,
|
||||
public subject: Subject,
|
||||
public junctionEntityRelationIds: any[]) { // junctionEntities can be replaced with ids?
|
||||
}
|
||||
|
||||
get metadata(): EntityMetadata {
|
||||
return this.relation.entityMetadata;
|
||||
public junctionEntities: ObjectLiteral[]) { // junctionEntities can be replaced with ids?
|
||||
}
|
||||
|
||||
}
|
||||
@ -76,11 +76,11 @@ export class Subject { // todo: move entity with id creation into metadata? // t
|
||||
}
|
||||
|
||||
get mustBeInserted() {
|
||||
return !this.databaseEntity;
|
||||
return this.canBeInserted && !this.databaseEntity;
|
||||
}
|
||||
|
||||
get mustBeUpdated() {
|
||||
return this.diffColumns.length > 0 || this.diffRelations.length > 0;
|
||||
return this.canBeUpdated && (this.diffColumns.length > 0 || this.diffRelations.length > 0);
|
||||
}
|
||||
|
||||
get databaseEntity(): ObjectLiteral|undefined {
|
||||
|
||||
@ -449,7 +449,7 @@ export class SpecificRepository<Entity extends ObjectLiteral> {
|
||||
const relation = this.convertMixedRelationToMetadata(relationOrName);
|
||||
if (!(entityOrEntities instanceof Array)) entityOrEntities = [entityOrEntities];
|
||||
|
||||
const entityReferencedColumn = relation.isOwning ? relation.joinTable.referencedColumn : relation.joinTable.inverseReferencedColumn;
|
||||
const entityReferencedColumn = relation.isOwning ? relation.joinTable.referencedColumn : relation.inverseRelation.joinTable.inverseReferencedColumn;
|
||||
const ownerEntityColumn = relation.isOwning ? relation.junctionEntityMetadata.columns[0] : relation.junctionEntityMetadata.columns[1];
|
||||
const inverseEntityColumn = relation.isOwning ? relation.junctionEntityMetadata.columns[1] : relation.junctionEntityMetadata.columns[0];
|
||||
|
||||
|
||||
@ -20,26 +20,39 @@ describe("persistence > cascade operations", () => {
|
||||
|
||||
it.only("should work perfectly", () => Promise.all(connections.map(async connection => {
|
||||
|
||||
|
||||
// create category
|
||||
const category1 = new Category();
|
||||
category1.name = "Category saved by cascades #1";
|
||||
// category1.onePost = post1;
|
||||
|
||||
// create category
|
||||
const category2 = new Category();
|
||||
category2.name = "Category saved by cascades #2";
|
||||
// category1.onePost = post1;
|
||||
|
||||
// create post
|
||||
const post1 = new Post();
|
||||
post1.title = "Hello Post #1";
|
||||
// post1.oneCategory = category1;
|
||||
|
||||
// todo(next): check out to one
|
||||
|
||||
// create photos
|
||||
const photo1 = new Photo();
|
||||
photo1.url = "http://me.com/photo";
|
||||
photo1.post = post1;
|
||||
photo1.categories = [category1, category2];
|
||||
|
||||
const photo2 = new Photo();
|
||||
photo2.url = "http://me.com/photo";
|
||||
photo2.post = post1;
|
||||
|
||||
post1.category = category1;
|
||||
post1.category.photos = [photo1, photo2];
|
||||
await connection.entityManager.persist(post1);
|
||||
// category1.photos = [photo1, photo2];
|
||||
|
||||
// post1.category = category1;
|
||||
// post1.category.photos = [photo1, photo2];
|
||||
await connection.entityManager.persist(photo1);
|
||||
|
||||
console.log("********************************************************");
|
||||
|
||||
|
||||
@ -7,6 +7,8 @@ import {Photo} from "./Photo";
|
||||
import {ManyToMany} from "../../../../../src/decorator/relations/ManyToMany";
|
||||
import {JoinTable} from "../../../../../src/decorator/relations/JoinTable";
|
||||
import {ManyToOne} from "../../../../../src/decorator/relations/ManyToOne";
|
||||
import {OneToOne} from "../../../../../src/decorator/relations/OneToOne";
|
||||
import {JoinColumn} from "../../../../../src/decorator/relations/JoinColumn";
|
||||
|
||||
@Table()
|
||||
export class Category {
|
||||
@ -17,6 +19,14 @@ export class Category {
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@OneToOne(type => Post, post => post.oneCategory, {
|
||||
cascadeInsert: true,
|
||||
cascadeUpdate: true,
|
||||
cascadeRemove: true
|
||||
})
|
||||
@JoinColumn()
|
||||
onePost: Post;
|
||||
|
||||
@OneToMany(type => Post, post => post.category, {
|
||||
cascadeInsert: true,
|
||||
cascadeUpdate: true,
|
||||
@ -24,7 +34,7 @@ export class Category {
|
||||
})
|
||||
posts: Post[];
|
||||
|
||||
@ManyToMany(type => Photo, {
|
||||
@ManyToMany(type => Photo, photo => photo.categories, {
|
||||
cascadeInsert: true,
|
||||
cascadeUpdate: true,
|
||||
cascadeRemove: true
|
||||
|
||||
@ -3,6 +3,8 @@ import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/Prima
|
||||
import {Column} from "../../../../../src/decorator/columns/Column";
|
||||
import {ManyToOne} from "../../../../../src/decorator/relations/ManyToOne";
|
||||
import {Post} from "../entity/Post";
|
||||
import {Category} from "../entity/Category";
|
||||
import {ManyToMany} from "../../../../../src/decorator/relations/ManyToMany";
|
||||
|
||||
@Table()
|
||||
export class Photo {
|
||||
@ -21,4 +23,11 @@ export class Photo {
|
||||
})
|
||||
post: Post|null;
|
||||
|
||||
@ManyToMany(type => Category, category => category.photos, {
|
||||
cascadeInsert: true,
|
||||
cascadeUpdate: true,
|
||||
cascadeRemove: true
|
||||
})
|
||||
categories: Category[];
|
||||
|
||||
}
|
||||
@ -6,6 +6,7 @@ import {Category} from "./Category";
|
||||
import {Photo} from "./Photo";
|
||||
import {ManyToMany} from "../../../../../src/decorator/relations/ManyToMany";
|
||||
import {JoinTable} from "../../../../../src/decorator/relations/JoinTable";
|
||||
import {OneToOne} from "../../../../../src/decorator/relations/OneToOne";
|
||||
|
||||
@Table()
|
||||
export class Post {
|
||||
@ -31,4 +32,11 @@ export class Post {
|
||||
@JoinTable()
|
||||
photos: Photo[];
|
||||
|
||||
@OneToOne(type => Category, category => category.onePost, {
|
||||
cascadeInsert: true,
|
||||
cascadeUpdate: true,
|
||||
cascadeRemove: true
|
||||
})
|
||||
oneCategory: Category;
|
||||
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
import {Table} from "../../../../../src/decorator/tables/Table";
|
||||
import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/PrimaryGeneratedColumn";
|
||||
import {Column} from "../../../../../src/decorator/columns/Column";
|
||||
import {Post} from "./Post";
|
||||
import {OneToMany} from "../../../../../src/decorator/relations/OneToMany";
|
||||
import {Photo} from "./Photo";
|
||||
import {ManyToMany} from "../../../../../src/decorator/relations/ManyToMany";
|
||||
import {JoinTable} from "../../../../../src/decorator/relations/JoinTable";
|
||||
import {ManyToOne} from "../../../../../src/decorator/relations/ManyToOne";
|
||||
import {OneToOne} from "../../../../../src/decorator/relations/OneToOne";
|
||||
import {JoinColumn} from "../../../../../src/decorator/relations/JoinColumn";
|
||||
|
||||
@Table()
|
||||
export class Category {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@OneToOne(type => Post, post => post.oneCategory, {
|
||||
cascadeInsert: true,
|
||||
cascadeUpdate: true,
|
||||
cascadeRemove: true
|
||||
})
|
||||
@JoinColumn()
|
||||
onePost: Post;
|
||||
|
||||
@OneToMany(type => Post, post => post.category, {
|
||||
cascadeInsert: true,
|
||||
cascadeUpdate: true,
|
||||
cascadeRemove: true
|
||||
})
|
||||
posts: Post[];
|
||||
|
||||
@ManyToMany(type => Photo, {
|
||||
cascadeInsert: true,
|
||||
cascadeUpdate: true,
|
||||
cascadeRemove: true
|
||||
})
|
||||
@JoinTable()
|
||||
photos: Photo[];
|
||||
|
||||
@ManyToOne(type => Photo, {
|
||||
cascadeInsert: true,
|
||||
cascadeUpdate: true,
|
||||
cascadeRemove: true
|
||||
})
|
||||
photo: Photo|null;
|
||||
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
import {Table} from "../../../../../src/decorator/tables/Table";
|
||||
import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/PrimaryGeneratedColumn";
|
||||
import {Column} from "../../../../../src/decorator/columns/Column";
|
||||
import {ManyToOne} from "../../../../../src/decorator/relations/ManyToOne";
|
||||
import {Post} from "../entity/Post";
|
||||
|
||||
@Table()
|
||||
export class Photo {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
url: string;
|
||||
|
||||
@ManyToOne(type => Post, {
|
||||
cascadeInsert: true,
|
||||
cascadeUpdate: true,
|
||||
cascadeRemove: true,
|
||||
nullable: false
|
||||
})
|
||||
post: Post|null;
|
||||
|
||||
}
|
||||
42
test/functional/persistence/insert-operations/entity/Post.ts
Normal file
42
test/functional/persistence/insert-operations/entity/Post.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import {Table} from "../../../../../src/decorator/tables/Table";
|
||||
import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/PrimaryGeneratedColumn";
|
||||
import {Column} from "../../../../../src/decorator/columns/Column";
|
||||
import {ManyToOne} from "../../../../../src/decorator/relations/ManyToOne";
|
||||
import {Category} from "./Category";
|
||||
import {Photo} from "./Photo";
|
||||
import {ManyToMany} from "../../../../../src/decorator/relations/ManyToMany";
|
||||
import {JoinTable} from "../../../../../src/decorator/relations/JoinTable";
|
||||
import {OneToOne} from "../../../../../src/decorator/relations/OneToOne";
|
||||
|
||||
@Table()
|
||||
export class Post {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
title: string;
|
||||
|
||||
@ManyToOne(type => Category, category => category.posts, {
|
||||
cascadeInsert: true,
|
||||
cascadeUpdate: true,
|
||||
cascadeRemove: true
|
||||
})
|
||||
category: Category|null;
|
||||
|
||||
@ManyToMany(type => Photo, {
|
||||
cascadeInsert: true,
|
||||
cascadeUpdate: true,
|
||||
cascadeRemove: true
|
||||
})
|
||||
@JoinTable()
|
||||
photos: Photo[];
|
||||
|
||||
@OneToOne(type => Category, category => category.onePost, {
|
||||
cascadeInsert: true,
|
||||
cascadeUpdate: true,
|
||||
cascadeRemove: true
|
||||
})
|
||||
oneCategory: Category;
|
||||
|
||||
}
|
||||
@ -0,0 +1,186 @@
|
||||
import "reflect-metadata";
|
||||
import {setupTestingConnections, closeConnections, reloadDatabases} from "../../../utils/test-utils";
|
||||
import {Connection} from "../../../../src/connection/Connection";
|
||||
import {Post} from "./entity/Post";
|
||||
import {Category} from "./entity/Category";
|
||||
import {Photo} from "./entity/Photo";
|
||||
|
||||
describe("persistence > insert operations", () => {
|
||||
|
||||
let connections: Connection[];
|
||||
before(async () => connections = await setupTestingConnections({
|
||||
entities: [__dirname + "/entity/*{.js,.ts}"],
|
||||
schemaCreate: true,
|
||||
dropSchemaOnConnection: true,
|
||||
}));
|
||||
beforeEach(() => reloadDatabases(connections));
|
||||
after(() => closeConnections(connections));
|
||||
|
||||
describe("cascade insert", function() {
|
||||
|
||||
it("should work perfectly", () => Promise.all(connections.map(async connection => {
|
||||
|
||||
// create category
|
||||
const category1 = new Category();
|
||||
category1.name = "Category saved by cascades #1";
|
||||
// category1.onePost = post1;
|
||||
|
||||
// create post
|
||||
const post1 = new Post();
|
||||
post1.title = "Hello Post #1";
|
||||
post1.oneCategory = category1;
|
||||
|
||||
// todo(next): check out to one
|
||||
|
||||
// create photos
|
||||
const photo1 = new Photo();
|
||||
photo1.url = "http://me.com/photo";
|
||||
photo1.post = post1;
|
||||
const photo2 = new Photo();
|
||||
photo2.url = "http://me.com/photo";
|
||||
photo2.post = post1;
|
||||
|
||||
// post1.category = category1;
|
||||
// post1.category.photos = [photo1, photo2];
|
||||
await connection.entityManager.persist(post1);
|
||||
|
||||
console.log("********************************************************");
|
||||
|
||||
/*const posts = await connection.entityManager
|
||||
.createQueryBuilder(Post, "post")
|
||||
.leftJoinAndSelect("post.category", "category")
|
||||
// .innerJoinAndSelect("post.photos", "photos")
|
||||
.getResults();
|
||||
|
||||
posts[0].title = "Updated Post #1";
|
||||
|
||||
console.log("********************************************************");
|
||||
console.log("posts: ", posts);
|
||||
|
||||
// posts[0].category = null; // todo: uncomment to check remove
|
||||
console.log("removing post's category: ", posts[0]);
|
||||
await connection.entityManager.persist(posts[0]);*/
|
||||
|
||||
/* await connection.entityManager.persist([photo1, photo2]);
|
||||
|
||||
post1.photos = [photo1];
|
||||
await connection.entityManager.persist(post1);
|
||||
|
||||
console.log("********************************************************");
|
||||
console.log("********************************************************");
|
||||
|
||||
post1.photos = [photo1, photo2];
|
||||
|
||||
await connection.entityManager.persist(post1);
|
||||
|
||||
console.log("********************************************************");
|
||||
console.log("********************************************************");
|
||||
|
||||
post1.title = "Updated Post";
|
||||
await connection.entityManager.persist(post1);*/
|
||||
|
||||
})));
|
||||
|
||||
it("should insert entity when cascade option is set", () => Promise.all(connections.map(async connection => {
|
||||
|
||||
// create first category and post and save them
|
||||
const category1 = new Category();
|
||||
category1.name = "Category saved by cascades #1";
|
||||
|
||||
const post1 = new Post();
|
||||
post1.title = "Hello Post #1";
|
||||
post1.category = category1;
|
||||
|
||||
await connection.entityManager.persist(post1);
|
||||
|
||||
// create second category and post and save them
|
||||
const category2 = new Category();
|
||||
category2.name = "Category saved by cascades #2";
|
||||
|
||||
const post2 = new Post();
|
||||
post2.title = "Hello Post #2";
|
||||
post2.category = category2;
|
||||
|
||||
await connection.entityManager.persist(post2);
|
||||
|
||||
// now check
|
||||
const posts = await connection.entityManager.find(Post, {
|
||||
alias: "post",
|
||||
innerJoinAndSelect: {
|
||||
category: "post.category"
|
||||
},
|
||||
orderBy: {
|
||||
"post.id": "ASC"
|
||||
}
|
||||
});
|
||||
|
||||
posts.should.be.eql([{
|
||||
id: 1,
|
||||
title: "Hello Post #1",
|
||||
category: {
|
||||
id: 1,
|
||||
name: "Category saved by cascades #1"
|
||||
}
|
||||
}, {
|
||||
id: 2,
|
||||
title: "Hello Post #2",
|
||||
category: {
|
||||
id: 2,
|
||||
name: "Category saved by cascades #2"
|
||||
}
|
||||
}]);
|
||||
})));
|
||||
|
||||
it("should insert from inverse side when cascade option is set", () => Promise.all(connections.map(async connection => {
|
||||
|
||||
// create first post and category and save them
|
||||
const post1 = new Post();
|
||||
post1.title = "Hello Post #1";
|
||||
|
||||
const category1 = new Category();
|
||||
category1.name = "Category saved by cascades #1";
|
||||
category1.posts = [post1];
|
||||
|
||||
await connection.entityManager.persist(category1);
|
||||
|
||||
// create first post and category and save them
|
||||
const post2 = new Post();
|
||||
post2.title = "Hello Post #2";
|
||||
|
||||
const category2 = new Category();
|
||||
category2.name = "Category saved by cascades #2";
|
||||
category2.posts = [post2];
|
||||
|
||||
await connection.entityManager.persist(category2);
|
||||
|
||||
// now check
|
||||
const posts = await connection.entityManager.find(Post, {
|
||||
alias: "post",
|
||||
innerJoinAndSelect: {
|
||||
category: "post.category"
|
||||
},
|
||||
orderBy: {
|
||||
"post.id": "ASC"
|
||||
}
|
||||
});
|
||||
|
||||
posts.should.be.eql([{
|
||||
id: 1,
|
||||
title: "Hello Post #1",
|
||||
category: {
|
||||
id: 1,
|
||||
name: "Category saved by cascades #1"
|
||||
}
|
||||
}, {
|
||||
id: 2,
|
||||
title: "Hello Post #2",
|
||||
category: {
|
||||
id: 2,
|
||||
name: "Category saved by cascades #2"
|
||||
}
|
||||
}]);
|
||||
})));
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user