refactored require entities from directories part

This commit is contained in:
Umed Khudoiberdiev 2016-03-13 14:05:20 +05:00
parent 5f92ede75c
commit 7a2fe7b143
7 changed files with 100 additions and 85 deletions

View File

@ -44,11 +44,12 @@
"dependencies": {
"fs": "^0.0.2",
"lodash": "^4.5.0",
"mysql": "^2.10.2",
"path": "^0.11.14",
"reflect-metadata": "^0.1.3",
"require-all": "^2.0.0",
"sha1": "^1.1.1",
"typedi": "~0.2.0",
"mysql": "^2.10.2"
"typedi": "~0.2.0"
},
"scripts": {
"postversion": "./node_modules/.bin/gulp package",

View File

@ -1,11 +1,6 @@
import {createMysqlConnection} from "../../src/typeorm";
import {Post} from "./entity/Post";
import {PostDetails} from "./entity/PostDetails";
import {PostCategory} from "./entity/PostCategory";
import {PostMetadata} from "./entity/PostMetadata";
import {PostImage} from "./entity/PostImage";
import {PostInformation} from "./entity/PostInformation";
import {PostAuthor} from "./entity/PostAuthor";
// first create a connection
let options = {
@ -17,7 +12,7 @@ let options = {
autoSchemaCreate: true
};
createMysqlConnection(options, [Post, PostDetails, PostCategory, PostMetadata, PostImage, PostInformation, PostAuthor]).then(connection => {
createMysqlConnection(options, [__dirname + "/entity"]).then(connection => {
let details1 = new PostDetails();
details1.comment = "People";

View File

@ -1,18 +1,16 @@
import {Connection} from "./Connection";
import {OrmUtils} from "../util/OrmUtils";
import {defaultMetadataStorage} from "../metadata-builder/MetadataStorage";
import {Driver} from "../driver/Driver";
import {DefaultNamingStrategy} from "../naming-strategy/DefaultNamingStrategy";
import {ConnectionNotFoundError} from "./error/ConnectionNotFoundError";
import {EntityMetadataBuilder} from "../metadata-builder/EntityMetadataBuilder";
import {importClassesFromDirectories} from "../util/DirectoryExportedClassesLoader";
/**
* Connection manager holds all connections made to the databases.
*/
export class ConnectionManager {
// todo: add support for importing entities and subscribers from subdirectories, make support of glob patterns
// -------------------------------------------------------------------------
// Properties
// -------------------------------------------------------------------------
@ -36,7 +34,7 @@ export class ConnectionManager {
/**
* Sets a container that can be used in custom user subscribers. This allows to inject services in user classes.
*/
set container(container: { get(someClass: any): any }) {
set container(container: { get(someClass: Function): any }) {
this._container = container;
}
@ -69,24 +67,6 @@ export class ConnectionManager {
return foundConnection;
}
/**
* Imports entities for the given connection. If connection name is not given then default connection is used.
*/
importEntities(entities: Function[]): void;
importEntities(connectionName: string, entities: Function[]): void;
importEntities(connectionNameOrEntities: string|Function[], entities?: Function[]): void {
let connectionName = "default";
if (typeof connectionNameOrEntities === "string") {
connectionName = <string> connectionNameOrEntities;
} else {
entities = <Function[]> connectionNameOrEntities;
}
const metadatas = this.entityMetadataBuilder.build(entities);
if (metadatas.length > 0)
this.getConnection(connectionName).addMetadatas(metadatas);
}
/**
* Imports entities from the given paths (directories) for the given connection. If connection name is not given
* then default connection is used.
@ -101,12 +81,7 @@ export class ConnectionManager {
paths = <string[]> connectionNameOrPaths;
}
const entitiesInFiles = OrmUtils.requireAll(paths);
const allEntities = entitiesInFiles.reduce((allEntities, entities) => {
return allEntities.concat(Object.keys(entities).map(key => entities[key]));
}, []);
this.importEntities(connectionName, allEntities);
this.importEntities(connectionName, importClassesFromDirectories(paths));
}
/**
@ -115,27 +90,45 @@ export class ConnectionManager {
*/
importSubscribersFromDirectories(paths: string[]): void;
importSubscribersFromDirectories(connectionName: string, paths: string[]): void;
importSubscribersFromDirectories(connectionName: any, paths?: string[]): void {
if (typeof connectionName === "object") {
paths = connectionName;
connectionName = "default";
importSubscribersFromDirectories(connectionNameOrPaths: string|string[], paths?: string[]): void {
let connectionName = "default";
if (typeof connectionNameOrPaths === "string") {
connectionName = <string> connectionNameOrPaths;
} else {
paths = <string[]> connectionNameOrPaths;
}
const subscribersInFiles = OrmUtils.requireAll(paths);
const allSubscriberClasses = subscribersInFiles.reduce((all, subscriberInFile) => {
return all.concat(Object.keys(subscriberInFile).map(key => subscriberInFile[key]));
}, []);
const allSubscriberClasses = importClassesFromDirectories(paths);
const subscribers = defaultMetadataStorage
.ormEventSubscriberMetadatas
.filter(metadata => allSubscriberClasses.indexOf(metadata.constructor) !== -1)
.map(metadata => {
const constructor: any = metadata.constructor;
return this._container ? this._container.get(constructor) : new constructor();
});
if (subscribers.length > 0)
this.getConnection(connectionName).addSubscribers(subscribers);
.findOrmEventSubscribersForClasses(allSubscriberClasses)
.map(metadata => this.createContainerInstance(metadata.constructor));
this.getConnection(connectionName).addSubscribers(subscribers);
}
/**
* Imports entities for the given connection. If connection name is not given then default connection is used.
*/
importEntities(entities: Function[]): void;
importEntities(connectionName: string, entities: Function[]): void;
importEntities(connectionNameOrEntities: string|Function[], entities?: Function[]): void {
let connectionName = "default";
if (typeof connectionNameOrEntities === "string") {
connectionName = <string> connectionNameOrEntities;
} else {
entities = <Function[]> connectionNameOrEntities;
}
const metadatas = this.entityMetadataBuilder.build(entities);
this.getConnection(connectionName).addMetadatas(metadatas);
}
// -------------------------------------------------------------------------
// Private Methods
// -------------------------------------------------------------------------
private createContainerInstance(constructor: Function) {
return this._container ? this._container.get(constructor) : new (<any> constructor)();
}
}

View File

@ -114,6 +114,11 @@ export class MetadataStorage {
// Public Methods
// -------------------------------------------------------------------------
findOrmEventSubscribersForClasses(classes: Function[]): OrmEventSubscriberMetadata[] {
// todo: didn't checked. Check if is working. Maybe dont need to use target and use constructor somehow?
return this.ormEventSubscriberMetadatas.filter(metadata => classes.indexOf(metadata.target) !== -1);
}
findTableMetadatasForClasses(classes: Function[]): TableMetadata[] {
return this.tableMetadatas.filter(metadata => classes.indexOf(metadata.target) !== -1);
}

View File

@ -0,0 +1,51 @@
import * as fs from "fs";
/**
* Loads all exported classes from the given directory.
*/
export class DirectoryExportedClassesLoader {
// todo: this can be extracted into external module and used across all other modules
// todo: add support for glob patterns
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
/**
* Imports all entities (makes them "require") from the given directories.
*/
importClassesFromDirectories(directories: string[]): Function[] {
const requireAll = require("require-all");
const filter = /(.*)\.js$/;
const dirs = directories
.filter(directory => fs.existsSync(directory))
.map(directory => requireAll({ dirname: directory, filter: filter, recursive: true }));
return this.loadFileClasses(dirs, []);
}
// -------------------------------------------------------------------------
// Private Methods
// -------------------------------------------------------------------------
private loadFileClasses(exported: any, allLoaded: Function[]) {
if (exported instanceof Function) {
allLoaded.push(exported);
} else if (exported instanceof Object) {
Object.keys(exported).forEach(key => this.loadFileClasses(exported[key], allLoaded));
} else if (exported instanceof Array) {
exported.forEach((i: any) => this.loadFileClasses(i, allLoaded));
}
return allLoaded;
}
}
export function importClassesFromDirectories(directories: string[]): Function[] {
const loader = new DirectoryExportedClassesLoader();
return loader.importClassesFromDirectories(directories);
}

View File

@ -1,30 +0,0 @@
import * as fs from "fs";
import * as path from "path";
/**
* Common utility functions.
*/
export class OrmUtils {
/**
* Makes "require()" all js files (or custom extension files) in the given directory.
* @deprecated use npm module instead
*/
static requireAll(directories: string[], extension: string = ".js"): any[] {
let files: any[] = [];
directories.forEach((dir: string) => {
if (fs.existsSync(dir)) {
fs.readdirSync(dir).forEach((file: string) => {
if (fs.statSync(dir + "/" + file).isDirectory()) {
let requiredFiles = this.requireAll([dir + "/" + file], extension);
requiredFiles.forEach((file: string) => files.push(file));
} else if (path.extname(file) === extension) {
files.push(require(dir + "/" + file));
}
});
}
}); // todo: implement recursion
return files;
}
}

View File

@ -32,7 +32,7 @@ describe("many-to-many", function() {
// connect to db
let connection: Connection;
before(function() {
return createMysqlConnection(options, [Post, PostDetails, PostCategory, PostMetadata, PostImage, PostInformation, PostAuthor]).then(conn => {
return createMysqlConnection(options, [__dirname + "/../../sample/sample4-many-to-many/entity"]).then(conn => {
connection = conn;
}).catch(e => console.log("Error during connection to db: " + e));
});