added factories and used container in the connection class

This commit is contained in:
Umed Khudoiberdiev 2016-05-22 17:24:24 +05:00
parent 1e79a63795
commit 8d68c8c40b
16 changed files with 139 additions and 82 deletions

View File

@ -23,7 +23,10 @@ import {ReactiveEntityManager} from "../entity-manager/ReactiveEntityManager";
import {TreeRepository} from "../repository/TreeRepository";
import {ReactiveTreeRepository} from "../repository/ReactiveTreeRepository";
import {NamingStrategyInterface} from "../naming-strategy/NamingStrategyInterface";
import {RepositoryBuilder} from "../repository/RepositoryBuilder";
import {NamingStrategyNotFoundError} from "./error/NamingStrategyNotFoundError";
import {EntityManagerFactory} from "../entity-manager/EntityManagerFactory";
import {RepositoryFactory} from "../repository/RepositoryFactory";
import {SchemaCreatorFactory} from "../schema-creator/SchemaCreatorFactory";
/**
* A single connection instance to the database. Each connection has its own repositories, subscribers and metadatas.
@ -34,9 +37,20 @@ export class Connection {
// Properties
// -------------------------------------------------------------------------
/**
* All connection's repositories.
*/
private repositories: Repository<any>[] = [];
/**
* All connection's reactive repositories.
*/
private reactiveRepositories: ReactiveRepository<any>[] = [];
private repositoryFactory = getFromContainer(RepositoryFactory);
private schemaCreatorFactory = getFromContainer(SchemaCreatorFactory);
// -------------------------------------------------------------------------
// Readonly properties
// -------------------------------------------------------------------------
@ -119,8 +133,8 @@ export class Connection {
this.driver = driver;
this.driver.connectionOptions = options;
this.options = options;
this.entityManager = new EntityManager(this);
this.reactiveEntityManager = new ReactiveEntityManager(this);
this.entityManager = getFromContainer(EntityManagerFactory).createEntityManager(this);
this.reactiveEntityManager = getFromContainer(EntityManagerFactory).createReactiveEntityManager(this);
}
// -------------------------------------------------------------------------
@ -173,9 +187,12 @@ export class Connection {
/**
* Creates database schema for all entities registered in this connection.
*/
syncSchema() {
async syncSchema(dropBeforeSync: boolean = false): Promise<void> {
if (dropBeforeSync)
await this.driver.clearDatabase();
const schemaBuilder = this.driver.createSchemaBuilder();
const schemaCreator = new SchemaCreator(schemaBuilder, this.entityMetadatas);
const schemaCreator = this.schemaCreatorFactory.create(schemaBuilder, this.entityMetadatas);
return schemaCreator.create();
}
@ -254,13 +271,7 @@ export class Connection {
if (!this.isConnected)
throw new NoConnectionForRepositoryError(this.name);
let metadata: EntityMetadata;
if (typeof entityClassOrName === "string") {
metadata = this.entityMetadatas.findByName(entityClassOrName);
} else {
metadata = this.entityMetadatas.findByTarget(entityClassOrName);
}
const metadata = this.entityMetadatas.findByNameOrTarget(entityClassOrName);
const repository = this.repositories.find(repository => Repository.ownsMetadata(repository, metadata));
if (!repository)
throw new RepositoryNotFoundError(this.name, entityClassOrName);
@ -286,13 +297,7 @@ export class Connection {
if (!this.isConnected)
throw new NoConnectionForRepositoryError(this.name);
let metadata: EntityMetadata;
if (typeof entityClassOrName === "string") {
metadata = this.entityMetadatas.findByName(entityClassOrName);
} else {
metadata = this.entityMetadatas.findByTarget(entityClassOrName);
}
const metadata = this.entityMetadatas.findByNameOrTarget(entityClassOrName);
const repository = this.repositories.find(repository => Repository.ownsMetadata(repository, metadata));
if (!repository)
throw new RepositoryNotFoundError(this.name, entityClassOrName);
@ -365,15 +370,15 @@ export class Connection {
}
/**
* Gets the naming strategy to be used for this connection.
* Creates a naming strategy to be used for this connection.
*/
private createNamingStrategy(): NamingStrategyInterface {
if (!this.options.namingStrategy)
return new DefaultNamingStrategy();
return getFromContainer(DefaultNamingStrategy);
const namingMetadata = this.namingStrategyMetadatas.find(strategy => strategy.name === this.options.namingStrategy);
if (!namingMetadata)
throw new Error(`Naming strategy called "${this.options.namingStrategy}" was not found.`);
throw new NamingStrategyNotFoundError(this.options.namingStrategy, this.name);
return getFromContainer<NamingStrategyInterface>(namingMetadata.target);
}
@ -383,13 +388,15 @@ export class Connection {
*/
private createRepository(metadata: EntityMetadata) {
if (metadata.table.isClosure) {
const repository = new TreeRepository<any>(this, this.entityMetadatas, metadata);
const repository = this.repositoryFactory.createRepository(this, this.entityMetadatas, metadata);
const reactiveRepository = this.repositoryFactory.createReactiveRepository(repository);
this.repositories.push(repository);
this.reactiveRepositories.push(new ReactiveTreeRepository(repository));
this.reactiveRepositories.push(reactiveRepository);
} else {
const repository = new Repository<any>(this, this.entityMetadatas, metadata);
const repository = this.repositoryFactory.createTreeRepository(this, this.entityMetadatas, metadata);
const reactiveRepository = this.repositoryFactory.createReactiveTreeRepository(repository);
this.repositories.push(repository);
this.reactiveRepositories.push(new ReactiveRepository(repository));
this.reactiveRepositories.push(reactiveRepository);
}
}

View File

@ -0,0 +1,13 @@
/**
* @internal
*/
export class NamingStrategyNotFoundError extends Error {
name = "NamingStrategyNotFoundError";
constructor(strategyName: string, connectionName: string) {
super();
this.message = `Naming strategy named "${strategyName}" was not found. Looks like this naming strategy does not ` +
`exist or it was not registered in current "${connectionName}" connection?`;
}
}

View File

@ -331,5 +331,4 @@ export class EntityManager {
return this.getTreeRepository(entityClass).countAncestors(entity);
}
}

View File

@ -0,0 +1,23 @@
import {Connection} from "../connection/Connection";
import {EntityManager} from "./EntityManager";
import {ReactiveEntityManager} from "./ReactiveEntityManager";
/**
* Entity manager supposed to work with any entity, automatically find its repository and call its method, whatever
* entity type are you passing.
*/
export class EntityManagerFactory {
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
createEntityManager(connection: Connection) {
return new EntityManager(connection);
}
createReactiveEntityManager(connection: Connection) {
return new ReactiveEntityManager(connection);
}
}

View File

@ -21,6 +21,14 @@ export class EntityMetadataCollection extends Array<EntityMetadata> {
return metadata;
}
findByNameOrTarget(nameOrTarget: Function|string) {
if (typeof nameOrTarget === "string") {
return this.findByName(nameOrTarget);
} else {
return this.findByTarget(nameOrTarget);
}
}
findByName(name: string) {
const metadata = this.find(metadata => metadata.name === name);

View File

@ -31,7 +31,7 @@ export class Repository<Entity> {
// Constructor
// -------------------------------------------------------------------------
constructor(protected connection: Connection,
constructor(protected connection: Connection,
protected entityMetadatas: EntityMetadataCollection,
protected metadata: EntityMetadata) {
this.driver = connection.driver;

View File

@ -1,33 +0,0 @@
import {Connection} from "../connection/Connection";
import {EntityMetadata} from "../metadata/EntityMetadata";
import {QueryBuilder} from "../query-builder/QueryBuilder";
import {PlainObjectToNewEntityTransformer} from "../query-builder/transformer/PlainObjectToNewEntityTransformer";
import {PlainObjectToDatabaseEntityTransformer} from "../query-builder/transformer/PlainObjectToDatabaseEntityTransformer";
import {EntityPersistOperationBuilder} from "../persistment/EntityPersistOperationsBuilder";
import {PersistOperationExecutor} from "../persistment/PersistOperationExecutor";
import {EntityWithId} from "../persistment/operation/PersistOperation";
import {FindOptions, FindOptionsUtils} from "./FindOptions";
import {EntityMetadataCollection} from "../metadata/collection/EntityMetadataCollection";
import {Broadcaster} from "../subscriber/Broadcaster";
import {Driver} from "../driver/Driver";
/**
* Repository is supposed to work with your entity objects. Find entities, insert, update, delete, etc.
*/
export class RepositoryBuilder {
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(protected connection: Connection,
protected entityMetadatas: EntityMetadataCollection,
protected metadata: EntityMetadata) {
}
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
}

View File

@ -0,0 +1,37 @@
import {TreeRepository} from "./TreeRepository";
import {EntityMetadata} from "../metadata/EntityMetadata";
import {EntityMetadataCollection} from "../metadata/collection/EntityMetadataCollection";
import {Connection} from "../connection/Connection";
import {Repository} from "./Repository";
import {ReactiveRepository} from "./ReactiveRepository";
import {ReactiveTreeRepository} from "./ReactiveTreeRepository";
/**
*/
export class RepositoryFactory {
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
createRepository(connection: Connection,
allMetadatas: EntityMetadataCollection,
metadata: EntityMetadata) {
return new Repository<any>(connection, allMetadatas, metadata);
}
createTreeRepository(connection: Connection,
allMetadatas: EntityMetadataCollection,
metadata: EntityMetadata) {
return new TreeRepository<any>(connection, allMetadatas, metadata);
}
createReactiveRepository(repository: Repository<any>) {
return new ReactiveRepository(repository);
}
createReactiveTreeRepository(repository: TreeRepository<any>) {
return new ReactiveTreeRepository(repository);
}
}

View File

@ -0,0 +1,17 @@
import {SchemaBuilder} from "../schema-builder/SchemaBuilder";
import {SchemaCreator} from "./SchemaCreator";
import {EntityMetadataCollection} from "../metadata/collection/EntityMetadataCollection";
/**
*/
export class SchemaCreatorFactory {
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
create(schemaBuilder: SchemaBuilder, entityMetadatas: EntityMetadataCollection) {
return new SchemaCreator(schemaBuilder, entityMetadatas);
}
}

View File

@ -51,9 +51,7 @@ describe("persistence > many-to-many", function() {
// clean up database before each test
function reloadDatabase() {
return connection.driver
.clearDatabase()
.then(() => connection.syncSchema())
return connection.syncSchema(true)
.catch(e => console.log("Error during schema re-creation: ", e));
}

View File

@ -45,9 +45,7 @@ describe("persistence > one-to-many", function() {
// clean up database before each test
function reloadDatabase() {
return connection.driver
.clearDatabase()
.then(() => connection.syncSchema())
return connection.syncSchema(true)
.catch(e => console.log("Error during schema re-creation: ", e));
}

View File

@ -41,9 +41,7 @@ describe("insertion", function() {
// clean up database before each test
function reloadDatabase() {
return connection.driver
.clearDatabase()
.then(() => connection.syncSchema())
return connection.syncSchema(true)
.catch(e => console.log("Error during schema re-creation: ", e));
}

View File

@ -50,9 +50,7 @@ describe("one-to-one", function() {
// clean up database before each test
function reloadDatabase() {
return connection.driver
.clearDatabase()
.then(() => connection.syncSchema());
return connection.syncSchema(true);
}
let postRepository: Repository<Post>,

View File

@ -47,9 +47,7 @@ describe("many-to-one", function() {
// clean up database before each test
function reloadDatabase() {
return connection.driver
.clearDatabase()
.then(() => connection.syncSchema());
return connection.syncSchema(true);
}
let postRepository: Repository<Post>,

View File

@ -49,9 +49,7 @@ describe("many-to-many", function() {
// clean up database before each test
function reloadDatabase() {
return connection.driver
.clearDatabase()
.then(() => connection.syncSchema());
return connection.syncSchema(true);
}
let postRepository: Repository<Post>,

View File

@ -32,9 +32,7 @@ export function setupConnection(entities: Function[], callback?: (connection: Co
export function reloadDatabase(connection: Connection) {
return function () {
return connection.driver
.clearDatabase()
.then(() => connection.syncSchema())
return connection.syncSchema(true)
.catch(e => console.log("Error during schema re-creation: ", e));
};
}