metadata refactoring

This commit is contained in:
Umed Khudoiberdiev 2016-03-20 22:16:21 +05:00
parent 3764579896
commit eb78d759d7
14 changed files with 155 additions and 51 deletions

View File

@ -9,6 +9,11 @@ import {EntityMetadata} from "../metadata-builder/metadata/EntityMetadata";
import {SchemaCreator} from "../schema-creator/SchemaCreator";
import {MetadataNotFoundError} from "./error/MetadataNotFoundError";
interface RepositoryAndMetadata {
repository: Repository<any>;
metadata: EntityMetadata;
}
/**
* A single connection instance to the database. Each connection has its own repositories, subscribers and metadatas.
*/
@ -23,7 +28,7 @@ export class Connection {
private _metadatas: EntityMetadata[] = [];
private _subscribers: OrmSubscriber<any>[] = [];
private _broadcasters: OrmBroadcaster<any>[] = [];
private _repositories: Repository<any>[] = [];
private repositoryAndMetadatas: RepositoryAndMetadata[] = [];
private _options: ConnectionOptions;
// -------------------------------------------------------------------------
@ -79,7 +84,7 @@ export class Connection {
* All repositories that are registered for this connection.
*/
get repositories(): Repository<any>[] {
return this._repositories;
return this.repositoryAndMetadatas.map(repoAndMeta => repoAndMeta.repository);
}
/**
@ -120,7 +125,7 @@ export class Connection {
addMetadatas(metadatas: EntityMetadata[]) {
this._metadatas = this._metadatas.concat(metadatas);
this._broadcasters = this._broadcasters.concat(metadatas.map(metadata => this.createBroadcasterForMetadata(metadata)));
this._repositories = this._repositories.concat(metadatas.map(metadata => this.createRepositoryForMetadata(metadata)));
this.repositoryAndMetadatas = this.repositoryAndMetadatas.concat(metadatas.map(metadata => this.createRepoMeta(metadata)));
}
/**
@ -135,11 +140,11 @@ export class Connection {
*/
getRepository<Entity>(entityClass: Function): Repository<Entity> {
const metadata = this.getMetadata(entityClass);
const repository = this.repositories.find(repository => repository.metadata === metadata);
if (!repository)
const repoMeta = this.repositoryAndMetadatas.find(repoMeta => repoMeta.metadata === metadata);
if (!repoMeta)
throw new RepositoryNotFoundError(entityClass);
return repository;
return repoMeta.repository;
}
/**
@ -172,8 +177,11 @@ export class Connection {
return new OrmBroadcaster<any>(this.subscribers, metadata.target);
}
private createRepositoryForMetadata(metadata: EntityMetadata): Repository<any> {
return new Repository<any>(this, metadata, this.getBroadcaster(metadata.target));
private createRepoMeta(metadata: EntityMetadata): RepositoryAndMetadata {
return {
metadata: metadata,
repository: new Repository<any>(this, metadata, this.getBroadcaster(metadata.target))
};
}
}

View File

@ -4,8 +4,8 @@ import {IndexMetadata} from "../../metadata-builder/metadata/IndexMetadata";
/**
* Fields that needs to be indexed must be marked with this decorator.
*/
export function Index() {
export function Index(name?: string) {
return function (object: Object, propertyName: string) {
defaultMetadataStorage.addIndexMetadata(new IndexMetadata(object.constructor, propertyName));
defaultMetadataStorage.addIndexMetadata(new IndexMetadata(object.constructor, propertyName, name));
};
}

View File

@ -70,21 +70,6 @@ export class EntityMetadataBuilder {
entityIndices = entityIndices.concat(inheritedIndices);
});
// generate columns for relations
/* const relationColumns = entityRelations
.filter(relation => relation.isOwning && (relation.relationType === RelationTypes.ONE_TO_ONE || relation.relationType ===RelationTypes.MANY_TO_ONE))
.filter(relation => !entityColumns.find(column => column.name === relation.name))
.map(relation => {
const options: ColumnOptions = {
type: "int", // todo: setup proper inverse side type later
oldColumnName: relation.oldColumnName,
isNullable: relation.isNullable
};
return new ColumnMetadata(tableMetadata.target, relation.name, false, false, false, options);
});
const allColumns = entityColumns.concat(relationColumns);*/
const entityMetadata = new EntityMetadata(tableMetadata, entityColumns, entityRelations, entityIndices, entityCompoundIndices, []);
// set naming strategies

View File

@ -4,7 +4,7 @@ export class MetadataWithSuchNameAlreadyExistsError extends Error {
constructor(metadataType: string, name: string) {
super();
this.message = metadataType + " metadata with such name " + name + " already exists. " +
"Do you apply something twice? Or maybe try to change a name?";
"Do you apply decorator twice? Or maybe try to change a name?";
}
}

View File

@ -7,12 +7,40 @@ import {ColumnType} from "../types/ColumnTypes";
* Constructor arguments for ColumnMetadata class.
*/
export interface ColumnMetadataArgs {
/**
* Class to which this column is applied.
*/
target: Function;
/**
* Class's property name to which this column is applied.
*/
propertyName: string;
/**
* Indicates if this column is primary key or not.
*/
isPrimaryKey?: boolean;
/**
* Indicates if this column is create date column or not.
*/
isCreateDate?: boolean;
/**
* Indicates if this column is update date column or not.
*/
isUpdateDate?: boolean;
/**
* Indicates if this column is virtual or not.
*/
isVirtual?: boolean;
/**
* Extra column options.
*/
options: ColumnOptions;
}

View File

@ -1,5 +1,5 @@
/**
* This metadata interface contains all information about compound index on a document.
* This metadata interface contains all information about table's compound index.
*/
export class CompoundIndexMetadata {
@ -7,6 +7,9 @@ export class CompoundIndexMetadata {
// Private Properties
// ---------------------------------------------------------------------
/**
* Class to which this decorator is applied.
*/
private _target: Function;
/**
@ -34,6 +37,9 @@ export class CompoundIndexMetadata {
return this._target;
}
/**
* Fields combination to be used as index.
*/
get fields() {
return this._fields;
}

View File

@ -10,9 +10,24 @@ export class ForeignKeyMetadata {
// Properties
// -------------------------------------------------------------------------
/**
* Table to which this foreign key is applied.
*/
private _table: TableMetadata;
/**
* Array of columns.
*/
private _columns: ColumnMetadata[];
/**
* Table to which this foreign key is references.
*/
private _referencedTable: TableMetadata;
/**
* Array of referenced columns.
*/
private _referencedColumns: ColumnMetadata[];
// -------------------------------------------------------------------------
@ -30,34 +45,55 @@ export class ForeignKeyMetadata {
// Accessors
// -------------------------------------------------------------------------
/**
* Table to which this foreign key is applied.
*/
get table(): TableMetadata {
return this._table;
}
/**
* Array of columns.
*/
get columns(): ColumnMetadata[] {
return this._columns;
}
/**
* Table to which this foreign key is references.
*/
get referencedTable(): TableMetadata {
return this._referencedTable;
}
/**
* Array of referenced columns.
*/
get referencedColumns(): ColumnMetadata[] {
return this._referencedColumns;
}
/**
* Array of column names.
*/
get columnNames(): string[] {
return this.columns.map(column => column.name)
}
/**
* Array of referenced column names.
*/
get referencedColumnNames(): string[] {
return this.referencedColumns.map(column => column.name)
}
/**
* Foreign key name.
*/
get name() {
const key = `${this.table.name}_${this.columnNames.join("_")}` +
`_${this.referencedTable.name}_${this.referencedColumnNames.join("_")}`;
return "fk_" + require('sha1')(key);
return "fk_" + require('sha1')(key); // todo: use crypto instead?
}
}

View File

@ -9,5 +9,15 @@ export class IndexMetadata extends PropertyMetadata {
* The name of the index.
*/
name: string;
// ---------------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------------
constructor(target: Function, propertyName: string, name?: string) {
super(target, propertyName);
this.name = name; // todo: if there is no name, then generate it
}
}

View File

@ -1,4 +1,5 @@
/**
* Contains metadata information about ORM event subscribers.
*/
export class OrmEventSubscriberMetadata {
@ -6,6 +7,9 @@ export class OrmEventSubscriberMetadata {
// Private Properties
// ---------------------------------------------------------------------
/**
* Class to which this decorator is applied.
*/
private _target: Function;
// ---------------------------------------------------------------------

View File

@ -7,7 +7,14 @@ export abstract class PropertyMetadata {
// Properties
// ---------------------------------------------------------------------
/**
* Class to which this decorator is applied.
*/
private _target: Function;
/**
* Class's property name to which this decorator is applied.
*/
private _propertyName: string;
// ---------------------------------------------------------------------

View File

@ -65,8 +65,10 @@ export class RelationMetadata extends PropertyMetadata {
// Public Properties
// ---------------------------------------------------------------------
/**
* Naming strategy used to generate and normalize column name.
*/
namingStrategy: NamingStrategy;
// ownerEntityPropertiesMap: Object;
// ---------------------------------------------------------------------
// Private Properties

View File

@ -1,7 +1,7 @@
import {NamingStrategy} from "../../naming-strategy/NamingStrategy";
/**
* This metadata interface contains all information about some table.
* This metadata interface contains all information about specific table.
*/
export class TableMetadata {
@ -9,14 +9,28 @@ export class TableMetadata {
// Public Properties
// ---------------------------------------------------------------------
/**
* Naming strategy used to generate and normalize table name.
*/
namingStrategy: NamingStrategy;
// ---------------------------------------------------------------------
// Private Properties
// ---------------------------------------------------------------------
/**
* Class to which this column is applied.
*/
private _target: Function;
/**
* Table name in the database.
*/
private _name: string;
/**
* Indicates if this table is abstract or not. Regular tables can inherit columns from abstract tables.
*/
private _isAbstract: boolean;
// ---------------------------------------------------------------------
@ -41,10 +55,16 @@ export class TableMetadata {
return this._target;
}
/**
* Table name in the database.
*/
get name() {
return this.namingStrategy ? this.namingStrategy.tableName(this._name) : this._name;
}
/**
* Indicates if this table is abstract or not. Regular tables can inherit columns from abstract tables.
*/
get isAbstract() {
return this._isAbstract;
}

View File

@ -1,4 +1,3 @@
/**
* Describes all relation's options.
*/

View File

@ -20,8 +20,19 @@ export class Repository<Entity> {
// Properties
// -------------------------------------------------------------------------
private _connection: Connection;
private _metadata: EntityMetadata;
/**
* Connection used by this repository.
*/
private connection: Connection;
/**
* Entity metadata of the table with which this repository is working.
*/
private metadata: EntityMetadata;
/**
* Broadcaster used to broadcast this repository events.
*/
private broadcaster: OrmBroadcaster<Entity>;
// -------------------------------------------------------------------------
@ -31,23 +42,11 @@ export class Repository<Entity> {
constructor(connection: Connection,
metadata: EntityMetadata,
broadcaster: OrmBroadcaster<Entity>) {
this._connection = connection;
this._metadata = metadata;
this.connection = connection;
this.metadata = metadata;
this.broadcaster = broadcaster;
}
// -------------------------------------------------------------------------
// Getter Methods
// -------------------------------------------------------------------------
get metadata(): EntityMetadata {
return this._metadata;
}
get connection(): Connection {
return this._connection;
}
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
@ -129,7 +128,7 @@ export class Repository<Entity> {
const persistOperation = this.difference(dbEntity, entity);
return persister.executePersistOperation(persistOperation);
}).then(() => entity);
}
}
/**
* Finds entities that match given conditions.