added tests for set/add/remove relation + tests for removeById/removeByIds methods

This commit is contained in:
Umed Khudoiberdiev 2016-05-26 19:06:16 +05:00
parent 24352ef52d
commit 27fe82279c
8 changed files with 667 additions and 11 deletions

View File

@ -183,7 +183,7 @@ export class MysqlDriver extends BaseDriver implements Driver {
const updateValues = this.escapeObjectMap(valuesMap).join(",");
const conditionString = this.escapeObjectMap(conditions).join(" AND ");
const query = `UPDATE ${tableName} SET ${updateValues} ${conditionString ? (" WHERE " + conditionString) : ""}`;
// console.log("executing update: ", query);
console.log("executing update: ", query);
return this.query(query).then(() => {});
// const qb = this.createQueryBuilder().update(tableName, valuesMap).from(tableName, "t");
// Object.keys(conditions).forEach(key => qb.andWhere(key + "=:" + key, { [key]: (<any> conditions)[key] }));

View File

@ -597,7 +597,7 @@ export class QueryBuilder<Entity> {
case "select":
return "SELECT " + allSelects.join(", ") + " FROM " + tableName + " " + alias;
case "delete":
return "DELETE FROM " + tableName + " " + (alias ? alias : "");
return "DELETE " + (alias ? alias : "") + " FROM " + tableName + " " + (alias ? alias : "");
case "update":
const updateSet = Object.keys(this.updateQuerySet).map(key => key + "=:updateQuerySet_" + key);
const params = Object.keys(this.updateQuerySet).reduce((object, key) => {

View File

@ -288,15 +288,17 @@ export class Repository<Entity> {
if (relation.isManyToMany)
throw new Error(`Many-to-many relation is not supported for this operation. Use #addToRelation method for many-to-many relations.`);
let values: any = {}, conditions: any = {};
let table: string, values: any = {}, conditions: any = {};
if (relation.isOwning) {
table = relation.entityMetadata.table.name;
values[relation.name] = relatedEntityId;
conditions[relation.joinColumn.referencedColumn.name] = entityId;
} else {
values[relation.inverseRelation.name] = entityId;
conditions[relation.inverseRelation.joinColumn.referencedColumn.name] = relatedEntityId;
table = relation.inverseEntityMetadata.table.name;
values[relation.inverseRelation.name] = relatedEntityId;
conditions[relation.inverseRelation.joinColumn.referencedColumn.name] = entityId;
}
return this.driver.update(relation.entityMetadata.table.name, values, conditions).then(() => {});
return this.driver.update(table, values, conditions).then(() => {});
}
/**
@ -315,8 +317,8 @@ export class Repository<Entity> {
if (!relation.isManyToMany)
throw new Error(`Only many-to-many relation supported for this operation. However ${this.metadata.name}#${propertyName} relation type is ${relation.relationType}`);
const values: any = { };
relatedEntityIds.forEach(relatedEntityId => {
const insertPromises = relatedEntityIds.map(relatedEntityId => {
const values: any = { };
if (relation.isOwning) {
values[relation.junctionEntityMetadata.columns[0].name] = entityId;
values[relation.junctionEntityMetadata.columns[1].name] = relatedEntityId;
@ -324,8 +326,10 @@ export class Repository<Entity> {
values[relation.junctionEntityMetadata.columns[1].name] = entityId;
values[relation.junctionEntityMetadata.columns[0].name] = relatedEntityId;
}
return this.driver.insert(relation.junctionEntityMetadata.table.name, values)
});
return this.driver.insert(relation.junctionEntityMetadata.table.name, values).then(() => {});
return Promise.all(insertPromises).then(() => {});
}
/**
@ -351,7 +355,7 @@ export class Repository<Entity> {
const secondColumnName = relation.isOwning ? relation.junctionEntityMetadata.columns[1].name : relation.junctionEntityMetadata.columns[0].name;
relatedEntityIds.forEach((relatedEntityId, index) => {
qb.orWhere(`(junctionEntity.${firstColumnName}=:entityId AND junctionEntity.${secondColumnName}=:relatedEntity_${index})`)
qb.orWhere(`(${firstColumnName}=:entityId AND ${secondColumnName}=:relatedEntity_${index})`)
.setParameter("relatedEntity_" + index, relatedEntityId);
});
@ -396,7 +400,7 @@ export class Repository<Entity> {
const alias = this.metadata.table.name;
return this.createQueryBuilder(alias)
.delete()
.where(alias + "." + this.metadata.primaryColumn.propertyName + " IN :ids", { ids: ids })
.where(alias + "." + this.metadata.primaryColumn.propertyName + " IN (:ids)", { ids: ids })
.execute()
.then(() => {});
}

View File

@ -0,0 +1,14 @@
import {Table} from "../../../../../src/decorator/tables/Table";
import {PrimaryColumn} from "../../../../../src/decorator/columns/PrimaryColumn";
import {Column} from "../../../../../src/decorator/columns/Column";
@Table()
export class Post {
@PrimaryColumn("int", { generated: true })
id: number;
@Column()
title: string;
}

View File

@ -0,0 +1,153 @@
import "reflect-metadata";
import * as chai from "chai";
import {expect} from "chai";
import {Connection} from "../../../../src/connection/Connection";
import {Repository} from "../../../../src/repository/Repository";
import {Post} from "./entity/Post";
import {CreateConnectionOptions} from "../../../../src/connection-manager/CreateConnectionOptions";
import {createConnection} from "../../../../src/index";
chai.should();
chai.use(require("sinon-chai"));
chai.use(require("chai-as-promised"));
describe("repository > removeById and removeByIds methods", function() {
// -------------------------------------------------------------------------
// Configuration
// -------------------------------------------------------------------------
const parameters: CreateConnectionOptions = {
driver: "mysql",
connection: {
host: "192.168.99.100",
port: 3306,
username: "root",
password: "admin",
database: "test",
autoSchemaCreate: true,
logging: {
logFailedQueryError: true
}
},
entities: [Post]
};
// connect to db
let connection: Connection;
before(function() {
return createConnection(parameters)
.then(con => connection = con)
.catch(e => {
console.log("Error during connection to db: " + e);
throw e;
});
});
after(function() {
connection.close();
});
// clean up database before each test
function reloadDatabase() {
return connection.syncSchema(true)
.catch(e => console.log("Error during schema re-creation: ", e));
}
let postRepository: Repository<Post>;
before(function() {
postRepository = connection.getRepository(Post);
});
// -------------------------------------------------------------------------
// Specifications
// -------------------------------------------------------------------------
describe("remove using removeById method", function() {
let loadedPosts: Post[];
before(reloadDatabase);
// save a new posts
before(function() {
const newPost1 = postRepository.create();
newPost1.title = "Super post #1";
const newPost2 = postRepository.create();
newPost2.title = "Super post #2";
const newPost3 = postRepository.create();
newPost3.title = "Super post #3";
const newPost4 = postRepository.create();
newPost4.title = "Super post #4";
return Promise.all([
postRepository.persist(newPost1),
postRepository.persist(newPost2),
postRepository.persist(newPost3),
postRepository.persist(newPost4)
]);
});
// remove one
before(function() {
return postRepository.removeById(1);
});
// load to check
before(function() {
return postRepository.find().then(posts => loadedPosts = posts);
});
it("should delete successfully", function () {
loadedPosts.length.should.be.equal(3);
expect(loadedPosts.find(p => p.id === 1)).to.be.empty;
expect(loadedPosts.find(p => p.id === 2)).not.to.be.empty;
expect(loadedPosts.find(p => p.id === 3)).not.to.be.empty;
expect(loadedPosts.find(p => p.id === 4)).not.to.be.empty;
});
});
describe("remove using removeByIds method", function() {
let loadedPosts: Post[];
before(reloadDatabase);
// save a new posts
before(function() {
const newPost1 = postRepository.create();
newPost1.title = "Super post #1";
const newPost2 = postRepository.create();
newPost2.title = "Super post #2";
const newPost3 = postRepository.create();
newPost3.title = "Super post #3";
const newPost4 = postRepository.create();
newPost4.title = "Super post #4";
return Promise.all([
postRepository.persist(newPost1),
postRepository.persist(newPost2),
postRepository.persist(newPost3),
postRepository.persist(newPost4)
]);
});
// remove one
before(function() {
return postRepository.removeByIds([2, 3]);
});
// load to check
before(function() {
return postRepository.find().then(posts => loadedPosts = posts);
});
it("should delete successfully", function () {
loadedPosts.length.should.be.equal(2);
expect(loadedPosts.find(p => p.id === 1)).not.to.be.empty;
expect(loadedPosts.find(p => p.id === 2)).to.be.empty;
expect(loadedPosts.find(p => p.id === 3)).to.be.empty;
expect(loadedPosts.find(p => p.id === 4)).not.to.be.empty;
});
});
});

View File

@ -0,0 +1,23 @@
import {Table} from "../../../../../src/decorator/tables/Table";
import {PrimaryColumn} from "../../../../../src/decorator/columns/PrimaryColumn";
import {Post} from "./Post";
import {Column} from "../../../../../src/decorator/columns/Column";
import {ManyToOne} from "../../../../../src/decorator/relations/ManyToOne";
import {ManyToMany} from "../../../../../src/decorator/relations/ManyToMany";
@Table()
export class Category {
@PrimaryColumn("int", { generated: true })
id: number;
@Column()
name: string;
@ManyToOne(type => Post, post => post.categories)
post: Post;
@ManyToMany(type => Post, post => post.manyCategories)
manyPosts: Post[];
}

View File

@ -0,0 +1,25 @@
import {Category} from "./Category";
import {Table} from "../../../../../src/decorator/tables/Table";
import {PrimaryColumn} from "../../../../../src/decorator/columns/PrimaryColumn";
import {Column} from "../../../../../src/decorator/columns/Column";
import {OneToMany} from "../../../../../src/decorator/relations/OneToMany";
import {ManyToMany} from "../../../../../src/decorator/relations/ManyToMany";
import {JoinTable} from "../../../../../src/decorator/relations/JoinTable";
@Table()
export class Post {
@PrimaryColumn("int", { generated: true })
id: number;
@Column()
title: string;
@OneToMany(type => Category, category => category.post)
categories: Category[]|null;
@ManyToMany(type => Category, category => category.manyPosts)
@JoinTable()
manyCategories: Category[];
}

View File

@ -0,0 +1,437 @@
import "reflect-metadata";
import * as chai from "chai";
import {expect} from "chai";
import {Connection} from "../../../../src/connection/Connection";
import {Repository} from "../../../../src/repository/Repository";
import {Post} from "./entity/Post";
import {Category} from "./entity/Category";
import {CreateConnectionOptions} from "../../../../src/connection-manager/CreateConnectionOptions";
import {createConnection} from "../../../../src/index";
chai.should();
chai.use(require("sinon-chai"));
chai.use(require("chai-as-promised"));
describe("repository > set/add/remove relation methods", function() {
// -------------------------------------------------------------------------
// Configuration
// -------------------------------------------------------------------------
const parameters: CreateConnectionOptions = {
driver: "mysql",
connection: {
host: "192.168.99.100",
port: 3306,
username: "root",
password: "admin",
database: "test",
autoSchemaCreate: true,
logging: {
logFailedQueryError: true
}
},
entities: [Post, Category]
};
// connect to db
let connection: Connection;
before(function() {
return createConnection(parameters)
.then(con => connection = con)
.catch(e => {
console.log("Error during connection to db: " + e);
throw e;
});
});
after(function() {
connection.close();
});
// clean up database before each test
function reloadDatabase() {
return connection.syncSchema(true)
.catch(e => console.log("Error during schema re-creation: ", e));
}
let postRepository: Repository<Post>;
let categoryRepository: Repository<Category>;
before(function() {
postRepository = connection.getRepository(Post);
categoryRepository = connection.getRepository(Category);
});
// -------------------------------------------------------------------------
// Specifications
// -------------------------------------------------------------------------
describe("add elements to many-to-many from owner side", function() {
let newPost: Post, newCategory1: Category, newCategory2: Category, loadedPost: Post;
before(reloadDatabase);
// save a new category
before(function () {
newCategory1 = categoryRepository.create();
newCategory1.name = "Animals";
return categoryRepository.persist(newCategory1);
});
// save a new category
before(function () {
newCategory2 = categoryRepository.create();
newCategory2.name = "Kids";
return categoryRepository.persist(newCategory2);
});
// save a new post
before(function() {
newPost = postRepository.create();
newPost.title = "Super post";
return postRepository.persist(newPost);
});
// add categories to a post
before(function() {
return postRepository.addToRelation(post => post.manyCategories, newPost.id, [newCategory1.id, newCategory2.id]);
});
// load a post, want to have categories count
before(function() {
return postRepository
.findOneById(1, { alias: "post", leftJoinAndSelect: { manyCategories: "post.manyCategories" } })
.then(post => loadedPost = post);
});
it("should save successfully", function () {
expect(loadedPost).not.to.be.empty;
expect(loadedPost.manyCategories).not.to.be.empty;
if (loadedPost.manyCategories) {
expect(loadedPost.manyCategories[0]).not.to.be.empty;
expect(loadedPost.manyCategories[1]).not.to.be.empty;
}
});
});
describe("add elements to many-to-many from inverse side", function() {
let newPost1: Post, newPost2: Post, newCategory: Category, loadedCategory: Category;
before(reloadDatabase);
// save a new post
before(function () {
newPost1 = postRepository.create();
newPost1.title = "post #1";
return postRepository.persist(newPost1);
});
// save a new post
before(function () {
newPost2 = postRepository.create();
newPost2.title = "post #2";
return postRepository.persist(newPost2);
});
// save a new category
before(function () {
newCategory = categoryRepository.create();
newCategory.name = "Kids";
return categoryRepository.persist(newCategory);
});
// add categories to a post
before(function() {
return categoryRepository.addToRelation(category => category.manyPosts, newCategory.id, [newPost1.id, newPost2.id]);
});
// load a post, want to have categories count
before(function() {
return categoryRepository
.findOneById(1, { alias: "category", leftJoinAndSelect: { manyPosts: "category.manyPosts" } })
.then(category => loadedCategory = category);
});
it("should save successfully", function () {
expect(loadedCategory).not.to.be.empty;
expect(loadedCategory.manyPosts).not.to.be.empty;
if (loadedCategory.manyPosts) {
expect(loadedCategory.manyPosts[0]).not.to.be.empty;
expect(loadedCategory.manyPosts[1]).not.to.be.empty;
}
});
});
describe("remove elements to many-to-many from owner side", function() {
let newPost: Post, newCategory1: Category, newCategory2: Category, newCategory3: Category, loadedPost: Post;
before(reloadDatabase);
// save a new category
before(function () {
newCategory1 = categoryRepository.create();
newCategory1.name = "Animals";
return categoryRepository.persist(newCategory1);
});
// save a new category
before(function () {
newCategory2 = categoryRepository.create();
newCategory2.name = "Kids";
return categoryRepository.persist(newCategory2);
});
// save a new category
before(function () {
newCategory3 = categoryRepository.create();
newCategory3.name = "Adults";
return categoryRepository.persist(newCategory3);
});
// save a new post with categories
before(function() {
newPost = postRepository.create();
newPost.title = "Super post";
newPost.manyCategories = [newCategory1, newCategory2, newCategory3];
return postRepository.persist(newPost);
});
// add categories to a post
before(function() {
return postRepository.removeFromRelation(post => post.manyCategories, newPost.id, [newCategory1.id, newCategory3.id]);
});
// load a post, want to have categories count
before(function() {
return postRepository
.findOneById(1, { alias: "post", leftJoinAndSelect: { manyCategories: "post.manyCategories" } })
.then(post => loadedPost = post);
});
it("should remove successfully", function () {
expect(loadedPost).not.to.be.empty;
expect(loadedPost.manyCategories).not.to.be.empty;
loadedPost.manyCategories.length.should.be.equal(1);
if (loadedPost.manyCategories) {
loadedPost.manyCategories[0].name.should.be.equal("Kids");
}
});
});
describe("remove elements to many-to-many from inverse side", function() {
let newCategory: Category, newPost1: Post, newPost2: Post, newPost3: Post, loadedCategory: Category;
before(reloadDatabase);
// save a new category
before(function () {
newPost1 = postRepository.create();
newPost1.title = "post #1";
return postRepository.persist(newPost1);
});
// save a new category
before(function () {
newPost2 = postRepository.create();
newPost2.title = "post #2";
return postRepository.persist(newPost2);
});
// save a new category
before(function () {
newPost3 = postRepository.create();
newPost3.title = "post #3";
return postRepository.persist(newPost3);
});
// save a new post with categories
before(function() {
newCategory = categoryRepository.create();
newCategory.name = "SuperCategory";
newCategory.manyPosts = [newPost1, newPost2, newPost3];
return categoryRepository.persist(newCategory);
});
// add categories to a post
before(function() {
return categoryRepository.removeFromRelation(post => post.manyPosts, newCategory.id, [newPost1.id, newPost3.id]);
});
// load a post, want to have categories count
before(function() {
return categoryRepository
.findOneById(1, { alias: "category", leftJoinAndSelect: { manyPosts: "category.manyPosts" } })
.then(category => loadedCategory = category);
});
it("should remove successfully", function () {
expect(loadedCategory).not.to.be.empty;
expect(loadedCategory.manyPosts).not.to.be.empty;
loadedCategory.manyPosts.length.should.be.equal(1);
if (loadedCategory.manyPosts) {
loadedCategory.manyPosts[0].title.should.be.equal("post #2");
}
});
});
describe("set element to one-to-many relation", function() {
let newPost: Post, newCategory1: Category, loadedPost: Post;
before(reloadDatabase);
// save a new category
before(function () {
newCategory1 = categoryRepository.create();
newCategory1.name = "Animals";
return categoryRepository.persist(newCategory1);
});
// save a new post
before(function() {
newPost = postRepository.create();
newPost.title = "Super post";
return postRepository.persist(newPost);
});
// add categories to a post
before(function() {
return postRepository.setRelation(post => post.categories, newPost.id, newCategory1.id);
});
// load a post, want to have categories count
before(function() {
return postRepository
.findOneById(1, { alias: "post", leftJoinAndSelect: { categories: "post.categories" } })
.then(post => loadedPost = post);
});
it("should save successfully", function () {
expect(loadedPost).not.to.be.empty;
expect(loadedPost.categories).not.to.be.empty;
if (loadedPost.categories) {
expect(loadedPost.categories[0]).not.to.be.empty;
}
});
});
describe("set element to many-to-one relation", function() {
let newCategory: Category, newPost: Post, loadedCategory: Category;
before(reloadDatabase);
// save a new category
before(function () {
newPost = postRepository.create();
newPost.title = "post #1";
return postRepository.persist(newPost);
});
// save a new category
before(function () {
newCategory = categoryRepository.create();
newCategory.name = "Kids";
return categoryRepository.persist(newCategory);
});
// add categories to a post
before(function() {
return categoryRepository.setRelation(category => category.post, newCategory.id, newPost.id);
});
// load a post, want to have categories count
before(function() {
return categoryRepository
.findOneById(1, { alias: "category", leftJoinAndSelect: { post: "category.post" } })
.then(category => loadedCategory = category);
});
it("should save successfully", function () {
expect(loadedCategory).not.to.be.empty;
expect(loadedCategory.post).not.to.be.empty;
});
});
describe("set element to NULL in one-to-many relation", function() {
let newPost: Post, newCategory1: Category, loadedPost: Post;
before(reloadDatabase);
// save a new category
before(function () {
newCategory1 = categoryRepository.create();
newCategory1.name = "Animals";
return categoryRepository.persist(newCategory1);
});
// save a new post
before(function() {
newPost = postRepository.create();
newPost.title = "Super post";
newPost.categories = [newCategory1];
return postRepository.persist(newPost);
});
// add categories to a post
before(function() {
return postRepository.setRelation(post => post.categories, newPost.id, null);
});
// load a post, want to have categories count
before(function() {
return postRepository
.findOneById(1, { alias: "post", leftJoinAndSelect: { categories: "post.categories" } })
.then(post => loadedPost = post);
});
it("should save successfully", function () {
expect(loadedPost).not.to.be.empty;
expect(loadedPost.categories).to.be.empty;
});
});
describe("set element to NULL in many-to-one relation", function() {
let newCategory: Category, newPost: Post, loadedCategory: Category;
before(reloadDatabase);
// save a new category
before(function () {
newPost = postRepository.create();
newPost.title = "post #1";
return postRepository.persist(newPost);
});
// save a new category
before(function () {
newCategory = categoryRepository.create();
newCategory.name = "Kids";
newCategory.post = newPost;
return categoryRepository.persist(newCategory);
});
// add categories to a post
before(function() {
return categoryRepository.setRelation(category => category.post, newCategory.id, null);
});
// load a post, want to have categories count
before(function() {
return categoryRepository
.findOneById(1, { alias: "category", leftJoinAndSelect: { post: "category.post" } })
.then(category => loadedCategory = category);
});
it("should save successfully", function () {
expect(loadedCategory).not.to.be.empty;
expect(loadedCategory.post).to.be.empty;
});
});
});