added prefix support to embeddeds

This commit is contained in:
Umed Khudoiberdiev 2017-02-23 18:29:38 +05:00
parent 0e207a2e48
commit 4b1651176e
10 changed files with 41 additions and 16 deletions

View File

@ -23,6 +23,7 @@ each for its own `findOne*` or `find*` methods
* added `mongodb` support
* entity now can be saved partially within `persist` method
* added prefix support to embeddeds
### BUG FIXES

View File

@ -7,7 +7,7 @@ import {EmbeddedMetadataArgs} from "../metadata-args/EmbeddedMetadataArgs";
* single table of the entity where Embedded is used. And on hydration all columns which supposed to be in the
* embedded will be mapped to it from the single table.
*/
export function Embedded<T>(typeFunction: (type?: any) => ObjectType<T>, options?: { /*prefix: string, */ array?: boolean }) {
export function Embedded<T>(typeFunction: (type?: any) => ObjectType<T>, options?: { prefix?: string, array?: boolean }) {
return function (object: Object, propertyName: string) {
const reflectMetadataType = Reflect && (Reflect as any).getMetadata ? (Reflect as any).getMetadata("design:type", object, propertyName) : undefined;
@ -17,6 +17,7 @@ export function Embedded<T>(typeFunction: (type?: any) => ObjectType<T>, options
target: object.constructor,
propertyName: propertyName,
isArray: isArray,
prefix: options && options.prefix !== undefined ? options.prefix : undefined,
type: typeFunction
};
getMetadataArgsStorage().embeddeds.add(args);

View File

@ -18,6 +18,12 @@ export interface EmbeddedMetadataArgs {
*/
readonly isArray: boolean;
/**
* Prefix of the embedded, used instead of propertyName.
* If set to empty string, then prefix is not set at all.
*/
readonly prefix?: string;
/**
* Type of the class to be embedded.
*/

View File

@ -204,7 +204,7 @@ export class EntityMetadataBuilder {
const table = new TableMetadata(embeddableTable.table);
const columns = embeddableTable.columns.toArray().map(args => new ColumnMetadata(args));
const subEmbeddeds = findEmbeddedsRecursively(embeddableTable.embeddeds.toArray());
embeddeds.push(new EmbeddedMetadata(embedded.type(), embedded.propertyName, embedded.isArray, table, columns, subEmbeddeds));
embeddeds.push(new EmbeddedMetadata(table, columns, subEmbeddeds, embedded));
}
});
return embeddeds;

View File

@ -105,6 +105,7 @@ export class EntityMetadataValidator {
// todo: add validation if there two entities with the same target, and show error message with description of the problem (maybe file was renamed/moved but left in output directory)
// todo: check if there are multiple columns on the same column applied.
// todo: check column type if is missing in relational databases (throw new Error(`Column type of ${type} cannot be determined.`);)
// todo: include driver-specific checks. for example in mongodb empty prefixes are not allowed
});

View File

@ -219,7 +219,7 @@ export class ColumnMetadata {
};
buildPrefixRecursively(this.embeddedMetadata);
return this.entityMetadata.namingStrategy.embeddedColumnName(prefixes.join("_"), this.propertyName, this._name); // todo: this .join("_") logic should be part of naming strategy
return this.entityMetadata.namingStrategy.embeddedColumnName(prefixes, this.propertyName, this._name);
}
// if there is a naming strategy then use it to normalize propertyName as column name

View File

@ -1,6 +1,7 @@
import {EntityMetadata} from "./EntityMetadata";
import {TableMetadata} from "./TableMetadata";
import {ColumnMetadata} from "./ColumnMetadata";
import {EmbeddedMetadataArgs} from "../metadata-args/EmbeddedMetadataArgs";
/**
* Contains all information about entity's embedded property.
@ -55,19 +56,24 @@ export class EmbeddedMetadata {
*/
readonly isArray: boolean;
/**
* Prefix of the embedded, used instead of propertyName.
* If set to empty string, then prefix is not set at all.
*/
readonly customPrefix: string|undefined;
// ---------------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------------
constructor(type: Function|undefined,
propertyName: string,
isArray: boolean,
table: TableMetadata,
constructor(table: TableMetadata,
columns: ColumnMetadata[],
embeddeds: EmbeddedMetadata[]) {
this.type = type;
this.propertyName = propertyName;
this.isArray = isArray;
embeddeds: EmbeddedMetadata[],
args: EmbeddedMetadataArgs) {
this.type = args.type ? args.type() : undefined;
this.propertyName = args.propertyName;
this.isArray = args.isArray;
this.customPrefix = args.prefix;
this.table = table;
this.columns = columns;
this.embeddeds = embeddeds;
@ -93,8 +99,16 @@ export class EmbeddedMetadata {
return new (this.type as any);
}
/**
* Gets the prefix of the columns.
* By default its a property name of the class where this prefix is.
* But if custom prefix is set then it takes its value as a prefix.
* However if custom prefix is set to empty string prefix to column is not applied at all.
*/
get prefix() {
// todo: implement custom prefix later
if (this.customPrefix !== undefined)
return this.customPrefix;
return this.propertyName;
}

View File

@ -15,9 +15,11 @@ export class DefaultNamingStrategy implements NamingStrategyInterface {
return customName ? customName : propertyName;
}
embeddedColumnName(embeddedPropertyName: string, columnPropertyName: string, columnCustomName?: string): string {
embeddedColumnName(prefixes: string[], columnPropertyName: string, columnCustomName?: string): string {
// todo: need snake case property name but only if its a property name and not a custom embedded prefix
return camelCase(embeddedPropertyName + "_" + (columnCustomName ? columnCustomName : columnPropertyName));
prefixes = prefixes.filter(prefix => !!prefix);
const embeddedPropertyName = prefixes.length ? prefixes.join("_") + "_" : "";
return camelCase(embeddedPropertyName + (columnCustomName ? columnCustomName : columnPropertyName));
}
relationName(propertyName: string): string {

View File

@ -22,7 +22,7 @@ export interface NamingStrategyInterface {
/**
* Gets the embedded's column name from the given property name.
*/
embeddedColumnName(embeddedPropertyName: string, columnPropertyName: string, columnCustomName?: string): string;
embeddedColumnName(prefixes: string[], columnPropertyName: string, columnCustomName?: string): string;
/**
* Gets the table's relation name from the given property name.

View File

@ -5,7 +5,7 @@ import {expect} from "chai";
import {Race} from "./entity/Race";
import {Duration} from "./entity/Duration";
describe.only("github issues > embeddeds with custom column name don't work", () => {
describe("github issues > embeddeds with custom column name don't work", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({