mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
refactored relations between connection, driver and other classes
This commit is contained in:
parent
31f0c0b2e8
commit
ac5bb23955
@ -11,7 +11,7 @@ First you need to create a new subscriber class and implement `EventSubscriberIn
|
||||
|
||||
```typescript
|
||||
import {EventSubscriber, UpdateEvent, RemoveEvent, InsertEvent} from "typeorm/listeners"
|
||||
import {EventSubscriberInterface} from "typeorm/subscriber/EventSubscriberInterface";
|
||||
import {EventSubscriberInterface} from "typeorm/typeorm";
|
||||
|
||||
@EventSubscriber()
|
||||
export class MySubscriber implements EventSubscriberInterface<any> {
|
||||
@ -80,13 +80,7 @@ You can also use listeners in your entities. Such listeners can be convenient fo
|
||||
|
||||
```typescript
|
||||
import {Table} from "typeorm/tables";
|
||||
import {AfterLoad} from "typeorm/decorator/listeners/AfterLoad";
|
||||
import {AfterInsert} from "typeorm/decorator/listeners/AfterInsert";
|
||||
import {BeforeInsert} from "typeorm/decorator/listeners/BeforeInsert";
|
||||
import {BeforeUpdate} from "typeorm/decorator/listeners/BeforeUpdate";
|
||||
import {AfterUpdate} from "typeorm/decorator/listeners/AfterUpdate";
|
||||
import {BeforeRemove} from "typeorm/decorator/listeners/BeforeRemove";
|
||||
import {AfterRemove} from "typeorm/decorator/listeners/AfterRemove";
|
||||
import {AfterLoad, AfterInsert, BeforeInsert, BeforeUpdate, AfterUpdate, BeforeRemove, AfterRemove} from "typeorm/listeners";
|
||||
|
||||
@Table("posts")
|
||||
export class Post {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "typeorm",
|
||||
"private": true,
|
||||
"version": "0.0.2-alpha.6",
|
||||
"version": "0.0.2-alpha.7",
|
||||
"description": "Data-mapper ORM for Typescript",
|
||||
"license": "Apache-2.0",
|
||||
"readmeFilename": "README.md",
|
||||
|
||||
@ -69,7 +69,7 @@ export class Connection {
|
||||
constructor(name: string, driver: Driver, options: ConnectionOptions) {
|
||||
this.name = name;
|
||||
this.driver = driver;
|
||||
this.driver.connection = this;
|
||||
this.driver.connectionOptions = options;
|
||||
this.options = options;
|
||||
this.entityManager = new EntityManager(this);
|
||||
}
|
||||
@ -113,7 +113,8 @@ export class Connection {
|
||||
* Gets repository for the given entity class.
|
||||
*/
|
||||
getRepository<Entity>(entityClass: ConstructorFunction<Entity>|Function): Repository<Entity> {
|
||||
const metadata = this.getEntityMetadata(entityClass);
|
||||
// const metadata = this.getEntityMetadata(entityClass);
|
||||
const metadata = this.entityMetadatas.find(metadata => metadata.target === entityClass);
|
||||
const repoMeta = this.repositoryAndMetadatas.find(repoMeta => repoMeta.metadata === metadata);
|
||||
if (!repoMeta)
|
||||
throw new RepositoryNotFoundError(entityClass);
|
||||
@ -164,7 +165,7 @@ export class Connection {
|
||||
private createRepoMeta(metadata: EntityMetadata): RepositoryAndMetadata {
|
||||
return {
|
||||
metadata: metadata,
|
||||
repository: new Repository<any>(this, metadata)
|
||||
repository: new Repository<any>(this, this.entityMetadatas, metadata)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {Connection} from "../connection/Connection";
|
||||
import {ConnectionOptions} from "../connection/ConnectionOptions";
|
||||
|
||||
/**
|
||||
* Provides base functionality for all driver implementations.
|
||||
@ -10,34 +10,34 @@ export abstract class BaseDriver {
|
||||
// Properties
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
connection: Connection;
|
||||
abstract connectionOptions: ConnectionOptions;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Protected Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
protected logQuery(query: string) {
|
||||
if (this.connection.options.logging && this.connection.options.logging.logQueries)
|
||||
if (this.connectionOptions.logging && this.connectionOptions.logging.logQueries)
|
||||
this.log("executing query: " + query, "log");
|
||||
}
|
||||
|
||||
protected logQueryError(error: any) {
|
||||
if (this.connection.options.logging && this.connection.options.logging.logFailedQueryError) {
|
||||
if (this.connectionOptions.logging && this.connectionOptions.logging.logFailedQueryError) {
|
||||
this.log("error during executing query:", "error");
|
||||
this.log(error, "error");
|
||||
}
|
||||
}
|
||||
|
||||
protected logFailedQuery(query: string) {
|
||||
if (this.connection.options.logging &&
|
||||
(this.connection.options.logging.logQueries || this.connection.options.logging.logOnlyFailedQueries))
|
||||
if (this.connectionOptions.logging &&
|
||||
(this.connectionOptions.logging.logQueries || this.connectionOptions.logging.logOnlyFailedQueries))
|
||||
this.log("query failed: " + query, "error");
|
||||
}
|
||||
|
||||
protected log(message: any, level: "log"|"debug"|"info"|"error") {
|
||||
if (!this.connection.options.logging) return;
|
||||
if (this.connection.options && this.connection.options.logging && this.connection.options.logging.logger) {
|
||||
this.connection.options.logging.logger(message, level);
|
||||
if (!this.connectionOptions.logging) return;
|
||||
if (this.connectionOptions && this.connectionOptions.logging && this.connectionOptions.logging.logger) {
|
||||
this.connectionOptions.logging.logger(message, level);
|
||||
} else {
|
||||
switch (level) {
|
||||
case "log":
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import {SchemaBuilder} from "../schema-builder/SchemaBuilder";
|
||||
import {QueryBuilder} from "../query-builder/QueryBuilder";
|
||||
import {Connection} from "../connection/Connection";
|
||||
import {ColumnMetadata} from "../metadata-builder/metadata/ColumnMetadata";
|
||||
import {ConnectionOptions} from "../connection/ConnectionOptions";
|
||||
|
||||
/**
|
||||
* Driver communicates with specific database.
|
||||
@ -19,9 +18,9 @@ export interface Driver {
|
||||
readonly nativeConnection: any;
|
||||
|
||||
/**
|
||||
* Connection used in this driver.
|
||||
* Connection options used in this driver.
|
||||
*/
|
||||
connection: Connection;
|
||||
connectionOptions: ConnectionOptions;
|
||||
|
||||
/**
|
||||
* Database name to which this connection is made.
|
||||
@ -31,7 +30,7 @@ export interface Driver {
|
||||
/**
|
||||
* Creates a query builder which can be used to build an sql queries.
|
||||
*/
|
||||
createQueryBuilder<Entity>(): QueryBuilder<Entity>;
|
||||
readonly queryBuilderClass: Function;
|
||||
|
||||
/**
|
||||
* Creates a schema builder which can be used to build database/table schemas.
|
||||
|
||||
@ -2,12 +2,12 @@ import {Driver} from "./Driver";
|
||||
import {SchemaBuilder} from "../schema-builder/SchemaBuilder";
|
||||
import {QueryBuilder} from "../query-builder/QueryBuilder";
|
||||
import {MysqlSchemaBuilder} from "../schema-builder/MysqlSchemaBuilder";
|
||||
import {Connection} from "../connection/Connection";
|
||||
import {ConnectionIsNotSetError} from "./error/ConnectionIsNotSetError";
|
||||
import {BaseDriver} from "./BaseDriver";
|
||||
import {ColumnMetadata} from "../metadata-builder/metadata/ColumnMetadata";
|
||||
import {ColumnTypes} from "../metadata-builder/types/ColumnTypes";
|
||||
import * as moment from "moment";
|
||||
import {ConnectionOptions} from "../connection/ConnectionOptions";
|
||||
|
||||
/**
|
||||
* This driver organizes work with mysql database.
|
||||
@ -21,7 +21,7 @@ export class MysqlDriver extends BaseDriver implements Driver {
|
||||
/**
|
||||
* Connection used in this driver.
|
||||
*/
|
||||
connection: Connection;
|
||||
connectionOptions: ConnectionOptions;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Private Properties
|
||||
@ -62,8 +62,8 @@ export class MysqlDriver extends BaseDriver implements Driver {
|
||||
if (this.mysqlConnection && this.mysqlConnection.config.database)
|
||||
return this.mysqlConnection.config.database;
|
||||
|
||||
if (this.connection.options.database)
|
||||
return this.connection.options.database;
|
||||
if (this.connectionOptions.database)
|
||||
return this.connectionOptions.database;
|
||||
|
||||
throw new Error("Cannot get the database name. Since database name is not explicitly given in configuration " +
|
||||
"(maybe connection url is used?), database name cannot be retrieved until connection is made.");
|
||||
@ -97,8 +97,8 @@ export class MysqlDriver extends BaseDriver implements Driver {
|
||||
/**
|
||||
* Creates a query builder which can be used to build an sql queries.
|
||||
*/
|
||||
createQueryBuilder<Entity>(): QueryBuilder<Entity> {
|
||||
return new QueryBuilder<Entity>(this.connection);
|
||||
get queryBuilderClass() {
|
||||
return QueryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -113,10 +113,10 @@ export class MysqlDriver extends BaseDriver implements Driver {
|
||||
*/
|
||||
connect(): Promise<void> {
|
||||
this.mysqlConnection = this.mysql.createConnection({
|
||||
host: this.connection.options.host,
|
||||
user: this.connection.options.username,
|
||||
password: this.connection.options.password,
|
||||
database: this.connection.options.database
|
||||
host: this.connectionOptions.host,
|
||||
user: this.connectionOptions.username,
|
||||
password: this.connectionOptions.password,
|
||||
database: this.connectionOptions.database
|
||||
});
|
||||
return new Promise<void>((ok, fail) => {
|
||||
this.mysqlConnection.connect((err: any) => err ? fail(err) : ok());
|
||||
@ -180,9 +180,24 @@ export class MysqlDriver extends BaseDriver implements Driver {
|
||||
if (!this.mysqlConnection)
|
||||
throw new ConnectionIsNotSetError("mysql");
|
||||
|
||||
const qb = this.createQueryBuilder().update(tableName, valuesMap).from(tableName, "t");
|
||||
Object.keys(conditions).forEach(key => qb.andWhere(key + "=:" + key, { [key]: (<any> conditions)[key] }));
|
||||
return qb.execute().then(() => {});
|
||||
const updateValues = this.escapeObjectMap(valuesMap).join(",");
|
||||
const conditionString = this.escapeObjectMap(conditions).join(" AND ");
|
||||
const query = `UPDATE ${tableName} SET ${updateValues} ${conditionString ? (" WHERE " + conditionString) : ""}`;
|
||||
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] }));
|
||||
// return qb.execute().then(() => {});
|
||||
}
|
||||
|
||||
private escapeObjectMap(objectMap: { [key: string]: any }): string[] {
|
||||
return Object.keys(objectMap).map(key => {
|
||||
const value = (<any> objectMap)[key];
|
||||
if (value === null || value === undefined) {
|
||||
return key + "=NULL";
|
||||
} else {
|
||||
return key + "=" + this.escape(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -193,9 +208,10 @@ export class MysqlDriver extends BaseDriver implements Driver {
|
||||
throw new ConnectionIsNotSetError("mysql");
|
||||
|
||||
const columns = Object.keys(keyValues).join(",");
|
||||
const values = Object.keys(keyValues).map(key => (<any> keyValues)[key]).join(",");
|
||||
// const values = this.escapeObjectMap(keyValues).join(",");
|
||||
const values = Object.keys(keyValues).map(key => this.escape((<any> keyValues)[key])).join(","); // todo: escape here
|
||||
const query = `INSERT INTO ${tableName}(${columns}) VALUES (${values})`;
|
||||
return this.query(query);
|
||||
return this.query<any>(query).then(result => result.insertId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -204,10 +220,13 @@ export class MysqlDriver extends BaseDriver implements Driver {
|
||||
delete(tableName: string, conditions: Object): Promise<void> {
|
||||
if (!this.mysqlConnection)
|
||||
throw new ConnectionIsNotSetError("mysql");
|
||||
|
||||
const qb = this.createQueryBuilder().delete(tableName);
|
||||
Object.keys(conditions).forEach(key => qb.andWhere(key + "=:" + key, { [key]: (<any> conditions)[key] }));
|
||||
return qb.execute().then(() => {});
|
||||
|
||||
const conditionString = this.escapeObjectMap(conditions).join(" AND ");
|
||||
const query = `DELETE FROM ${tableName} WHERE ${conditionString}`;
|
||||
return this.query(query).then(() => {});
|
||||
// const qb = this.createQueryBuilder().delete(tableName);
|
||||
// Object.keys(conditions).forEach(key => qb.andWhere(key + "=:" + key, { [key]: (<any> conditions)[key] }));
|
||||
// return qb.execute().then(() => {});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -5,6 +5,8 @@ import {ColumnType} from "../types/ColumnTypes";
|
||||
|
||||
/**
|
||||
* Constructor arguments for ColumnMetadata class.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export interface ColumnMetadataArgs {
|
||||
|
||||
@ -51,6 +53,8 @@ export interface ColumnMetadataArgs {
|
||||
|
||||
/**
|
||||
* This metadata contains all information about class's column.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export class ColumnMetadata extends PropertyMetadata {
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
/**
|
||||
* This metadata interface contains all information about table's compound index.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export class CompoundIndexMetadata {
|
||||
|
||||
|
||||
@ -3,6 +3,8 @@ import {EventListenerType} from "../types/EventListenerTypes";
|
||||
|
||||
/**
|
||||
* This metadata interface contains all information about some index on a field.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export class EntityListenerMetadata extends PropertyMetadata {
|
||||
|
||||
|
||||
@ -8,6 +8,8 @@ import {ForeignKeyMetadata} from "./ForeignKeyMetadata";
|
||||
|
||||
/**
|
||||
* Contains all entity metadata.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export class EntityMetadata {
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
/**
|
||||
* Contains metadata information about ORM event subscribers.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export class EventSubscriberMetadata {
|
||||
|
||||
|
||||
@ -5,6 +5,8 @@ export type OnDeleteType = "RESTRICT"|"CASCADE"|"SET NULL";
|
||||
|
||||
/**
|
||||
* This metadata interface contains all information foreign keys.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export class ForeignKeyMetadata {
|
||||
|
||||
|
||||
@ -2,6 +2,8 @@ import {PropertyMetadata} from "./PropertyMetadata";
|
||||
|
||||
/**
|
||||
* This metadata interface contains all information about some index on a field.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export class IndexMetadata extends PropertyMetadata {
|
||||
|
||||
|
||||
@ -2,6 +2,8 @@ import {TableMetadata} from "./TableMetadata";
|
||||
|
||||
/**
|
||||
* This metadata interface contains all information about junction table.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export class JunctionTableMetadata extends TableMetadata {
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
/**
|
||||
* This represents metadata of some object's property.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export abstract class PropertyMetadata {
|
||||
|
||||
|
||||
@ -17,6 +17,8 @@ export type PropertyTypeInFunction<T> = string|((t: T) => string|any);
|
||||
|
||||
/**
|
||||
* Relation metadata constructor arguments.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export interface RelationMetadataArgs {
|
||||
|
||||
@ -59,6 +61,8 @@ export interface RelationMetadataArgs {
|
||||
|
||||
/**
|
||||
* This metadata interface contains all information about some document's relation.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export class RelationMetadata extends PropertyMetadata {
|
||||
|
||||
|
||||
@ -2,6 +2,8 @@ import {NamingStrategy} from "../../naming-strategy/NamingStrategy";
|
||||
|
||||
/**
|
||||
* This metadata interface contains all information about specific table.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export class TableMetadata {
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import {OnDeleteType} from "../metadata/ForeignKeyMetadata";
|
||||
|
||||
/**
|
||||
* Describes all relation's options.
|
||||
*/
|
||||
|
||||
@ -45,7 +45,8 @@ export class EntityPersistOperationBuilder {
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(private connection: Connection) {
|
||||
constructor(private connection: Connection,
|
||||
private entityMetadatas: EntityMetadata[]) {
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@ -109,7 +110,8 @@ export class EntityPersistOperationBuilder {
|
||||
dbEntities: EntityWithId[],
|
||||
fromRelation?: RelationMetadata,
|
||||
operations: InsertOperation[] = []): InsertOperation[] {
|
||||
const metadata = this.connection.getEntityMetadata(newEntity.constructor);
|
||||
// const metadata = this.connection.getEntityMetadata(newEntity.constructor);
|
||||
const metadata = this.entityMetadatas.find(metadata => metadata.target === newEntity.constructor);
|
||||
const isObjectNew = !this.findEntityWithId(dbEntities, metadata.target, newEntity[metadata.primaryColumn.name]);
|
||||
|
||||
// if object is new and should be inserted, we check if cascades are allowed before add it to operations list
|
||||
@ -234,7 +236,8 @@ export class EntityPersistOperationBuilder {
|
||||
}
|
||||
|
||||
private findRelationsWithEntityInside(insertOperation: InsertOperation, entityToSearchIn: any) {
|
||||
const metadata = this.connection.getEntityMetadata(entityToSearchIn.constructor);
|
||||
// const metadata = this.connection.getEntityMetadata(entityToSearchIn.constructor);
|
||||
const metadata = this.entityMetadatas.find(metadata => metadata.target === entityToSearchIn.constructor);
|
||||
|
||||
return metadata.relations.reduce((operations, relation) => {
|
||||
const value = entityToSearchIn[relation.propertyName];
|
||||
|
||||
@ -7,6 +7,7 @@ import {InsertOperation} from "./operation/InsertOperation";
|
||||
import {JunctionRemoveOperation} from "./operation/JunctionRemoveOperation";
|
||||
import {UpdateByRelationOperation} from "./operation/UpdateByRelationOperation";
|
||||
import {Broadcaster} from "../subscriber/Broadcaster";
|
||||
import {EntityMetadata} from "../metadata-builder/metadata/EntityMetadata";
|
||||
|
||||
/**
|
||||
* Executes PersistOperation in the given connection.
|
||||
@ -18,7 +19,8 @@ export class PersistOperationExecutor {
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(private connection: Connection) {
|
||||
constructor(private connection: Connection,
|
||||
private entityMetadatas: EntityMetadata[]) {
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@ -29,7 +31,7 @@ export class PersistOperationExecutor {
|
||||
* Executes given persist operation.
|
||||
*/
|
||||
executePersistOperation(persistOperation: PersistOperation) {
|
||||
const broadcaster = new Broadcaster(this.connection);
|
||||
const broadcaster = new Broadcaster(this.connection, this.entityMetadatas);
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() => this.broadcastBeforeEvents(broadcaster, persistOperation))
|
||||
@ -104,8 +106,8 @@ export class PersistOperationExecutor {
|
||||
*/
|
||||
private executeInsertOperations(persistOperation: PersistOperation) {
|
||||
return Promise.all(persistOperation.inserts.map(operation => {
|
||||
return this.insert(operation.entity).then((result: any) => {
|
||||
operation.entityId = result.insertId;
|
||||
return this.insert(operation.entity).then((insertId: any) => {
|
||||
operation.entityId = insertId;
|
||||
});
|
||||
}));
|
||||
}
|
||||
@ -174,7 +176,8 @@ export class PersistOperationExecutor {
|
||||
*/
|
||||
private updateIdsOfInsertedEntities(persistOperation: PersistOperation) {
|
||||
persistOperation.inserts.forEach(insertOperation => {
|
||||
const metadata = this.connection.getEntityMetadata(insertOperation.entity.constructor);
|
||||
// const metadata = this.connection.getEntityMetadata(insertOperation.entity.constructor);
|
||||
const metadata = this.entityMetadatas.find(metadata => metadata.target === insertOperation.entity.constructor);
|
||||
insertOperation.entity[metadata.primaryColumn.name] = insertOperation.entityId;
|
||||
});
|
||||
}
|
||||
@ -184,7 +187,8 @@ export class PersistOperationExecutor {
|
||||
*/
|
||||
private updateIdsOfRemovedEntities(persistOperation: PersistOperation) {
|
||||
persistOperation.removes.forEach(removeOperation => {
|
||||
const metadata = this.connection.getEntityMetadata(removeOperation.entity.constructor);
|
||||
// const metadata = this.connection.getEntityMetadata(removeOperation.entity.constructor);
|
||||
const metadata = this.entityMetadatas.find(metadata => metadata.target === removeOperation.entity.constructor);
|
||||
const removedEntity = persistOperation.allPersistedEntities.find(allNewEntity => {
|
||||
return allNewEntity.entity.constructor === removeOperation.entity.constructor && allNewEntity.id === removeOperation.entity[metadata.primaryColumn.name];
|
||||
});
|
||||
@ -197,7 +201,8 @@ export class PersistOperationExecutor {
|
||||
let tableName: string, relationName: string, relationId: any, idColumn: string, id: any;
|
||||
const idInInserts = insertOperations.find(o => o.entity === operation.targetEntity).entityId;
|
||||
if (operation.updatedRelation.isOneToMany) {
|
||||
const metadata = this.connection.getEntityMetadata(operation.insertOperation.entity.constructor);
|
||||
// const metadata = this.connection.getEntityMetadata(operation.insertOperation.entity.constructor);
|
||||
const metadata = this.entityMetadatas.find(metadata => metadata.target === operation.insertOperation.entity.constructor);
|
||||
tableName = metadata.table.name;
|
||||
relationName = operation.updatedRelation.inverseRelation.name;
|
||||
relationId = operation.targetEntity[metadata.primaryColumn.propertyName] || idInInserts;
|
||||
@ -205,7 +210,8 @@ export class PersistOperationExecutor {
|
||||
id = operation.insertOperation.entityId;
|
||||
|
||||
} else {
|
||||
const metadata = this.connection.getEntityMetadata(operation.targetEntity.constructor);
|
||||
// const metadata = this.connection.getEntityMetadata(operation.targetEntity.constructor);
|
||||
const metadata = this.entityMetadatas.find(metadata => metadata.target === operation.targetEntity.constructor);
|
||||
tableName = metadata.table.name;
|
||||
relationName = operation.updatedRelation.name;
|
||||
relationId = operation.insertOperation.entityId;
|
||||
@ -217,7 +223,8 @@ export class PersistOperationExecutor {
|
||||
|
||||
private update(updateOperation: UpdateOperation) {
|
||||
const entity = updateOperation.entity;
|
||||
const metadata = this.connection.getEntityMetadata(entity.constructor);
|
||||
// const metadata = this.connection.getEntityMetadata(entity.constructor);
|
||||
const metadata = this.entityMetadatas.find(metadata => metadata.target === entity.constructor);
|
||||
const values: any = updateOperation.columns.reduce((object, column) => {
|
||||
const value = this.connection.driver.preparePersistentValue(entity[column.propertyName], column);
|
||||
(<any> object)[column.name] = value;
|
||||
@ -243,12 +250,14 @@ export class PersistOperationExecutor {
|
||||
}
|
||||
|
||||
private delete(entity: any) {
|
||||
const metadata = this.connection.getEntityMetadata(entity.constructor);
|
||||
// const metadata = this.connection.getEntityMetadata(entity.constructor);
|
||||
const metadata = this.entityMetadatas.find(metadata => metadata.target === entity.constructor);
|
||||
return this.connection.driver.delete(metadata.table.name, { [metadata.primaryColumn.name]: entity[metadata.primaryColumn.propertyName] });
|
||||
}
|
||||
|
||||
private insert(entity: any) {
|
||||
const metadata = this.connection.getEntityMetadata(entity.constructor);
|
||||
// const metadata = this.connection.getEntityMetadata(entity.constructor);
|
||||
const metadata = this.entityMetadatas.find(metadata => metadata.target === entity.constructor);
|
||||
const columns = metadata.columns
|
||||
.filter(column => !column.isVirtual)
|
||||
.filter(column => entity.hasOwnProperty(column.propertyName))
|
||||
@ -256,14 +265,7 @@ export class PersistOperationExecutor {
|
||||
const values = metadata.columns
|
||||
.filter(column => !column.isVirtual)
|
||||
.filter(column => entity.hasOwnProperty(column.propertyName))
|
||||
.map(column => this.connection.driver.preparePersistentValue(entity[column.propertyName], column))
|
||||
.map(value => {
|
||||
if (value === null || value === undefined) {
|
||||
return "NULL";
|
||||
} else {
|
||||
return this.connection.driver.escape(value);
|
||||
}
|
||||
});
|
||||
.map(column => this.connection.driver.preparePersistentValue(entity[column.propertyName], column));
|
||||
const relationColumns = metadata.relations
|
||||
.filter(relation => relation.isOwning && !!relation.relatedEntityMetadata)
|
||||
.filter(relation => entity.hasOwnProperty(relation.propertyName))
|
||||
@ -274,19 +276,19 @@ export class PersistOperationExecutor {
|
||||
.filter(relation => relation.isOwning && !!relation.relatedEntityMetadata)
|
||||
.filter(relation => entity.hasOwnProperty(relation.propertyName))
|
||||
.filter(relation => entity[relation.propertyName].hasOwnProperty(relation.relatedEntityMetadata.primaryColumn.name))
|
||||
.map(relation => this.connection.driver.escape(entity[relation.propertyName][relation.relatedEntityMetadata.primaryColumn.name]));
|
||||
.map(relation => entity[relation.propertyName][relation.relatedEntityMetadata.primaryColumn.name]);
|
||||
|
||||
const allColumns = columns.concat(relationColumns);
|
||||
const allValues = values.concat(relationValues);
|
||||
|
||||
if (metadata.createDateColumn) {
|
||||
allColumns.push(metadata.createDateColumn.name);
|
||||
allValues.push(this.connection.driver.escape(this.connection.driver.preparePersistentValue(new Date(), metadata.createDateColumn)));
|
||||
allValues.push(this.connection.driver.preparePersistentValue(new Date(), metadata.createDateColumn));
|
||||
}
|
||||
|
||||
if (metadata.updateDateColumn) {
|
||||
allColumns.push(metadata.updateDateColumn.name);
|
||||
allValues.push(this.connection.driver.escape(this.connection.driver.preparePersistentValue(new Date(), metadata.updateDateColumn)));
|
||||
allValues.push(this.connection.driver.preparePersistentValue(new Date(), metadata.updateDateColumn));
|
||||
}
|
||||
|
||||
return this.connection.driver.insert(metadata.table.name, this.zipObject(allColumns, allValues));
|
||||
@ -294,8 +296,10 @@ export class PersistOperationExecutor {
|
||||
|
||||
private insertJunctions(junctionOperation: JunctionInsertOperation, insertOperations: InsertOperation[]) {
|
||||
const junctionMetadata = junctionOperation.metadata;
|
||||
const metadata1 = this.connection.getEntityMetadata(junctionOperation.entity1.constructor);
|
||||
const metadata2 = this.connection.getEntityMetadata(junctionOperation.entity2.constructor);
|
||||
// const metadata1 = this.connection.getEntityMetadata(junctionOperation.entity1.constructor);
|
||||
// const metadata2 = this.connection.getEntityMetadata(junctionOperation.entity2.constructor);
|
||||
const metadata1 = this.entityMetadatas.find(metadata => metadata.target === junctionOperation.entity1.constructor);
|
||||
const metadata2 = this.entityMetadatas.find(metadata => metadata.target === junctionOperation.entity2.constructor);
|
||||
const columns = junctionMetadata.columns.map(column => column.name);
|
||||
const id1 = junctionOperation.entity1[metadata1.primaryColumn.name] || insertOperations.find(o => o.entity === junctionOperation.entity1).entityId;
|
||||
const id2 = junctionOperation.entity2[metadata2.primaryColumn.name] || insertOperations.find(o => o.entity === junctionOperation.entity2).entityId;
|
||||
@ -305,8 +309,10 @@ export class PersistOperationExecutor {
|
||||
|
||||
private removeJunctions(junctionOperation: JunctionRemoveOperation) {
|
||||
const junctionMetadata = junctionOperation.metadata;
|
||||
const metadata1 = this.connection.getEntityMetadata(junctionOperation.entity1.constructor);
|
||||
const metadata2 = this.connection.getEntityMetadata(junctionOperation.entity2.constructor);
|
||||
// const metadata1 = this.connection.getEntityMetadata(junctionOperation.entity1.constructor);
|
||||
// const metadata2 = this.connection.getEntityMetadata(junctionOperation.entity2.constructor);
|
||||
const metadata1 = this.entityMetadatas.find(metadata => metadata.target === junctionOperation.entity1.constructor);
|
||||
const metadata2 = this.entityMetadatas.find(metadata => metadata.target === junctionOperation.entity2.constructor);
|
||||
const columns = junctionMetadata.columns.map(column => column.name);
|
||||
const id1 = junctionOperation.entity1[metadata1.primaryColumn.name];
|
||||
const id2 = junctionOperation.entity2[metadata2.primaryColumn.name];
|
||||
|
||||
@ -3,6 +3,7 @@ import {AliasMap} from "./alias/AliasMap";
|
||||
import {Connection} from "../connection/Connection";
|
||||
import {RawSqlResultsToEntityTransformer} from "./transformer/RawSqlResultsToEntityTransformer";
|
||||
import {Broadcaster} from "../subscriber/Broadcaster";
|
||||
import {EntityMetadata} from "../metadata-builder/metadata/EntityMetadata";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@ -43,9 +44,10 @@ export class QueryBuilder<Entity> {
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(private connection: Connection) {
|
||||
constructor(private connection: Connection,
|
||||
private entityMetadatas: EntityMetadata[]) {
|
||||
this.aliasMap = new AliasMap(connection.entityMetadatas);
|
||||
this.broadcaster = new Broadcaster(connection);
|
||||
this.broadcaster = new Broadcaster(connection, this.entityMetadatas);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@ -307,7 +309,8 @@ export class QueryBuilder<Entity> {
|
||||
getResults(): Promise<Entity[]> {
|
||||
const mainAlias = this.aliasMap.mainAlias.name;
|
||||
if (this.firstResult || this.maxResults) {
|
||||
const metadata = this.connection.getEntityMetadata(this.fromEntity.alias.target);
|
||||
// const metadata = this.connection.getEntityMetadata(this.fromEntity.alias.target);
|
||||
const metadata = this.entityMetadatas.find(metadata => metadata.target === this.fromEntity.alias.target);
|
||||
let idsQuery = `SELECT DISTINCT(distinctAlias.${mainAlias}_${metadata.primaryColumn.name}) as ids`;
|
||||
if (this.orderBys && this.orderBys.length > 0)
|
||||
idsQuery += ", " + this.orderBys.map(orderBy => orderBy.sort.replace(".", "_")).join(", ");
|
||||
@ -346,7 +349,8 @@ export class QueryBuilder<Entity> {
|
||||
|
||||
getCount(): Promise<number> {
|
||||
const mainAlias = this.aliasMap.mainAlias.name;
|
||||
const metadata = this.connection.getEntityMetadata(this.fromEntity.alias.target);
|
||||
const metadata = this.entityMetadatas.find(metadata => metadata.target === this.fromEntity.alias.target);
|
||||
// const metadata = this.connection.getEntityMetadata(this.fromEntity.alias.target);
|
||||
const countQuery = this.clone({ skipOrderBys: true })
|
||||
.select(`COUNT(DISTINCT(${mainAlias}.${metadata.primaryColumn.name})) as cnt`)
|
||||
.getSql();
|
||||
@ -363,7 +367,7 @@ export class QueryBuilder<Entity> {
|
||||
}
|
||||
|
||||
clone(options?: { skipOrderBys?: boolean }) {
|
||||
const qb = new QueryBuilder(this.connection);
|
||||
const qb = new QueryBuilder(this.connection, this.entityMetadatas);
|
||||
|
||||
switch (this.type) {
|
||||
case "select":
|
||||
@ -594,7 +598,7 @@ export class QueryBuilder<Entity> {
|
||||
protected replaceParameters(sql: string) {
|
||||
Object.keys(this.parameters).forEach(key => {
|
||||
const value = this.parameters[key] !== null && this.parameters[key] !== undefined ? this.connection.driver.escape(this.parameters[key]) : "NULL";
|
||||
sql = sql.replace(":" + key, value);
|
||||
sql = sql.replace(":" + key, value); // todo: make replace only in value statements, otherwise problems
|
||||
});
|
||||
return sql;
|
||||
}
|
||||
|
||||
@ -17,7 +17,9 @@ export class Repository<Entity> {
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(private connection: Connection, private metadata: EntityMetadata) {
|
||||
constructor(private connection: Connection,
|
||||
private entityMetadatas: EntityMetadata[],
|
||||
private metadata: EntityMetadata) {
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@ -39,8 +41,10 @@ export class Repository<Entity> {
|
||||
* Creates a new query builder that can be used to build a sql query.
|
||||
*/
|
||||
createQueryBuilder(alias: string): QueryBuilder<Entity> {
|
||||
return this.connection.driver
|
||||
.createQueryBuilder<Entity>()
|
||||
// const qb = this.connection.driver.createQueryBuilder<Entity>();
|
||||
const cls: any = this.connection.driver.queryBuilderClass;
|
||||
const qb = new cls(this.connection, this.entityMetadatas);
|
||||
return qb
|
||||
.select(alias)
|
||||
.from(this.metadata.target, alias);
|
||||
}
|
||||
@ -89,8 +93,8 @@ export class Repository<Entity> {
|
||||
*/
|
||||
persist(entity: Entity): Promise<Entity> {
|
||||
let loadedDbEntity: any;
|
||||
const persister = new PersistOperationExecutor(this.connection);
|
||||
const builder = new EntityPersistOperationBuilder(this.connection);
|
||||
const persister = new PersistOperationExecutor(this.connection, this.entityMetadatas);
|
||||
const builder = new EntityPersistOperationBuilder(this.connection, this.entityMetadatas);
|
||||
const allPersistedEntities = this.extractObjectsById(entity, this.metadata);
|
||||
const promise: Promise<Entity> = !this.hasId(entity) ? Promise.resolve<Entity|null>(null) : this.initialize(entity);
|
||||
return promise
|
||||
@ -109,10 +113,10 @@ export class Repository<Entity> {
|
||||
* Removes a given entity from the database.
|
||||
*/
|
||||
remove(entity: Entity): Promise<Entity> {
|
||||
const persister = new PersistOperationExecutor(this.connection);
|
||||
const persister = new PersistOperationExecutor(this.connection, this.entityMetadatas);
|
||||
return this.initialize(entity).then(dbEntity => {
|
||||
(<any> entity)[this.metadata.primaryColumn.name] = undefined;
|
||||
const builder = new EntityPersistOperationBuilder(this.connection);
|
||||
const builder = new EntityPersistOperationBuilder(this.connection, this.entityMetadatas);
|
||||
const dbEntities = this.extractObjectsById(dbEntity, this.metadata);
|
||||
const allPersistedEntities = this.extractObjectsById(entity, this.metadata);
|
||||
const persistOperation = builder.buildOnlyRemovement(this.metadata, dbEntity, entity, dbEntities, allPersistedEntities);
|
||||
@ -269,7 +273,8 @@ export class Repository<Entity> {
|
||||
.filter(entityWithId => entityWithId.id !== null && entityWithId.id !== undefined)
|
||||
.filter(entityWithId => !dbEntities.find(dbEntity => dbEntity.entity.constructor === entityWithId.entity.constructor && dbEntity.id === entityWithId.id))
|
||||
.map(entityWithId => {
|
||||
const metadata = this.connection.getEntityMetadata(entityWithId.entity.constructor);
|
||||
// const metadata = this.connection.getEntityMetadata(entityWithId.entity.constructor);
|
||||
const metadata = this.entityMetadatas.find(metadata => metadata.target === entityWithId.entity.constructor);
|
||||
const repository = this.connection.getRepository(entityWithId.entity.constructor);
|
||||
return repository.findById(entityWithId.id).then(loadedEntity => {
|
||||
if (!loadedEntity) return undefined;
|
||||
|
||||
@ -2,6 +2,7 @@ import {EventSubscriberInterface} from "./EventSubscriberInterface";
|
||||
import {Connection} from "../connection/Connection";
|
||||
import {ColumnMetadata} from "../metadata-builder/metadata/ColumnMetadata";
|
||||
import {EventListenerTypes} from "../metadata-builder/types/EventListenerTypes";
|
||||
import {EntityMetadata} from "../metadata-builder/metadata/EntityMetadata";
|
||||
|
||||
/**
|
||||
* Broadcaster provides a helper methods to broadcast events to the subscribers.
|
||||
@ -14,7 +15,8 @@ export class Broadcaster {
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(private connection: Connection) {
|
||||
constructor(private connection: Connection,
|
||||
private entityMetadatas: EntityMetadata[]) {
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@ -118,7 +120,8 @@ export class Broadcaster {
|
||||
}
|
||||
|
||||
broadcastLoadEvents(entity: any): Promise<void> {
|
||||
const metadata = this.connection.getEntityMetadata(entity.constructor);
|
||||
// const metadata = this.connection.getEntityMetadata(entity.constructor);
|
||||
const metadata = this.entityMetadatas.find(metadata => metadata.target === entity.constructor);
|
||||
let promises: Promise<any>[] = [];
|
||||
|
||||
metadata
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user