refactored connection class

This commit is contained in:
Umed Khudoiberdiev 2016-05-23 10:45:32 +05:00
parent 8d68c8c40b
commit 81e15a0a3c
5 changed files with 85 additions and 51 deletions

View File

@ -4,7 +4,6 @@ import {Repository} from "../repository/Repository";
import {EventSubscriberInterface} from "../subscriber/EventSubscriberInterface";
import {RepositoryNotFoundError} from "./error/RepositoryNotFoundError";
import {EntityMetadata} from "../metadata/EntityMetadata";
import {SchemaCreator} from "../schema-creator/SchemaCreator";
import {ConstructorFunction} from "../common/ConstructorFunction";
import {EntityListenerMetadata} from "../metadata/EntityListenerMetadata";
import {EntityManager} from "../entity-manager/EntityManager";
@ -27,6 +26,8 @@ import {NamingStrategyNotFoundError} from "./error/NamingStrategyNotFoundError";
import {EntityManagerFactory} from "../entity-manager/EntityManagerFactory";
import {RepositoryFactory} from "../repository/RepositoryFactory";
import {SchemaCreatorFactory} from "../schema-creator/SchemaCreatorFactory";
import {ReactiveRepositoryNotFoundError} from "./error/ReactiveRepositoryNotFoundError";
import {RepositoryNotTreeError} from "./error/RepositoryNotTreeError";
/**
* A single connection instance to the database. Each connection has its own repositories, subscribers and metadatas.
@ -47,10 +48,6 @@ export class Connection {
*/
private reactiveRepositories: ReactiveRepository<any>[] = [];
private repositoryFactory = getFromContainer(RepositoryFactory);
private schemaCreatorFactory = getFromContainer(SchemaCreatorFactory);
// -------------------------------------------------------------------------
// Readonly properties
// -------------------------------------------------------------------------
@ -192,7 +189,8 @@ export class Connection {
await this.driver.clearDatabase();
const schemaBuilder = this.driver.createSchemaBuilder();
const schemaCreator = this.schemaCreatorFactory.create(schemaBuilder, this.entityMetadatas);
const schemaCreatorFactory = getFromContainer(SchemaCreatorFactory);
const schemaCreator = schemaCreatorFactory.create(schemaBuilder, this.entityMetadatas);
return schemaCreator.create();
}
@ -302,7 +300,7 @@ export class Connection {
if (!repository)
throw new RepositoryNotFoundError(this.name, entityClassOrName);
if (!metadata.table.isClosure)
throw new Error(`Cannot get a tree repository. ${metadata.name} is not a tree table. Try to use @ClosureTable decorator instead of @Table.`);
throw new RepositoryNotTreeError(entityClassOrName);
return <TreeRepository<Entity>> repository;
}
@ -310,14 +308,14 @@ export class Connection {
/**
* Gets reactive repository for the given entity class.
*/
getReactiveRepository<Entity>(entityClass: ConstructorFunction<Entity>|Function): ReactiveRepository<Entity> {
getReactiveRepository<Entity>(entityClass: ConstructorFunction<Entity>|Function|string): ReactiveRepository<Entity> {
if (!this.isConnected)
throw new NoConnectionForRepositoryError(this.name);
const metadata = this.entityMetadatas.findByTarget(entityClass);
const metadata = this.entityMetadatas.findByNameOrTarget(entityClass);
const repository = this.reactiveRepositories.find(repository => ReactiveRepository.ownsMetadata(repository, metadata));
if (!repository)
throw new RepositoryNotFoundError(this.name, entityClass); // todo throw ReactiveRepositoryNotFoundError
throw new ReactiveRepositoryNotFoundError(this.name, entityClass);
return repository;
}
@ -325,16 +323,16 @@ export class Connection {
/**
* Gets reactive tree repository for the given entity class.
*/
getReactiveTreeRepository<Entity>(entityClass: ConstructorFunction<Entity>|Function): ReactiveTreeRepository<Entity> {
getReactiveTreeRepository<Entity>(entityClass: ConstructorFunction<Entity>|Function|string): ReactiveTreeRepository<Entity> {
if (!this.isConnected)
throw new NoConnectionForRepositoryError(this.name);
const metadata = this.entityMetadatas.findByTarget(entityClass);
const metadata = this.entityMetadatas.findByNameOrTarget(entityClass);
const repository = this.reactiveRepositories.find(repository => ReactiveRepository.ownsMetadata(repository, metadata));
if (!repository)
throw new RepositoryNotFoundError(this.name, entityClass);
if (!metadata.table.isClosure)
throw new Error(`Cannot get a tree repository. ${metadata.name} is not a tree table. Try to use @ClosureTable decorator instead of @Table.`);
throw new RepositoryNotTreeError(entityClass);
return <ReactiveTreeRepository<Entity>> repository;
}
@ -348,25 +346,32 @@ export class Connection {
*/
private buildMetadatas() {
// first register naming strategies
const metadatas = defaultMetadataStorage().namingStrategyMetadatas.filterByClasses(this.namingStrategyClasses);
metadatas.forEach(cls => this.namingStrategyMetadatas.push(cls));
// take imported naming strategy metadatas
defaultMetadataStorage()
.namingStrategyMetadatas
.filterByClasses(this.namingStrategyClasses)
.forEach(namingStrategy => this.namingStrategyMetadatas.push(namingStrategy));
// second register subscriber metadatas
const subscribers = defaultMetadataStorage()
// take imported event subscribers
defaultMetadataStorage()
.eventSubscriberMetadatas
.filterByClasses(this.subscriberClasses)
.map(metadata => getFromContainer(metadata.target));
this.eventSubscribers.push(...subscribers);
.map(metadata => getFromContainer(metadata.target))
.forEach(subscriber => this.eventSubscribers.push(subscriber));
// third register entity and entity listener metadatas
const entityMetadataBuilder = new EntityMetadataBuilder(this.createNamingStrategy());
const entityMetadatas = entityMetadataBuilder.build(this.entityClasses);
const entityListenerMetadatas = defaultMetadataStorage().entityListenerMetadatas.filterByClasses(this.entityClasses);
// take imported entity listeners
defaultMetadataStorage()
.entityListenerMetadatas
.filterByClasses(this.entityClasses)
.forEach(entityListener => this.entityListeners.push(entityListener));
entityMetadatas.forEach(cls => this.entityMetadatas.push(cls));
entityListenerMetadatas.forEach(cls => this.entityListeners.push(cls));
entityMetadatas.forEach(metadata => this.createRepository(metadata));
// build entity metadatas for the current connection
getFromContainer(EntityMetadataBuilder)
.build(this.createNamingStrategy(), this.entityClasses)
.forEach(metadata => {
this.entityMetadatas.push(metadata);
this.createRepository(metadata);
});
}
/**
@ -387,14 +392,15 @@ export class Connection {
* Creates repository and reactive repository for the given entity metadata.
*/
private createRepository(metadata: EntityMetadata) {
const repositoryFactory = getFromContainer(RepositoryFactory);
if (metadata.table.isClosure) {
const repository = this.repositoryFactory.createRepository(this, this.entityMetadatas, metadata);
const reactiveRepository = this.repositoryFactory.createReactiveRepository(repository);
const repository = repositoryFactory.createRepository(this, this.entityMetadatas, metadata);
const reactiveRepository = repositoryFactory.createReactiveRepository(repository);
this.repositories.push(repository);
this.reactiveRepositories.push(reactiveRepository);
} else {
const repository = this.repositoryFactory.createTreeRepository(this, this.entityMetadatas, metadata);
const reactiveRepository = this.repositoryFactory.createReactiveTreeRepository(repository);
const repository = repositoryFactory.createTreeRepository(this, this.entityMetadatas, metadata);
const reactiveRepository = repositoryFactory.createReactiveTreeRepository(repository);
this.repositories.push(repository);
this.reactiveRepositories.push(reactiveRepository);
}

View File

@ -0,0 +1,14 @@
/**
* @internal
*/
export class ReactiveRepositoryNotFoundError extends Error {
name = "ReactiveRepositoryNotFoundError";
constructor(connectionName: string, entityClass: Function|string) {
super();
const targetName = typeof entityClass === "function" && (<any> entityClass).name ? (<any> entityClass).name : entityClass;
this.message = `No reactive repository for "${targetName}" was found. Looks like this entity is not registered in ` +
`current "${connectionName}" connection?`;
}
}

View File

@ -0,0 +1,13 @@
/**
* @internal
*/
export class RepositoryNotTreeError extends Error {
name = "RepositoryNotTreeError";
constructor(entityClass: Function|string) {
super();
const targetName = typeof entityClass === "function" && (<any> entityClass).name ? (<any> entityClass).name : entityClass;
this.message = `Repository of the "${targetName}" class is not a TreeRepository. Try to use @ClosureTable decorator instead of @Table.`;
}
}

View File

@ -28,13 +28,6 @@ export class EntityMetadataBuilder {
private entityValidator = new EntityMetadataValidator();
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(private namingStrategy: NamingStrategyInterface) {
}
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
@ -53,7 +46,8 @@ export class EntityMetadataBuilder {
/**
* Builds a complete metadata aggregations for the given entity classes.
*/
build(entityClasses: Function[]): EntityMetadata[] {
build(namingStrategy: NamingStrategyInterface,
entityClasses: Function[]): EntityMetadata[] {
const allMetadataStorage = defaultMetadataStorage();
@ -62,20 +56,20 @@ export class EntityMetadataBuilder {
const tableMetadatas = allTableMetadatas.filterByClasses(entityClasses).filter(table => !table.isAbstract);
// set naming strategy
// allMetadataStorage.tableMetadatas.forEach(tableMetadata => tableMetadata.namingStrategy = this.namingStrategy);
// allTableMetadatas.forEach(column => column.namingStrategy = this.namingStrategy);
// entityMetadata.relations.forEach(relation => relation.namingStrategy = this.namingStrategy);
// allMetadataStorage.tableMetadatas.forEach(tableMetadata => tableMetadata.namingStrategy = namingStrategy);
// allTableMetadatas.forEach(column => column.namingStrategy = namingStrategy);
// entityMetadata.relations.forEach(relation => relation.namingStrategy = namingStrategy);
const entityMetadatas = tableMetadatas.map(tableMetadata => {
const mergedMetadata = allMetadataStorage.mergeWithAbstract(allTableMetadatas, tableMetadata);
// set naming strategy
// tableMetadata.namingStrategy = this.namingStrategy;
mergedMetadata.columnMetadatas.forEach(column => column.namingStrategy = this.namingStrategy);
mergedMetadata.relationMetadatas.forEach(relation => relation.namingStrategy = this.namingStrategy);
mergedMetadata.indexMetadatas.forEach(relation => relation.namingStrategy = this.namingStrategy);
mergedMetadata.compositeIndexMetadatas.forEach(relation => relation.namingStrategy = this.namingStrategy);
// tableMetadata.namingStrategy = namingStrategy;
mergedMetadata.columnMetadatas.forEach(column => column.namingStrategy = namingStrategy);
mergedMetadata.relationMetadatas.forEach(relation => relation.namingStrategy = namingStrategy);
mergedMetadata.indexMetadatas.forEach(relation => relation.namingStrategy = namingStrategy);
mergedMetadata.compositeIndexMetadatas.forEach(relation => relation.namingStrategy = namingStrategy);
// merge indices and composite indices because simple indices actually are compose indices with only one column
this.mergeIndicesAndCompositeIndices(mergedMetadata.indexMetadatas, mergedMetadata.compositeIndexMetadatas);
@ -86,7 +80,7 @@ export class EntityMetadataBuilder {
// create a new entity metadata
const entityMetadata = new EntityMetadata(
this.namingStrategy,
namingStrategy,
tableMetadata,
mergedMetadata.columnMetadatas,
mergedMetadata.relationMetadatas,
@ -180,7 +174,7 @@ export class EntityMetadataBuilder {
entityMetadatas
.filter(metadata => metadata.table.isClosure)
.forEach(metadata => {
const closureTableName = this.namingStrategy.closureJunctionTableName(metadata.table.name);
const closureTableName = namingStrategy.closureJunctionTableName(metadata.table.name);
const closureJunctionTableMetadata = new TableMetadata(undefined, closureTableName, "closureJunction");
const columns = [
@ -212,7 +206,7 @@ export class EntityMetadataBuilder {
}));
}
const closureJunctionEntityMetadata = new EntityMetadata(this.namingStrategy, closureJunctionTableMetadata, columns, [], []);
const closureJunctionEntityMetadata = new EntityMetadata(namingStrategy, closureJunctionTableMetadata, columns, [], []);
closureJunctionEntityMetadata.foreignKeys.push(
new ForeignKeyMetadata(closureJunctionTableMetadata, [columns[0]], metadata.table, [metadata.primaryColumn]),
new ForeignKeyMetadata(closureJunctionTableMetadata, [columns[1]], metadata.table, [metadata.primaryColumn])
@ -250,7 +244,7 @@ export class EntityMetadataBuilder {
options: column2options
})
];
const junctionEntityMetadata = new EntityMetadata(this.namingStrategy, tableMetadata, columns, [], []);
const junctionEntityMetadata = new EntityMetadata(namingStrategy, tableMetadata, columns, [], []);
junctionEntityMetadata.foreignKeys.push(
new ForeignKeyMetadata(tableMetadata, [columns[0]], metadata.table, [column1]),
new ForeignKeyMetadata(tableMetadata, [columns[1]], relation.inverseEntityMetadata.table, [column2])

View File

@ -0,0 +1,7 @@
export class EntityMetadataFactory {
createEntityMetadataBuilder() {
}
}