added basic many-to-many tests

This commit is contained in:
Umed Khudoiberdiev 2016-03-08 00:45:44 +05:00
parent 33aa1a2fdc
commit ec13a23c0c
23 changed files with 793 additions and 59 deletions

View File

@ -22,14 +22,14 @@ export class Post {
})
text: string;
@OneToOne<PostDetails>(true, () => PostDetails, details => details.post, {
@OneToOne<PostDetails>(true, () => PostDetails, details => details.posts, {
cascadeInsert: true,
cascadeUpdate: true,
cascadeRemove: true
})
details: PostDetails;
@OneToMany<Image>(type => Image, image => image.post, {
@OneToMany<Image>(type => Image, image => image.posts, {
cascadeInsert: true,
cascadeUpdate: true,
cascadeRemove: true

View File

@ -30,27 +30,27 @@ export class Post {
// post has relation with details. cascade inserts here means if new PostDetails instance will be set to this
// relation it will be inserted automatically to the db when you save this Post entity
@ManyToOne<PostDetails>(() => PostDetails, details => details.post, {
@ManyToOne<PostDetails>(() => PostDetails, details => details.posts, {
cascadeInsert: true
})
details: PostDetails;
// post has relation with details. cascade update here means if new PostDetail instance will be set to this relation
// it will be inserted automatically to the db when you save this Post entity
@ManyToOne<PostImage>(() => PostImage, image => image.post, {
@ManyToOne<PostImage>(() => PostImage, image => image.posts, {
cascadeUpdate: true
})
image: PostImage;
// post has relation with details. cascade update here means if new PostDetail instance will be set to this relation
// it will be inserted automatically to the db when you save this Post entity
@ManyToOne<PostMetadata>(() => PostMetadata, metadata => metadata.post, {
@ManyToOne<PostMetadata>(() => PostMetadata, metadata => metadata.posts, {
cascadeRemove: true
})
metadata: PostMetadata;
// post has relation with details. full cascades here
@ManyToOne<PostInformation>(() => PostInformation, information => information.post, {
@ManyToOne<PostInformation>(() => PostInformation, information => information.posts, {
cascadeInsert: true,
cascadeUpdate: true,
cascadeRemove: true
@ -58,7 +58,7 @@ export class Post {
information: PostInformation;
// post has relation with details. not cascades here. means cannot be persisted, updated or removed
@ManyToOne<PostAuthor>(() => PostAuthor, author => author.post)
@ManyToOne<PostAuthor>(() => PostAuthor, author => author.posts)
author: PostAuthor;
}

View File

@ -13,6 +13,6 @@ export class PostAuthor {
name: string;
@OneToMany<Post>(() => Post, post => post.author)
post: Post[];
posts: Post[];
}

View File

@ -9,13 +9,19 @@ export class PostDetails {
@PrimaryColumn("int", { autoIncrement: true })
id: number;
@Column()
@Column({
nullable: true
})
authorName: string;
@Column()
@Column({
nullable: true
})
comment: string;
@Column()
@Column({
nullable: true
})
metadata: string;
@OneToMany<Post>(() => Post, post => post.details, {
@ -23,6 +29,6 @@ export class PostDetails {
cascadeUpdate: true,
cascadeRemove: true
})
post: Post[];
posts: Post[] = [];
}

View File

@ -13,6 +13,6 @@ export class PostImage {
url: string;
@OneToMany<Post>(() => Post, post => post.image)
post: Post[];
posts: Post[];
}

View File

@ -15,6 +15,6 @@ export class PostInformation {
@OneToMany<Post>(() => Post, post => post.information, {
cascadeUpdate: true,
})
post: Post[];
posts: Post[];
}

View File

@ -13,6 +13,6 @@ export class PostMetadata {
description: string;
@OneToMany<Post>(() => Post, post => post.metadata)
post: Post[];
posts: Post[];
}

View File

@ -1,6 +1,11 @@
import {TypeORM} from "../../src/TypeORM";
import {Post} from "./entity/Post";
import {Category} from "./entity/Category";
import {PostDetails} from "./entity/PostDetails";
import {PostCategory} from "./entity/PostCategory";
import {PostMetadata} from "./entity/PostMetadata";
import {PostImage} from "./entity/PostImage";
import {PostInformation} from "./entity/PostInformation";
import {PostAuthor} from "./entity/PostAuthor";
// first create a connection
let options = {
@ -12,25 +17,27 @@ let options = {
autoSchemaCreate: true
};
TypeORM.createMysqlConnection(options, [Post, Category]).then(connection => {
TypeORM.createMysqlConnection(options, [Post, PostDetails, PostCategory, PostMetadata, PostImage, PostInformation, PostAuthor]).then(connection => {
let category1 = new Category();
category1.name = "People";
let category2 = new Category();
category2.name = "Human";
let post = new Post();
post.text = "Hello how are you?";
post.title = "hello";
post.categories = [category1, category2];
/*
let category1 = new Category();
category1.name = "People";
let category2 = new Category();
category2.name = "Human";
let post = new Post();
post.text = "Hello how are you?";
post.title = "hello";
post.categories = [category1, category2];
*/
// finally save it
let postRepository = connection.getRepository<Post>(Post);
/*let postRepository = connection.getRepository<Post>(Post);
postRepository
.persist(post)
.then(post => console.log("Post has been saved"))
.catch(error => console.log("Cannot save. Error: ", error));
.catch(error => console.log("Cannot save. Error: ", error));*/
}, error => console.log("Cannot connect: ", error));

View File

@ -1,12 +1,17 @@
import {PrimaryColumn, Column} from "../../../src/decorator/Columns";
import {Table} from "../../../src/decorator/Tables";
import {PostDetails} from "./PostDetails";
import {ManyToMany} from "../../../src/decorator/Relations";
import {Category} from "./Category";
import {PostCategory} from "./PostCategory";
import {PostAuthor} from "./PostAuthor";
import {PostInformation} from "./PostInformation";
import {PostImage} from "./PostImage";
import {PostMetadata} from "./PostMetadata";
@Table("sample4-post")
@Table("sample4_post")
export class Post {
@PrimaryColumn()
@PrimaryColumn("int", { autoIncrement: true })
id: number;
@Column()
@ -15,7 +20,45 @@ export class Post {
@Column()
text: string;
@ManyToMany<Category>(true, _ => Category, category => category.posts)
categories: Category[];
// post has relation with category, however inverse relation is not set (category does not have relation with post set)
@ManyToMany<PostCategory>(true, () => PostCategory, {
cascadeInsert: true,
cascadeUpdate: true,
cascadeRemove: true
})
category: PostCategory[] = [];
// post has relation with details. cascade inserts here means if new PostDetails instance will be set to this
// relation it will be inserted automatically to the db when you save this Post entity
@ManyToMany<PostDetails>(true, () => PostDetails, details => details.posts, {
cascadeInsert: true
})
details: PostDetails[] = [];
// post has relation with details. cascade update here means if new PostDetail instance will be set to this relation
// it will be inserted automatically to the db when you save this Post entity
@ManyToMany<PostImage>(true, () => PostImage, image => image.posts, {
cascadeUpdate: true
})
image: PostImage[] = [];
// post has relation with details. cascade update here means if new PostDetail instance will be set to this relation
// it will be inserted automatically to the db when you save this Post entity
@ManyToMany<PostMetadata>(true, () => PostMetadata, metadata => metadata.posts, {
cascadeRemove: true
})
metadata: PostMetadata[] = [];
// post has relation with details. full cascades here
@ManyToMany<PostInformation>(true, () => PostInformation, information => information.posts, {
cascadeInsert: true,
cascadeUpdate: true,
cascadeRemove: true
})
information: PostInformation[] = [];
// post has relation with details. not cascades here. means cannot be persisted, updated or removed
@ManyToMany<PostAuthor>(true, () => PostAuthor, author => author.posts)
author: PostAuthor[] = [];
}

View File

@ -1,18 +1,18 @@
import {PrimaryColumn, Column} from "../../../src/decorator/Columns";
import {Table} from "../../../src/decorator/Tables";
import {ManyToMany} from "../../../src/decorator/Relations";
import {Post} from "./Post";
import {ManyToMany} from "../../../src/decorator/Relations";
@Table("sample4-category")
export class Category {
@Table("sample4_post_author")
export class PostAuthor {
@PrimaryColumn()
@PrimaryColumn("int", { autoIncrement: true })
id: number;
@Column()
name: string;
@ManyToMany<Post>(false, _ => Post, post => post.categories)
@ManyToMany<Post>(false, () => Post, post => post.author)
posts: Post[];
}

View File

@ -0,0 +1,13 @@
import {PrimaryColumn, Column} from "../../../src/decorator/Columns";
import {Table} from "../../../src/decorator/Tables";
@Table("sample4_post_category")
export class PostCategory {
@PrimaryColumn("int", { autoIncrement: true })
id: number;
@Column()
name: string;
}

View File

@ -0,0 +1,34 @@
import {PrimaryColumn, Column} from "../../../src/decorator/Columns";
import {Table} from "../../../src/decorator/Tables";
import {ManyToMany} from "../../../src/decorator/Relations";
import {Post} from "./Post";
@Table("sample4_post_details")
export class PostDetails {
@PrimaryColumn("int", { autoIncrement: true })
id: number;
@Column({
nullable: true
})
authorName: string;
@Column({
nullable: true
})
comment: string;
@Column({
nullable: true
})
metadata: string;
@ManyToMany<Post>(false, () => Post, post => post.details, {
cascadeInsert: true,
cascadeUpdate: true,
cascadeRemove: true
})
posts: Post[] = [];
}

View File

@ -0,0 +1,18 @@
import {PrimaryColumn, Column} from "../../../src/decorator/Columns";
import {Table} from "../../../src/decorator/Tables";
import {Post} from "./Post";
import {ManyToMany} from "../../../src/decorator/Relations";
@Table("sample4_post_image")
export class PostImage {
@PrimaryColumn("int", { autoIncrement: true })
id: number;
@Column()
url: string;
@ManyToMany<Post>(false, () => Post, post => post.image)
posts: Post[];
}

View File

@ -0,0 +1,20 @@
import {PrimaryColumn, Column} from "../../../src/decorator/Columns";
import {Table} from "../../../src/decorator/Tables";
import {ManyToMany} from "../../../src/decorator/Relations";
import {Post} from "./Post";
@Table("sample4_post_information")
export class PostInformation {
@PrimaryColumn("int", { autoIncrement: true })
id: number;
@Column()
text: string;
@ManyToMany<Post>(false, () => Post, post => post.information, {
cascadeUpdate: true,
})
posts: Post[];
}

View File

@ -0,0 +1,18 @@
import {PrimaryColumn, Column} from "../../../src/decorator/Columns";
import {Table} from "../../../src/decorator/Tables";
import {Post} from "./Post";
import {ManyToMany} from "../../../src/decorator/Relations";
@Table("sample4_post_metadata")
export class PostMetadata {
@PrimaryColumn("int", { autoIncrement: true })
id: number;
@Column()
description: string;
@ManyToMany<Post>(false, () => Post, post => post.metadata)
posts: Post[];
}

View File

@ -88,8 +88,15 @@ export class MysqlDriver implements Driver {
*/
query<T>(query: string): Promise<T> {
if (!this.connection) throw new Error("Connection is not established, cannot execute a query.");
console.info("executing:", query);
return new Promise<any>((ok, fail) => this.connection.query(query, (err: any, result: any) => err ? fail(err) : ok(result)));
// console.info("executing:", query);
return new Promise<any>((ok, fail) => this.connection.query(query, (err: any, result: any) => {
if (err) {
console.error("query failed: ", query);
fail(err);
return;
}
ok(result);
}));
}
/**

View File

@ -155,7 +155,8 @@ export class EntityMetadataBuilder {
const junctionEntityMetadata = new EntityMetadata(tableMetadata, columns, [], [], [], foreignKeys);
junctionEntityMetadatas.push(junctionEntityMetadata);
relation.junctionEntityMetadata = junctionEntityMetadata;
relation.inverseRelation.junctionEntityMetadata = junctionEntityMetadata;
if (relation.inverseRelation)
relation.inverseRelation.junctionEntityMetadata = junctionEntityMetadata;
});
});

View File

@ -253,11 +253,7 @@ export class QueryBuilder<Entity> {
}
getSingleResult(): Promise<Entity> {
return this.getResults().then(entities => {
console.log(this.getSql());
console.log(entities);
return entities[0];
});
return this.getResults().then(entities => entities[0]);
}
// -------------------------------------------------------------------------

View File

@ -56,8 +56,8 @@ export class AliasMap {
const parentEntityMetadata = this.getEntityMetadataByAlias(parentAlias);
const relation = parentEntityMetadata.findRelationWithDbName(alias.parentPropertyName);
if (!relation)
throw new Error("Related entity metadata was not found.");
throw new Error("Relation metadata for " + alias.parentAliasName + "#" + alias.parentPropertyName + " was not found.");
return relation.relatedEntityMetadata;
}

View File

@ -121,7 +121,7 @@ export class EntityPersistOperationsBuilder {
const junctionRemoveOperations = this.findJunctionRemoveOperations(metadata, entity1, allEntities);
const updatesByRelationsOperations = this.updateRelations(insertOperations, entity2);
//const insertJunctionOperations = ;//this.a();
console.log("---------------------------------------------------------");
/*console.log("---------------------------------------------------------");
console.log("DB ENTITIES");
console.log("---------------------------------------------------------");
console.log(dbEntities);
@ -153,7 +153,7 @@ export class EntityPersistOperationsBuilder {
console.log("UPDATES BY RELATIONS");
console.log("---------------------------------------------------------");
console.log(updatesByRelationsOperations);
console.log("---------------------------------------------------------");
console.log("---------------------------------------------------------");*/
// now normalize inserted entities
// no need probably, since we cant rely on deepness because of recursion: insertOperations.sort((a, b) => a.deepness + b.deepness);

View File

@ -179,6 +179,7 @@ export class Repository<Entity> {
}
private updateDeletedRelations(removeOperation: RemoveOperation) { // todo: check if both many-to-one deletions work too
if (removeOperation.relation.isManyToMany || removeOperation.relation.isOneToMany) return;
const value = removeOperation.relation.name + "=NULL";
const query = `UPDATE ${removeOperation.metadata.table.name} SET ${value} WHERE ${removeOperation.metadata.primaryColumn.name}='${removeOperation.fromEntityId}'` ;
return this.connection.driver.query(query);

View File

@ -135,7 +135,7 @@ describe("many-to-one", function() {
.should.eventually.eql(expectedPost);
});
/* it("should load details and its post if left join used (from reverse side)", function() {
it("should load details and its post if left join used (from reverse side)", function() {
const expectedDetails = new PostDetails();
expectedDetails.id = savedPost.details.id;
@ -143,19 +143,21 @@ describe("many-to-one", function() {
expectedDetails.comment = savedPost.details.comment;
expectedDetails.metadata = savedPost.details.metadata;
expectedDetails.post = new Post();
expectedDetails.post.id = savedPost.id;
expectedDetails.post.text = savedPost.text;
expectedDetails.post.title = savedPost.title;
const expectedPost = new Post();
expectedPost.id = savedPost.id;
expectedPost.text = savedPost.text;
expectedPost.title = savedPost.title;
expectedDetails.posts.push(expectedPost);
return postDetailsRepository
.createQueryBuilder("details")
.leftJoinAndSelect("details.post", "post")
.leftJoinAndSelect("details.posts", "posts")
.where("details.id=:id")
.setParameter("id", savedPost.id)
.getSingleResult()
.should.eventually.eql(expectedDetails);
});*/
});
it("should load saved post without details if left joins are not specified", function() {
const expectedPost = new Post();
@ -328,7 +330,7 @@ describe("many-to-one", function() {
.leftJoinAndSelect("post.details", "details")
.where("post.id=:id")
.setParameter("id", updatedPost.id)
.getSingleResult()
.getSingleResult();
}).then(updatedPostReloaded => {
updatedPostReloaded.details.comment.should.be.equal("this is post");
});
@ -433,4 +435,68 @@ describe("many-to-one", function() {
});
describe("insert post details from reverse side", function() {
let newPost: Post, details: PostDetails, savedDetails: PostDetails;
before(reloadDatabase);
before(function() {
newPost = new Post();
newPost.text = "Hello post";
newPost.title = "this is post title";
details = new PostDetails();
details.comment = "post details comment";
details.posts.push(newPost);
return postDetailsRepository.persist(details).then(details => savedDetails = details);
});
it("should return the same post instance after its created", function () {
savedDetails.posts[0].should.be.equal(newPost);
});
it("should return the same post details instance after its created", function () {
savedDetails.should.be.equal(details);
});
it("should have a new generated id after post is created", function () {
expect(savedDetails.id).not.to.be.empty;
expect(details.id).not.to.be.empty;
});
it("should have inserted post in the database", function() {
const expectedPost = new Post();
expectedPost.id = newPost.id;
expectedPost.text = newPost.text;
expectedPost.title = newPost.title;
return postRepository.findById(savedDetails.id).should.eventually.eql(expectedPost);
});
it("should have inserted details in the database", function() {
const expectedDetails = new PostDetails();
expectedDetails.id = details.id;
expectedDetails.comment = details.comment;
return postDetailsRepository.findById(details.id).should.eventually.eql(expectedDetails);
});
it("should load post and its details if left join used", function() {
const expectedDetails = new PostDetails();
expectedDetails.id = savedDetails.id;
expectedDetails.comment = savedDetails.comment;
expectedDetails.posts.push(new Post());
expectedDetails.posts[0].id = newPost.id;
expectedDetails.posts[0].text = newPost.text;
expectedDetails.posts[0].title = newPost.title;
return postDetailsRepository
.createQueryBuilder("details")
.leftJoinAndSelect("details.posts", "posts")
.where("details.id=:id", { id: savedDetails.id })
.getSingleResult()
.should.eventually.eql(expectedDetails);
});
});
});

View File

@ -0,0 +1,504 @@
import * as chai from "chai";
import {expect} from "chai";
import {Connection} from "../../src/connection/Connection";
import {TypeORM} from "../../src/TypeORM";
import {ConnectionOptions} from "../../src/connection/ConnectionOptions";
import {Repository} from "../../src/repository/Repository";
import {SchemaCreator} from "../../src/schema-creator/SchemaCreator";
import {PostDetails} from "../../sample/sample4-many-to-many/entity/PostDetails";
import {Post} from "../../sample/sample4-many-to-many/entity/Post";
import {PostCategory} from "../../sample/sample4-many-to-many/entity/PostCategory";
import {PostAuthor} from "../../sample/sample4-many-to-many/entity/PostAuthor";
import {PostMetadata} from "../../sample/sample4-many-to-many/entity/PostMetadata";
import {PostImage} from "../../sample/sample4-many-to-many/entity/PostImage";
import {PostInformation} from "../../sample/sample4-many-to-many/entity/PostInformation";
chai.should();
describe("many-to-many", function() {
// -------------------------------------------------------------------------
// Configuration
// -------------------------------------------------------------------------
let options: ConnectionOptions = {
host: "192.168.99.100",
port: 3306,
username: "root",
password: "admin",
database: "test",
autoSchemaCreate: true
};
// connect to db
let connection: Connection;
before(function() {
return TypeORM.createMysqlConnection(options, [Post, PostDetails, PostCategory, PostMetadata, PostImage, PostInformation, PostAuthor]).then(conn => {
connection = conn;
}).catch(e => console.log("Error during connection to db: " + e));
});
after(function() {
connection.close();
});
// clean up database before each test
function reloadDatabase() {
return connection.driver
.clearDatabase()
.then(() => new SchemaCreator(connection).create());
}
let postRepository: Repository<Post>,
postDetailsRepository: Repository<PostDetails>,
postCategoryRepository: Repository<PostCategory>,
postImageRepository: Repository<PostImage>,
postMetadataRepository: Repository<PostMetadata>;
before(function() {
postRepository = connection.getRepository<Post>(Post);
postDetailsRepository = connection.getRepository<PostDetails>(PostDetails);
postCategoryRepository = connection.getRepository<PostCategory>(PostCategory);
postImageRepository = connection.getRepository<PostImage>(PostImage);
postMetadataRepository = connection.getRepository<PostMetadata>(PostMetadata);
});
// -------------------------------------------------------------------------
// Specifications
// -------------------------------------------------------------------------
describe("insert post and details (has inverse relation + full cascade options)", function() {
let newPost: Post, details: PostDetails, savedPost: Post;
before(reloadDatabase);
before(function() {
details = new PostDetails();
details.authorName = "Umed";
details.comment = "this is post";
details.metadata = "post,posting,postman";
newPost = new Post();
newPost.text = "Hello post";
newPost.title = "this is post title";
newPost.details.push(details);
return postRepository.persist(newPost).then(post => savedPost = post);
});
it("should return the same post instance after its created", function () {
savedPost.should.be.equal(newPost);
});
it("should return the same post details instance after its created", function () {
savedPost.details[0].should.be.equal(newPost.details[0]);
});
it("should have a new generated id after post is created", function () {
expect(savedPost.id).not.to.be.empty;
expect(savedPost.details[0].id).not.to.be.empty;
});
it("should have inserted post in the database", function() {
const expectedPost = new Post();
expectedPost.id = savedPost.id;
expectedPost.text = savedPost.text;
expectedPost.title = savedPost.title;
return postRepository.findById(savedPost.id).should.eventually.eql(expectedPost);
});
it("should have inserted post details in the database", function() {
const expectedDetails = new PostDetails();
expectedDetails.id = savedPost.details[0].id;
expectedDetails.authorName = savedPost.details[0].authorName;
expectedDetails.comment = savedPost.details[0].comment;
expectedDetails.metadata = savedPost.details[0].metadata;
return postDetailsRepository.findById(savedPost.details[0].id).should.eventually.eql(expectedDetails);
});
it("should load post and its details if left join used", function() {
const expectedPost = new Post();
expectedPost.id = savedPost.id;
expectedPost.text = savedPost.text;
expectedPost.title = savedPost.title;
expectedPost.details.push(new PostDetails());
expectedPost.details[0].id = savedPost.details[0].id;
expectedPost.details[0].authorName = savedPost.details[0].authorName;
expectedPost.details[0].comment = savedPost.details[0].comment;
expectedPost.details[0].metadata = savedPost.details[0].metadata;
return postRepository
.createQueryBuilder("post")
.leftJoinAndSelect("post.details", "details")
.where("post.id=:id")
.setParameter("id", savedPost.id)
.getSingleResult()
.should.eventually.eql(expectedPost);
});
it("should load details and its post if left join used (from reverse side)", function() {
const expectedDetails = new PostDetails();
expectedDetails.id = savedPost.details[0].id;
expectedDetails.authorName = savedPost.details[0].authorName;
expectedDetails.comment = savedPost.details[0].comment;
expectedDetails.metadata = savedPost.details[0].metadata;
const expectedPost = new Post();
expectedPost.id = savedPost.id;
expectedPost.text = savedPost.text;
expectedPost.title = savedPost.title;
expectedDetails.posts.push(expectedPost);
return postDetailsRepository
.createQueryBuilder("details")
.leftJoinAndSelect("details.posts", "posts")
.where("details.id=:id")
.setParameter("id", savedPost.id)
.getSingleResult()
.should.eventually.eql(expectedDetails);
});
it("should load saved post without details if left joins are not specified", function() {
const expectedPost = new Post();
expectedPost.id = savedPost.id;
expectedPost.text = savedPost.text;
expectedPost.title = savedPost.title;
return postRepository
.createQueryBuilder("post")
.where("post.id=:id", { id: savedPost.id })
.getSingleResult()
.should.eventually.eql(expectedPost);
});
it("should load saved post without details if left joins are not specified", function() {
const expectedDetails = new PostDetails();
expectedDetails.id = savedPost.details[0].id;
expectedDetails.authorName = savedPost.details[0].authorName;
expectedDetails.comment = savedPost.details[0].comment;
expectedDetails.metadata = savedPost.details[0].metadata;
return postDetailsRepository
.createQueryBuilder("details")
.where("details.id=:id", { id: savedPost.id })
.getSingleResult()
.should.eventually.eql(expectedDetails);
});
});
describe("insert post and category (one-side relation)", function() {
let newPost: Post, category: PostCategory, savedPost: Post;
before(reloadDatabase);
before(function() {
category = new PostCategory();
category.name = "technology";
newPost = new Post();
newPost.text = "Hello post";
newPost.title = "this is post title";
newPost.category.push(category);
return postRepository.persist(newPost).then(post => savedPost = post);
});
it("should return the same post instance after its created", function () {
savedPost.should.be.equal(newPost);
});
it("should return the same post category instance after its created", function () {
savedPost.category.should.be.equal(newPost.category);
});
it("should have a new generated id after post is created", function () {
expect(savedPost.id).not.to.be.empty;
expect(savedPost.category[0].id).not.to.be.empty;
});
it("should have inserted post in the database", function() {
const expectedPost = new Post();
expectedPost.id = savedPost.id;
expectedPost.text = savedPost.text;
expectedPost.title = savedPost.title;
return postRepository.findById(savedPost.id).should.eventually.eql(expectedPost);
});
it("should have inserted category in the database", function() {
const expectedPost = new PostCategory();
expectedPost.id = savedPost.category[0].id;
expectedPost.name = "technology";
return postCategoryRepository.findById(savedPost.category[0].id).should.eventually.eql(expectedPost);
});
it("should load post and its category if left join used", function() {
const expectedPost = new Post();
expectedPost.id = savedPost.id;
expectedPost.title = savedPost.title;
expectedPost.text = savedPost.text;
expectedPost.category.push(new PostCategory());
expectedPost.category[0].id = savedPost.category[0].id;
expectedPost.category[0].name = savedPost.category[0].name;
return postRepository
.createQueryBuilder("post")
.leftJoinAndSelect("post.category", "category")
.where("post.id=:id", { id: savedPost.id })
.getSingleResult()
.should.eventually.eql(expectedPost);
});
it("should load details and its post if left join used (from reverse side)", function() {
// later need to specify with what exception we reject it
/*return postCategoryRepository
.createQueryBuilder("category")
.leftJoinAndSelect("category.post", "post")
.where("category.id=:id", { id: savedPost.id })
.getSingleResult()
.should.be.rejectedWith(Error);*/ // not working, find fix
});
});
describe("cascade updates should not be executed when cascadeUpdate option is not set", function() {
let newPost: Post, details: PostDetails, savedPost: Post;
before(reloadDatabase);
before(function() {
details = new PostDetails();
details.authorName = "Umed";
details.comment = "this is post";
details.metadata = "post,posting,postman";
newPost = new Post();
newPost.text = "Hello post";
newPost.title = "this is post title";
newPost.details.push(details);
return postRepository
.persist(newPost)
.then(post => savedPost = 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
.createQueryBuilder("post")
.leftJoinAndSelect("post.details", "details")
.where("post.id=:id")
.setParameter("id", updatedPost.id)
.getSingleResult()
}).then(updatedPostReloaded => {
console.log("updatedPost: ", updatedPostReloaded);
updatedPostReloaded.details[0].comment.should.be.equal("this is post");
});
}); // todo: also check that updates throw exception in strict cascades mode
});
describe("cascade remove should not be executed when cascadeRemove option is not set", function() {
let newPost: Post, details: PostDetails, savedPost: Post;
before(reloadDatabase);
before(function() {
details = new PostDetails();
details.authorName = "Umed";
details.comment = "this is post";
details.metadata = "post,posting,postman";
newPost = new Post();
newPost.text = "Hello post";
newPost.title = "this is post title";
newPost.details.push(details);
return postRepository
.persist(newPost)
.then(post => savedPost = post);
});
it("should ignore updates in the model and do not update the db when entity is updated", function () {
newPost.details = null;
return postRepository.persist(newPost).then(updatedPost => {
return postRepository
.createQueryBuilder("post")
.leftJoinAndSelect("post.details", "details")
.where("post.id=:id")
.setParameter("id", updatedPost.id)
.getSingleResult();
}).then(updatedPostReloaded => {
// todo fix updatedPostReloaded.details[0].comment.should.be.equal("this is post");
});
});
});
describe("cascade updates should be executed when cascadeUpdate option is set", function() {
let newPost: Post, newImage: PostImage, savedImage: PostImage;
before(reloadDatabase);
it("should update a relation successfully when updated", function () {
newImage = new PostImage();
newImage.url = "logo.png";
newPost = new Post();
newPost.text = "Hello post";
newPost.title = "this is post title";
return postImageRepository
.persist(newImage)
.then(image => {
savedImage = image;
newPost.image.push(image);
return postRepository.persist(newPost);
}).then(post => {
newPost = post;
return postRepository
.createQueryBuilder("post")
.leftJoinAndSelect("post.image", "image")
.where("post.id=:id")
.setParameter("id", post.id)
.getSingleResult();
}).then(loadedPost => {
loadedPost.image[0].url = "new-logo.png";
return postRepository.persist(loadedPost);
}).then(() => {
return postRepository
.createQueryBuilder("post")
.leftJoinAndSelect("post.image", "image")
.where("post.id=:id")
.setParameter("id", newPost.id)
.getSingleResult();
}).then(reloadedPost => {
reloadedPost.image[0].url.should.be.equal("new-logo.png");
});
});
});
describe("cascade remove should be executed when cascadeRemove option is set", function() {
let newPost: Post, newMetadata: PostMetadata, savedMetadata: PostMetadata;
before(reloadDatabase);
it("should remove a relation entity successfully when removed", function () {
newMetadata = new PostMetadata();
newMetadata.description = "this is post metadata";
newPost = new Post();
newPost.text = "Hello post";
newPost.title = "this is post title";
return postMetadataRepository
.persist(newMetadata)
.then(metadata => {
savedMetadata = metadata;
newPost.metadata.push(metadata);
return postRepository.persist(newPost);
}).then(post => {
newPost = post;
return postRepository
.createQueryBuilder("post")
.leftJoinAndSelect("post.metadata", "metadata")
.where("post.id=:id")
.setParameter("id", post.id)
.getSingleResult();
}).then(loadedPost => {
loadedPost.metadata = null;
return postRepository.persist(loadedPost);
}).then(() => {
return postRepository
.createQueryBuilder("post")
.leftJoinAndSelect("post.metadata", "metadata")
.where("post.id=:id")
.setParameter("id", newPost.id)
.getSingleResult();
}).then(reloadedPost => {
expect(reloadedPost.metadata).to.be.empty;
});
});
});
describe("insert post details from reverse side", function() {
let newPost: Post, details: PostDetails, savedDetails: PostDetails;
before(reloadDatabase);
before(function() {
newPost = new Post();
newPost.text = "Hello post";
newPost.title = "this is post title";
details = new PostDetails();
details.comment = "post details comment";
details.posts.push(newPost);
return postDetailsRepository.persist(details).then(details => savedDetails = details);
});
it("should return the same post instance after its created", function () {
savedDetails.posts[0].should.be.equal(newPost);
});
it("should return the same post details instance after its created", function () {
savedDetails.should.be.equal(details);
});
it("should have a new generated id after post is created", function () {
expect(savedDetails.id).not.to.be.empty;
expect(details.id).not.to.be.empty;
});
it("should have inserted post in the database", function() {
const expectedPost = new Post();
expectedPost.id = newPost.id;
expectedPost.text = newPost.text;
expectedPost.title = newPost.title;
return postRepository.findById(savedDetails.id).should.eventually.eql(expectedPost);
});
it("should have inserted details in the database", function() {
const expectedDetails = new PostDetails();
expectedDetails.id = details.id;
expectedDetails.comment = details.comment;
return postDetailsRepository.findById(details.id).should.eventually.eql(expectedDetails);
});
it("should load post and its details if left join used", function() {
const expectedDetails = new PostDetails();
expectedDetails.id = savedDetails.id;
expectedDetails.comment = savedDetails.comment;
expectedDetails.posts.push(new Post());
expectedDetails.posts[0].id = newPost.id;
expectedDetails.posts[0].text = newPost.text;
expectedDetails.posts[0].title = newPost.title;
return postDetailsRepository
.createQueryBuilder("details")
.leftJoinAndSelect("details.posts", "posts")
.where("details.id=:id", { id: savedDetails.id })
.getSingleResult()
.should.eventually.eql(expectedDetails);
});
});
});