added basic many-to-one samples and tests

This commit is contained in:
Umed Khudoiberdiev 2016-03-07 22:43:13 +05:00
parent 3c7ff278f6
commit 33aa1a2fdc
10 changed files with 600 additions and 20 deletions

View File

@ -1,6 +1,11 @@
import {TypeORM} from "../../src/TypeORM";
import {Post} from "./entity/Post";
import {Comment} from "./entity/Comment";
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,19 +17,18 @@ let options = {
autoSchemaCreate: true
};
TypeORM.createMysqlConnection(options, [Post, Comment]).then(connection => {
TypeORM.createMysqlConnection(options, [Post, PostDetails, PostCategory, PostMetadata, PostImage, PostInformation, PostAuthor]).then(connection => {
let comment1 = new Comment();
comment1.text = "Hello world";
let comment2 = new Comment();
comment2.text = "Bye world";
let details = new PostDetails();
details.authorName = "Umed";
details.comment = "about post";
details.metadata = "post,details,one-to-one";
let post = new Post();
post.text = "Hello how are you?";
post.title = "hello";
post.comments = [comment1, comment2];
post.details = details;
// finally save it
let postRepository = connection.getRepository<Post>(Post);
postRepository

View File

@ -1,9 +1,14 @@
import {PrimaryColumn, Column} from "../../../src/decorator/Columns";
import {Table} from "../../../src/decorator/Tables";
import {OneToMany} from "../../../src/decorator/Relations";
import {Comment} from "./Comment";
import {PostDetails} from "./PostDetails";
import {ManyToOne} from "../../../src/decorator/Relations";
import {PostCategory} from "./PostCategory";
import {PostAuthor} from "./PostAuthor";
import {PostInformation} from "./PostInformation";
import {PostImage} from "./PostImage";
import {PostMetadata} from "./PostMetadata";
@Table("sample3-post")
@Table("sample3_post")
export class Post {
@PrimaryColumn("int", { autoIncrement: true })
@ -15,7 +20,45 @@ export class Post {
@Column()
text: string;
@OneToMany<Comment>(_ => Comment, comment => comment.post)
comments: Comment[];
// post has relation with category, however inverse relation is not set (category does not have relation with post set)
@ManyToOne<PostCategory>(() => 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
@ManyToOne<PostDetails>(() => PostDetails, details => details.post, {
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, {
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, {
cascadeRemove: true
})
metadata: PostMetadata;
// post has relation with details. full cascades here
@ManyToOne<PostInformation>(() => PostInformation, information => information.post, {
cascadeInsert: true,
cascadeUpdate: true,
cascadeRemove: true
})
information: PostInformation;
// post has relation with details. not cascades here. means cannot be persisted, updated or removed
@ManyToOne<PostAuthor>(() => PostAuthor, author => author.post)
author: PostAuthor;
}

View File

@ -0,0 +1,18 @@
import {PrimaryColumn, Column} from "../../../src/decorator/Columns";
import {Table} from "../../../src/decorator/Tables";
import {Post} from "./Post";
import {OneToMany} from "../../../src/decorator/Relations";
@Table("sample3_post_author")
export class PostAuthor {
@PrimaryColumn("int", { autoIncrement: true })
id: number;
@Column()
name: string;
@OneToMany<Post>(() => Post, post => post.author)
post: Post[];
}

View File

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

View File

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

View File

@ -1,18 +1,18 @@
import {PrimaryColumn, Column} from "../../../src/decorator/Columns";
import {Table} from "../../../src/decorator/Tables";
import {ManyToOne} from "../../../src/decorator/Relations";
import {Post} from "./Post";
import {OneToMany} from "../../../src/decorator/Relations";
@Table("sample3-comment")
export class Comment {
@Table("sample3_post_image")
export class PostImage {
@PrimaryColumn("int", { autoIncrement: true })
id: number;
@Column()
text: string;
url: string;
@ManyToOne<Post>(_ => Post, post => post.comments)
post: Post;
@OneToMany<Post>(() => Post, post => post.image)
post: Post[];
}

View File

@ -0,0 +1,20 @@
import {PrimaryColumn, Column} from "../../../src/decorator/Columns";
import {Table} from "../../../src/decorator/Tables";
import {OneToMany} from "../../../src/decorator/Relations";
import {Post} from "./Post";
@Table("sample3_post_information")
export class PostInformation {
@PrimaryColumn("int", { autoIncrement: true })
id: number;
@Column()
text: string;
@OneToMany<Post>(() => Post, post => post.information, {
cascadeUpdate: true,
})
post: 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 {OneToMany} from "../../../src/decorator/Relations";
@Table("sample3_post_metadata")
export class PostMetadata {
@PrimaryColumn("int", { autoIncrement: true })
id: number;
@Column()
description: string;
@OneToMany<Post>(() => Post, post => post.metadata)
post: Post[];
}

View File

@ -14,7 +14,7 @@ import {PostImage} from "../../sample/sample2-one-to-one/entity/PostImage";
import {PostInformation} from "../../sample/sample2-one-to-one/entity/PostInformation";
chai.should();
describe("insertion", function() {
describe("one-to-one", function() {
// -------------------------------------------------------------------------
// Configuration

View File

@ -0,0 +1,436 @@
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/sample3-many-to-one/entity/PostDetails";
import {Post} from "../../sample/sample3-many-to-one/entity/Post";
import {PostCategory} from "../../sample/sample3-many-to-one/entity/PostCategory";
import {PostAuthor} from "../../sample/sample3-many-to-one/entity/PostAuthor";
import {PostMetadata} from "../../sample/sample3-many-to-one/entity/PostMetadata";
import {PostImage} from "../../sample/sample3-many-to-one/entity/PostImage";
import {PostInformation} from "../../sample/sample3-many-to-one/entity/PostInformation";
chai.should();
describe("many-to-one", 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 = 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.should.be.equal(newPost.details);
});
it("should have a new generated id after post is created", function () {
expect(savedPost.id).not.to.be.empty;
expect(savedPost.details.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.id;
expectedDetails.authorName = savedPost.details.authorName;
expectedDetails.comment = savedPost.details.comment;
expectedDetails.metadata = savedPost.details.metadata;
return postDetailsRepository.findById(savedPost.details.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 = new PostDetails();
expectedPost.details.id = savedPost.details.id;
expectedPost.details.authorName = savedPost.details.authorName;
expectedPost.details.comment = savedPost.details.comment;
expectedPost.details.metadata = savedPost.details.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.id;
expectedDetails.authorName = savedPost.details.authorName;
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;
return postDetailsRepository
.createQueryBuilder("details")
.leftJoinAndSelect("details.post", "post")
.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.id;
expectedDetails.authorName = savedPost.details.authorName;
expectedDetails.comment = savedPost.details.comment;
expectedDetails.metadata = savedPost.details.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 = 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.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.id;
expectedPost.name = "technology";
return postCategoryRepository.findById(savedPost.category.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 = new PostCategory();
expectedPost.category.id = savedPost.category.id;
expectedPost.category.name = savedPost.category.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 = 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.comment = "i am updated comment";
return postRepository.persist(newPost).then(updatedPost => {
updatedPost.details.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 => {
updatedPostReloaded.details.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 = 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 => {
updatedPostReloaded.details.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 = 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.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.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 = 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;
});
});
});
});