mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
refactoring persistence
This commit is contained in:
parent
1f5c6e0bf1
commit
e14fce5524
@ -11,7 +11,7 @@ export interface RelationOptions {
|
||||
* If set to true then it means that related object can be allowed to be inserted / updated / removed to the db.
|
||||
* This is option a shortcut if you would like to set cascadeInsert, cascadeUpdate and cascadeRemove to true.
|
||||
*/
|
||||
cascadeAll?: boolean;
|
||||
cascadeAll?: boolean; // todo: replace with cascade: boolean|("insert"|"update")[]
|
||||
|
||||
/**
|
||||
* If set to true then it means that related object can be allowed to be inserted to the db.
|
||||
|
||||
@ -17,6 +17,7 @@ import {DataTypeDefaults} from "../types/DataTypeDefaults";
|
||||
import {TableColumn} from "../../schema-builder/schema/TableColumn";
|
||||
import {PostgresConnectionCredentialsOptions} from "./PostgresConnectionCredentialsOptions";
|
||||
import {EntityMetadata} from "../../metadata/EntityMetadata";
|
||||
import {OrmUtils} from "../../util/OrmUtils";
|
||||
|
||||
/**
|
||||
* Organizes communication with PostgreSQL DBMS.
|
||||
@ -560,7 +561,17 @@ export class PostgresDriver implements Driver {
|
||||
* Creates generated map of values generated or returned by database after INSERT query.
|
||||
*/
|
||||
createGeneratedMap(metadata: EntityMetadata, insertResult: any) {
|
||||
return insertResult[0];
|
||||
if (!insertResult || !insertResult[0])
|
||||
return undefined;
|
||||
|
||||
const result: ObjectLiteral = insertResult[0];
|
||||
return Object.keys(result).reduce((map, key) => {
|
||||
const column = metadata.findColumnWithDatabaseName(key);
|
||||
if (column) {
|
||||
OrmUtils.mergeDeep(map, column.createValueMap(result[key]));
|
||||
}
|
||||
return map;
|
||||
}, {} as ObjectLiteral);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -17,6 +17,7 @@ import {MssqlParameter} from "./MssqlParameter";
|
||||
import {TableColumn} from "../../schema-builder/schema/TableColumn";
|
||||
import {SqlServerConnectionCredentialsOptions} from "./SqlServerConnectionCredentialsOptions";
|
||||
import {EntityMetadata} from "../../metadata/EntityMetadata";
|
||||
import {OrmUtils} from "../../util/OrmUtils";
|
||||
|
||||
/**
|
||||
* Organizes communication with SQL Server DBMS.
|
||||
@ -468,8 +469,18 @@ export class SqlServerDriver implements Driver {
|
||||
/**
|
||||
* Creates generated map of values generated or returned by database after INSERT query.
|
||||
*/
|
||||
createGeneratedMap(metadata: EntityMetadata, insertionResult: any) {
|
||||
return insertionResult[0];
|
||||
createGeneratedMap(metadata: EntityMetadata, insertResult: any) {
|
||||
if (!insertResult || !insertResult[0])
|
||||
return undefined;
|
||||
|
||||
const result: ObjectLiteral = insertResult[0];
|
||||
return Object.keys(result).reduce((map, key) => {
|
||||
const column = metadata.findColumnWithDatabaseName(key);
|
||||
if (column) {
|
||||
OrmUtils.mergeDeep(map, column.createValueMap(result[key]));
|
||||
}
|
||||
return map;
|
||||
}, {} as ObjectLiteral);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -326,6 +326,7 @@ export class EntityMetadataBuilder {
|
||||
});
|
||||
embeddedMetadata.embeddeds = this.createEmbeddedsRecursively(entityMetadata, this.metadataArgsStorage.filterEmbeddeds(targets));
|
||||
embeddedMetadata.embeddeds.forEach(subEmbedded => subEmbedded.parentEmbeddedMetadata = embeddedMetadata);
|
||||
entityMetadata.allEmbeddeds.push(embeddedMetadata);
|
||||
return embeddedMetadata;
|
||||
});
|
||||
}
|
||||
|
||||
@ -364,7 +364,7 @@ export class ColumnMetadata {
|
||||
* Examples what this method can return depend if this column is in embeds.
|
||||
* { id: 1 } or { title: "hello" }, { counters: { code: 1 } }, { data: { information: { counters: { code: 1 } } } }
|
||||
*/
|
||||
getEntityValueMap(entity: ObjectLiteral, returnIfEmpty: boolean = false): ObjectLiteral {
|
||||
getEntityValueMap(entity: ObjectLiteral): ObjectLiteral|undefined {
|
||||
|
||||
// extract column value from embeds of entity if column is in embedded
|
||||
if (this.embeddedMetadata) {
|
||||
@ -393,16 +393,21 @@ export class ColumnMetadata {
|
||||
};
|
||||
const map: ObjectLiteral = {};
|
||||
extractEmbeddedColumnValue(propertyNames, entity, map);
|
||||
return map;
|
||||
return Object.keys(map).length > 0 ? map : undefined;
|
||||
|
||||
} else { // no embeds - no problems. Simply return column property name and its value of the entity
|
||||
if (this.relationMetadata && entity[this.propertyName] && entity[this.propertyName] instanceof Object) {
|
||||
const map = this.relationMetadata.joinColumns.reduce((map, joinColumn) => {
|
||||
return OrmUtils.mergeDeep(map, joinColumn.referencedColumn!.getEntityValueMap(entity[this.propertyName]));
|
||||
const value = joinColumn.referencedColumn!.getEntityValueMap(entity[this.propertyName]);
|
||||
if (!value) return map;
|
||||
return OrmUtils.mergeDeep(map, value);
|
||||
}, {});
|
||||
return { [this.propertyName]: map };
|
||||
return { [this.propertyName]: Object.keys(map).length > 0 ? map : undefined };
|
||||
} else {
|
||||
return { [this.propertyName]: entity[this.propertyName] };
|
||||
if (entity[this.propertyName] !== undefined)
|
||||
return { [this.propertyName]: entity[this.propertyName] };
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -443,7 +448,7 @@ export class ColumnMetadata {
|
||||
return undefined;
|
||||
|
||||
} else { // no embeds - no problems. Simply return column name by property name of the entity
|
||||
if (this.relationMetadata && this.referencedColumn && this.isVirtual) { // todo: do we really need isVirtual?
|
||||
if (this.relationMetadata && this.referencedColumn/* && this.isVirtual*/) { // todo: do we really need isVirtual?
|
||||
const relatedEntity = this.relationMetadata.getEntityValue(entity);
|
||||
if (relatedEntity && relatedEntity instanceof Object)
|
||||
return this.referencedColumn.getEntityValue(relatedEntity);
|
||||
|
||||
@ -159,7 +159,7 @@ export class EmbeddedMetadata {
|
||||
this.prefix = this.buildPrefix(connection);
|
||||
this.parentPropertyNames = this.buildParentPropertyNames();
|
||||
this.parentPrefixes = this.buildParentPrefixes();
|
||||
this.propertyPath = this.parentPrefixes.join(".");
|
||||
this.propertyPath = this.parentPropertyNames.join(".");
|
||||
this.embeddedMetadataTree = this.buildEmbeddedMetadataTree();
|
||||
this.columnsFromTree = this.buildColumnsFromTree();
|
||||
this.relationsFromTree = this.buildRelationsFromTree();
|
||||
|
||||
@ -210,6 +210,11 @@ export class EntityMetadata {
|
||||
*/
|
||||
embeddeds: EmbeddedMetadata[] = [];
|
||||
|
||||
/**
|
||||
* All embeddeds - embeddeds from this entity metadata and from all child embeddeds, etc.
|
||||
*/
|
||||
allEmbeddeds: EmbeddedMetadata[] = [];
|
||||
|
||||
/**
|
||||
* Entity listener metadatas.
|
||||
*/
|
||||
@ -495,7 +500,7 @@ export class EntityMetadata {
|
||||
* Finds embedded with a given property path.
|
||||
*/
|
||||
findEmbeddedWithPropertyPath(propertyPath: string): EmbeddedMetadata|undefined {
|
||||
return this.embeddeds.find(embedded => {
|
||||
return this.allEmbeddeds.find(embedded => {
|
||||
return embedded.propertyPath === propertyPath;
|
||||
});
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ export class EntityMetadataUtils {
|
||||
// example: .update().set({ name: () => `SUBSTR('', 1, 2)` })
|
||||
const parentPath = prefix ? prefix + "." + key : key;
|
||||
if (metadata.hasEmbeddedWithPropertyPath(parentPath)) {
|
||||
const subPaths = this.createPropertyPath(metadata, entity[key], key);
|
||||
const subPaths = this.createPropertyPath(metadata, entity[key], parentPath);
|
||||
paths.push(...subPaths);
|
||||
} else {
|
||||
const path = prefix ? prefix + "." + key : key;
|
||||
|
||||
@ -289,6 +289,8 @@ export class RelationMetadata {
|
||||
getRelationIdMap(entity: ObjectLiteral): ObjectLiteral|undefined {
|
||||
const joinColumns = this.isOwning ? this.joinColumns : this.inverseRelation!.joinColumns;
|
||||
const referencedColumns = joinColumns.map(joinColumn => joinColumn.referencedColumn!);
|
||||
// console.log("entity", entity);
|
||||
// console.log("referencedColumns", referencedColumns);
|
||||
return this.inverseEntityMetadata.getValueMap(entity, referencedColumns);
|
||||
}
|
||||
|
||||
|
||||
@ -129,16 +129,23 @@ export class Subject {
|
||||
}
|
||||
}
|
||||
|
||||
if (changeMap.column) {
|
||||
// value = changeMap.valueFactory ? changeMap.valueFactory(value) : changeMap.column.createValueMap(value);
|
||||
|
||||
if (this.metadata.isJunction && changeMap.column) {
|
||||
OrmUtils.mergeDeep(updateMap, changeMap.column.createValueMap(changeMap.column.referencedColumn!.getEntityValue(value)));
|
||||
|
||||
} else if (changeMap.column) {
|
||||
OrmUtils.mergeDeep(updateMap, changeMap.column.createValueMap(value));
|
||||
|
||||
} else if (changeMap.relation) {
|
||||
changeMap.relation!.joinColumns.forEach(column => {
|
||||
OrmUtils.mergeDeep(updateMap, column.createValueMap(value));
|
||||
});
|
||||
OrmUtils.mergeDeep(updateMap, changeMap.relation!.createValueMap(value));
|
||||
// changeMap.relation!.joinColumns.forEach(column => {
|
||||
// OrmUtils.mergeDeep(updateMap, column.createValueMap(value));
|
||||
// });
|
||||
}
|
||||
return updateMap;
|
||||
}, {} as ObjectLiteral);
|
||||
// console.log(changeSet);
|
||||
this.changeMaps = changeMapsWithoutValues;
|
||||
return changeSet;
|
||||
}
|
||||
@ -146,7 +153,7 @@ export class Subject {
|
||||
buildIdentifier() {
|
||||
return this.metadata.primaryColumns.reduce((identifier, column) => {
|
||||
if (column.isGenerated && this.generatedMap) {
|
||||
return OrmUtils.mergeDeep(identifier, column.createValueMap(this.generatedMap[column.databaseName]));
|
||||
return OrmUtils.mergeDeep(identifier, column.getEntityValueMap(this.generatedMap));
|
||||
} else {
|
||||
return OrmUtils.mergeDeep(identifier, column.getEntityValueMap(this.entity!));
|
||||
}
|
||||
|
||||
@ -25,4 +25,9 @@ export interface SubjectChangeMap {
|
||||
*/
|
||||
value: Subject|any;
|
||||
|
||||
/**
|
||||
* Callback used to produce a final value.
|
||||
*/
|
||||
valueFactory?: (value: any) => any;
|
||||
|
||||
}
|
||||
@ -113,10 +113,26 @@ export class SubjectExecutor {
|
||||
newInsertedSubjects.push(...entityTargetSubjects);
|
||||
entityTargetSubjects.forEach(entityTargetSubject => this.insertSubjects.splice(this.insertSubjects.indexOf(entityTargetSubject), 1));
|
||||
});
|
||||
|
||||
const dependencies2: string[][] = [];
|
||||
metadatas.forEach(metadata => {
|
||||
metadata.relationsWithJoinColumns.forEach(relation => {
|
||||
dependencies2.push([metadata.targetName, relation.inverseEntityMetadata.targetName]);
|
||||
});
|
||||
});
|
||||
|
||||
const sortedEntityTargets2 = OrmUtils.toposort(dependencies2).reverse();
|
||||
|
||||
const newInsertedSubjects2: Subject[] = [];
|
||||
sortedEntityTargets2.forEach(sortedEntityTarget => {
|
||||
const entityTargetSubjects = this.insertSubjects.filter(subject => subject.metadata.targetName === sortedEntityTarget);
|
||||
newInsertedSubjects2.push(...entityTargetSubjects);
|
||||
entityTargetSubjects.forEach(entityTargetSubject => this.insertSubjects.splice(this.insertSubjects.indexOf(entityTargetSubject), 1));
|
||||
});
|
||||
|
||||
newInsertedSubjects.push(...newInsertedSubjects2);
|
||||
newInsertedSubjects.push(...this.insertSubjects);
|
||||
this.insertSubjects = newInsertedSubjects;
|
||||
// console.log("dependencies", dependencies);
|
||||
// console.log("toposort", );
|
||||
}
|
||||
|
||||
await this.executeInsertOperations();
|
||||
@ -203,6 +219,10 @@ export class SubjectExecutor {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if (column.referencedColumn) {
|
||||
//
|
||||
// }
|
||||
|
||||
return true;
|
||||
});
|
||||
diffColumns.forEach(column => {
|
||||
@ -281,6 +301,8 @@ export class SubjectExecutor {
|
||||
*/
|
||||
protected async executeInsertOperations(): Promise<void> {
|
||||
|
||||
// console.log(this.insertSubjects.map(subject => subject.entity));
|
||||
|
||||
// then we run insertion in the sequential order which is important since we have an ordered subjects
|
||||
await PromiseUtils.runInSequence(this.insertSubjects, async subject => {
|
||||
|
||||
@ -308,7 +330,6 @@ export class SubjectExecutor {
|
||||
// const valueSets = this.getValueSets();
|
||||
// if (valueSets.length > 1)
|
||||
// throw Error(`Returning / output can be used only when a single value / entity is inserted.`);
|
||||
|
||||
// const alias = this.expressionMap.mainAlias!.name;
|
||||
// const returningResult = await this.createQueryBuilder()
|
||||
// .select(this.expressionMap.returning as string[])
|
||||
@ -323,12 +344,12 @@ export class SubjectExecutor {
|
||||
|
||||
if (subject.entity) {
|
||||
subject.identifier = subject.buildIdentifier();
|
||||
// console.log(subject.identifier);
|
||||
}
|
||||
|
||||
// if there are changes left mark it for updation
|
||||
if (subject.hasChanges()) {
|
||||
subject.canBeUpdated = true;
|
||||
// console.log("can be updated!", subject.mustBeUpdated);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -116,9 +116,7 @@ export class ManyToManySubjectBuilder {
|
||||
|
||||
// extract only relation id from the related entities, since we only need it for comparision
|
||||
// by example: extract from category only relation id (category id, or let's say category title, depend on join column options)
|
||||
const relatedEntityRelationIdMap = relation.getRelationIdMap(relatedEntity);
|
||||
|
||||
console.log("relatedEntityRelationIdMap", relatedEntityRelationIdMap);
|
||||
const relatedEntityRelationIdMap = relation.inverseEntityMetadata!.getEntityIdMap(relatedEntity);
|
||||
|
||||
// try to find a subject of this related entity, maybe it was loaded or was marked for persistence
|
||||
const relatedEntitySubject = this.subjects.find(subject => {
|
||||
@ -131,10 +129,10 @@ export class ManyToManySubjectBuilder {
|
||||
// if related entity does not have a subject then it means user tries to bind entity which wasn't saved
|
||||
// in this persistence because he didn't pass this entity for save or he did not set cascades
|
||||
// but without entity being inserted we cannot bind it in the relation operation, so we throw an exception here
|
||||
if (!relatedEntitySubject || true === true)
|
||||
throw new Error(`Many-to-many relation ${relation.entityMetadata.name}.${relation.propertyPath} contains ` +
|
||||
if (!relatedEntitySubject)
|
||||
throw new Error(`Many-to-many relation "${relation.entityMetadata.name}.${relation.propertyPath}" contains ` +
|
||||
`entities which do not exist in the database yet, thus they cannot be bind in the database. ` +
|
||||
`Please setup cascade insertion or save entity before binding it.`);
|
||||
`Please setup cascade insertion or save entities before binding it.`);
|
||||
}
|
||||
|
||||
// try to find related entity in the database
|
||||
@ -147,8 +145,8 @@ export class ManyToManySubjectBuilder {
|
||||
if (relatedEntityExistInDatabase)
|
||||
return;
|
||||
|
||||
const ownerEntityMap = relation.isOwning ? subject.entity! : relatedEntity; // by example: ownerEntityMap is post from subject here
|
||||
const inverseEntityMap = relation.isOwning ? relatedEntity : subject.entity!; // by example: inverseEntityMap is category from categories array here
|
||||
const ownerValue = relation.isOwning ? subject : (relatedEntitySubject || relatedEntity); // by example: ownerEntityMap is post from subject here
|
||||
const inverseValue = relation.isOwning ? (relatedEntitySubject || relatedEntity) : subject; // by example: inverseEntityMap is category from categories array here
|
||||
|
||||
// create a new subject for insert operation of junction rows
|
||||
const junctionSubject = new Subject(relation.junctionEntityMetadata!);
|
||||
@ -158,21 +156,23 @@ export class ManyToManySubjectBuilder {
|
||||
relation.junctionEntityMetadata!.ownerColumns.forEach(column => {
|
||||
junctionSubject.changeMaps.push({
|
||||
column: column,
|
||||
value: column.referencedColumn!.getEntityValue(ownerEntityMap),
|
||||
value: ownerValue,
|
||||
// valueFactory: (value) => column.referencedColumn!.getEntityValue(value) // column.referencedColumn!.getEntityValue(ownerEntityMap),
|
||||
});
|
||||
});
|
||||
|
||||
relation.junctionEntityMetadata!.inverseColumns.forEach(column => {
|
||||
junctionSubject.changeMaps.push({
|
||||
column: column,
|
||||
value: column.referencedColumn!.getEntityValue(inverseEntityMap),
|
||||
value: inverseValue,
|
||||
// valueFactory: (value) => column.referencedColumn!.getEntityValue(value) // column.referencedColumn!.getEntityValue(inverseEntityMap),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// get all inverse entities relation ids that are "bind" to the currently persisted entity
|
||||
const changedInverseEntityRelationIds = relatedEntities
|
||||
.map(relatedEntity => relation.getRelationIdMap(relatedEntity))
|
||||
.map(relatedEntity => relation.inverseEntityMetadata!.getEntityIdMap(relatedEntity))
|
||||
.filter(relatedEntityRelationIdMap => relatedEntityRelationIdMap !== undefined && relatedEntityRelationIdMap !== null);
|
||||
|
||||
// now from all entities in the persisted entity find only those which aren't found in the db
|
||||
|
||||
@ -76,7 +76,7 @@ export class OneToManySubjectBuilder {
|
||||
// by example: extract from categories only relation ids (category id, or let's say category title, depend on join column options)
|
||||
const relatedPersistedEntityRelationIds: ObjectLiteral[] = [];
|
||||
relatedEntities.forEach(relatedEntity => { // by example: relatedEntity is a category here
|
||||
const relationIdMap = relation.getRelationIdMap(relatedEntity); // by example: relationIdMap is category.id map here, e.g. { id: ... }
|
||||
const relationIdMap = relation.inverseEntityMetadata!.getEntityIdMap(relatedEntity); // by example: relationIdMap is category.id map here, e.g. { id: ... }
|
||||
|
||||
// try to find a subject of this related entity, maybe it was loaded or was marked for persistence
|
||||
let relatedEntitySubject = this.subjects.find(subject => {
|
||||
@ -93,9 +93,9 @@ export class OneToManySubjectBuilder {
|
||||
// in this persistence because he didn't pass this entity for save or he did not set cascades
|
||||
// but without entity being inserted we cannot bind it in the relation operation, so we throw an exception here
|
||||
if (!relatedEntitySubject)
|
||||
throw new Error(`One-to-many relation ${relation.entityMetadata.name}.${relation.propertyPath} contains ` +
|
||||
throw new Error(`One-to-many relation "${relation.entityMetadata.name}.${relation.propertyPath}" contains ` +
|
||||
`entities which do not exist in the database yet, thus they cannot be bind in the database. ` +
|
||||
`Please setup cascade insertion or save entity before binding it.`);
|
||||
`Please setup cascade insertion or save entities before binding it.`);
|
||||
|
||||
// okay, so related subject exist and its marked for insertion, then add a new change map
|
||||
// by example: this will tell category to insert into its post relation our post we are working with
|
||||
|
||||
@ -94,7 +94,7 @@ export class OneToOneInverseSideSubjectBuilder {
|
||||
|
||||
// extract only relation id from the related entities, since we only need it for comparision
|
||||
// by example: extract from category only relation id (category id, or let's say category title, depend on join column options)
|
||||
const relationIdMap = relation.getRelationIdMap(relatedEntity); // by example: relationIdMap is category.id map here, e.g. { id: ... }
|
||||
const relationIdMap = relation.inverseEntityMetadata!.getEntityIdMap(relatedEntity); // by example: relationIdMap is category.id map here, e.g. { id: ... }
|
||||
|
||||
// try to find a subject of this related entity, maybe it was loaded or was marked for persistence
|
||||
let relatedEntitySubject = this.subjects.find(operateSubject => {
|
||||
@ -111,7 +111,7 @@ export class OneToOneInverseSideSubjectBuilder {
|
||||
// in this persistence because he didn't pass this entity for save or he did not set cascades
|
||||
// but without entity being inserted we cannot bind it in the relation operation, so we throw an exception here
|
||||
if (!relatedEntitySubject)
|
||||
throw new Error(`One-to-one inverse relation ${relation.entityMetadata.name}.${relation.propertyPath} contains ` +
|
||||
throw new Error(`One-to-one inverse relation "${relation.entityMetadata.name}.${relation.propertyPath}" contains ` +
|
||||
`entity which does not exist in the database yet, thus cannot be bind in the database. ` +
|
||||
`Please setup cascade insertion or save entity before binding it.`);
|
||||
|
||||
|
||||
@ -131,7 +131,12 @@ export class InsertQueryBuilder<Entity> extends QueryBuilder<Entity> {
|
||||
values = valueSets.map((valueSet, insertionIndex) => {
|
||||
const columnValues = columns.map(column => {
|
||||
const paramName = "_inserted_" + insertionIndex + "_" + column.databaseName;
|
||||
const value = this.connection.driver.preparePersistentValue(column.getEntityValue(valueSet), column);
|
||||
|
||||
let value = column.getEntityValue(valueSet);
|
||||
if (column.referencedColumn && value instanceof Object) {
|
||||
value = column.referencedColumn.getEntityValue(value);
|
||||
}
|
||||
value = this.connection.driver.preparePersistentValue(value, column);
|
||||
|
||||
if (value instanceof Function) { // support for SQL expressions in update query
|
||||
return value();
|
||||
|
||||
@ -563,7 +563,14 @@ export abstract class QueryBuilder<Entity> {
|
||||
protected createReturningExpression(): string {
|
||||
const columns = this.getReturningColumns();
|
||||
if (columns.length) {
|
||||
return columns.map(column => "INSERTED." + this.escape(column.databaseName)).join(", ");
|
||||
return columns.map(column => {
|
||||
const name = this.escape(column.databaseName);
|
||||
if (this.connection.driver instanceof SqlServerDriver) {
|
||||
return "INSERTED." + name;
|
||||
} else {
|
||||
return name;
|
||||
}
|
||||
}).join(", ");
|
||||
|
||||
} else if (typeof this.expressionMap.returning === "string") {
|
||||
return this.expressionMap.returning;
|
||||
|
||||
@ -147,11 +147,17 @@ export class UpdateQueryBuilder<Entity> extends QueryBuilder<Entity> implements
|
||||
// todo: make this and other query builder to work with properly with tables without metadata
|
||||
const column = metadata.findColumnWithPropertyPath(propertyPath);
|
||||
|
||||
// we update an entity and entity can contain property which aren't columns, so we just skip them
|
||||
// we update an entity and entity can contain properties which aren't columns, so we just skip them
|
||||
if (!column) return;
|
||||
|
||||
const paramName = "_updated_" + column.databaseName;
|
||||
const value = this.connection.driver.preparePersistentValue(column.getEntityValue(valuesSet), column);
|
||||
|
||||
//
|
||||
let value = column.getEntityValue(valuesSet);
|
||||
if (column.referencedColumn && value instanceof Object) {
|
||||
value = column.referencedColumn.getEntityValue(value);
|
||||
}
|
||||
value = this.connection.driver.preparePersistentValue(value, column);
|
||||
|
||||
// todo: duplication zone
|
||||
if (value instanceof Function) { // support for SQL expressions in update query
|
||||
|
||||
@ -60,11 +60,19 @@ export class OrmUtils {
|
||||
|
||||
if (this.isObject(target) && this.isObject(source)) {
|
||||
for (const key in source) {
|
||||
if (this.isObject(source[key])) {
|
||||
let propertyKey = key;
|
||||
if (source[key] instanceof Promise)
|
||||
continue;
|
||||
|
||||
// if (source[key] instanceof Promise) {
|
||||
// propertyKey = "__" + key + "__";
|
||||
// }
|
||||
|
||||
if (this.isObject(source[propertyKey]) && !(source[propertyKey] instanceof Date)) {
|
||||
if (!target[key]) Object.assign(target, { [key]: {} });
|
||||
this.mergeDeep(target[key], source[key]);
|
||||
this.mergeDeep(target[key], source[propertyKey]);
|
||||
} else {
|
||||
Object.assign(target, { [key]: source[key] });
|
||||
Object.assign(target, { [key]: source[propertyKey] });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,8 @@ import {closeTestingConnections, createTestingConnections, reloadTestingDatabase
|
||||
import {Connection} from "../../../src/connection/Connection";
|
||||
import {Student} from "./entity/Student";
|
||||
|
||||
describe("github issues > #144 Class Table Inheritance doesn't seem to work", () => {
|
||||
// todo fix this test once class table inheritance support is back
|
||||
describe.skip("github issues > #144 Class Table Inheritance doesn't seem to work", () => {
|
||||
|
||||
let connections: Connection[];
|
||||
before(async () => connections = await createTestingConnections({
|
||||
|
||||
@ -3,7 +3,8 @@ import {createTestingConnections, closeTestingConnections, reloadTestingDatabase
|
||||
import {Connection} from "../../../src/connection/Connection";
|
||||
import {Category} from "./entity/Category";
|
||||
|
||||
describe("github issues > #904 Using closure tables without @TreeLevelColumn will always fail on insert", () => {
|
||||
// todo: uncomment test once closure tables functionality is back
|
||||
describe.skip("github issues > #904 Using closure tables without @TreeLevelColumn will always fail on insert", () => {
|
||||
|
||||
let connections: Connection[];
|
||||
before(async () => connections = await createTestingConnections({
|
||||
|
||||
@ -48,7 +48,7 @@ describe("many-to-many", function() {
|
||||
// Specifications
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
describe.only("insert post and details (has inverse relation + full cascade options)", function() {
|
||||
describe("insert post and details (has inverse relation + full cascade options)", function() {
|
||||
let newPost: Post, details: PostDetails, savedPost: Post;
|
||||
|
||||
before(reloadDatabase);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user