mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
added prefix support to embeddeds
This commit is contained in:
parent
0e207a2e48
commit
4b1651176e
@ -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
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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.
|
||||
*/
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
});
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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({
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user