refactoring query builder; added tests for query builder insertion

This commit is contained in:
Umed Khudoiberdiev 2017-06-27 15:15:12 +05:00
parent fcde585260
commit 61fb589202
8 changed files with 119 additions and 11 deletions

View File

@ -1,5 +1,6 @@
import {QueryBuilder} from "./QueryBuilder";
import {ObjectLiteral} from "../common/ObjectLiteral";
import {ObjectType} from "../common/ObjectType";
/**
* Allows to build complex sql queries in a fashion way and execute those queries.
@ -27,8 +28,9 @@ export class DeleteQueryBuilder<Entity> extends QueryBuilder<Entity> {
* Specifies FROM which entity's table select/update/delete will be executed.
* Also sets a main string alias of the selection data.
*/
from(entityTarget: Function|string, aliasName: string): this {
return this.setMainAlias(entityTarget, aliasName);
from<T>(entityTarget: ObjectType<T>|string, aliasName: string): DeleteQueryBuilder<T> {
this.setMainAlias(entityTarget, aliasName);
return (this as any) as DeleteQueryBuilder<T>;
}
/**

View File

@ -1,6 +1,7 @@
import {QueryBuilder} from "./QueryBuilder";
import {ObjectLiteral} from "../common/ObjectLiteral";
import {ColumnMetadata} from "../metadata/ColumnMetadata";
import {ObjectType} from "../common/ObjectType";
/**
* Allows to build complex sql queries in a fashion way and execute those queries.
@ -26,8 +27,9 @@ export class InsertQueryBuilder<Entity> extends QueryBuilder<Entity> {
/**
* Specifies INTO which entity's table insertion will be executed.
*/
into(entityTarget: Function|string): this {
return this.setMainAlias(entityTarget);
into<T>(entityTarget: ObjectType<T>|string): InsertQueryBuilder<T> {
this.setMainAlias(entityTarget);
return (this as any) as InsertQueryBuilder<T>;
}
/**
@ -68,9 +70,9 @@ export class InsertQueryBuilder<Entity> extends QueryBuilder<Entity> {
// get values needs to be inserted
const values = valueSets.map((valueSet, key) => {
const columnNames = insertColumns.map(column => {
const paramName = ":_inserted_" + key + "_" + column.databaseName;
const paramName = "_inserted_" + key + "_" + column.databaseName;
this.setParameter(paramName, valueSet[column.propertyName]);
return paramName;
return ":" + paramName;
});
return "(" + columnNames.join(",") + ")";
}).join(", ");

View File

@ -7,6 +7,7 @@ import {UpdateQueryBuilder} from "./UpdateQueryBuilder";
import {DeleteQueryBuilder} from "./DeleteQueryBuilder";
import {InsertQueryBuilder} from "./InsertQueryBuilder";
import {RelationQueryBuilder} from "./RelationQueryBuilder";
import {ObjectType} from "../common/ObjectType";
// todo: completely cover query builder with tests
// todo: entityOrProperty can be target name. implement proper behaviour if it is.
@ -179,7 +180,12 @@ export abstract class QueryBuilder<Entity> {
/**
* Creates UPDATE query for the given entity and applies given update values.
*/
update(entity: Function|string, updateSet: ObjectLiteral): UpdateQueryBuilder<Entity>;
update<T>(entity: ObjectType<T>, updateSet: ObjectLiteral): UpdateQueryBuilder<T>;
/**
* Creates UPDATE query for the given entity and applies given update values.
*/
update(entity: string, updateSet: ObjectLiteral): UpdateQueryBuilder<Entity>;
/**
* Creates UPDATE query for the given table name and applies given update values.
@ -189,7 +195,7 @@ export abstract class QueryBuilder<Entity> {
/**
* Creates UPDATE query and applies given update values.
*/
update(entityOrTableNameUpdateSet?: string|Function|ObjectLiteral, maybeUpdateSet?: ObjectLiteral): UpdateQueryBuilder<Entity> {
update(entityOrTableNameUpdateSet?: string|Function|ObjectLiteral, maybeUpdateSet?: ObjectLiteral): UpdateQueryBuilder<any> {
const updateSet = maybeUpdateSet ? maybeUpdateSet : entityOrTableNameUpdateSet as ObjectLiteral|undefined;
if (entityOrTableNameUpdateSet instanceof Function || typeof entityOrTableNameUpdateSet === "string")

View File

@ -27,6 +27,7 @@ import {EntityMetadata} from "../metadata/EntityMetadata";
import {ColumnMetadata} from "../metadata/ColumnMetadata";
import {OrderByCondition} from "../find-options/OrderByCondition";
import {QueryExpressionMap} from "./QueryExpressionMap";
import {ObjectType} from "../common/ObjectType";
/**
* Allows to build complex sql queries in a fashion way and execute those queries.
@ -99,8 +100,9 @@ export class SelectQueryBuilder<Entity> extends QueryBuilder<Entity> {
* Specifies FROM which entity's table select/update/delete will be executed.
* Also sets a main string alias of the selection data.
*/
from(entityTarget: Function|string, aliasName: string): this {
return this.setMainAlias(entityTarget, aliasName);
from<T>(entityTarget: ObjectType<T>|string, aliasName: string): SelectQueryBuilder<T> {
this.setMainAlias(entityTarget, aliasName);
return (this as any) as SelectQueryBuilder<T>;
}
/**

View File

@ -26,8 +26,9 @@ export class UpdateQueryBuilder<Entity> extends QueryBuilder<Entity> {
/**
* Values needs to be updated.
*/
set(values: Partial<Entity>) {
set(values: Partial<Entity>): this {
this.expressionMap.valuesSet = values;
return this;
}
/**

View File

@ -0,0 +1,14 @@
import {Entity} from "../../../../../src/decorator/entity/Entity";
import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/PrimaryGeneratedColumn";
import {Column} from "../../../../../src/decorator/columns/Column";
@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
}

View File

@ -0,0 +1,14 @@
import {Entity} from "../../../../../src/decorator/entity/Entity";
import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/PrimaryGeneratedColumn";
import {Column} from "../../../../../src/decorator/columns/Column";
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
}

View File

@ -0,0 +1,67 @@
import "reflect-metadata";
import * as chai from "chai";
import {createTestingConnections, closeTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils";
import {Connection} from "../../../../src/connection/Connection";
import {User} from "./entity/User";
const should = chai.should();
describe("query builder > insert", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
schemaCreate: true,
dropSchemaOnConnection: true,
}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("should perform insertion correctly", () => Promise.all(connections.map(async connection => {
const user = new User();
user.name = "Alex Messer";
await connection.createQueryBuilder()
.insert()
.into(User)
.values(user)
.execute();
await connection.createQueryBuilder()
.insert()
.into(User)
.values({
name: "Dima Zotov"
})
.execute();
await connection.createQueryBuilder()
.insert()
.into(User)
.values([
{ name: "Umed Khudoiberdiev" },
{ name: "Bakhrom Baubekov" },
{ name: "Bakhodur Kandikov" },
])
.execute();
await connection.getRepository(User)
.createQueryBuilder("user")
.insert()
.values({ name: "Muhammad Mirzoev" })
.execute();
const users = await connection.getRepository(User).find();
users.should.be.eql([
{ id: 1, name: "Alex Messer" },
{ id: 2, name: "Dima Zotov" },
{ id: 3, name: "Umed Khudoiberdiev" },
{ id: 4, name: "Bakhrom Baubekov" },
{ id: 5, name: "Bakhodur Kandikov" },
{ id: 6, name: "Muhammad Mirzoev" },
]);
})));
});