UNPKG

quaerateum

Version:

Simple typescript ORM for node.js based on data-mapper, unit-of-work and identity-map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JS.

102 lines (79 loc) 3.73 kB
import { Collection } from './Collection'; import { SCALAR_TYPES } from './EntityFactory'; import { EntityManager } from '../EntityManager'; import { EntityData, EntityProperty, IEntity, IEntityType } from '../decorators'; import { Utils } from '../utils'; import { MetadataStorage } from '../metadata'; import { ReferenceType } from './enums'; export class EntityAssigner { static assign<T extends IEntityType<T>>(entity: T, data: EntityData<T>, options?: AssignOptions): void; static assign<T extends IEntityType<T>>(entity: T, data: EntityData<T>, onlyProperties?: boolean): void; static assign<T extends IEntityType<T>>(entity: T, data: EntityData<T>, onlyProperties: AssignOptions | boolean = false): void { const meta = MetadataStorage.getMetadata(entity.constructor.name); const props = meta.properties; const options = (typeof onlyProperties === 'boolean' ? { onlyProperties } : onlyProperties); Object.keys(data).forEach(prop => { if (options.onlyProperties && !(prop in props)) { return; } const value = data[prop as keyof EntityData<T>]; if (props[prop] && [ReferenceType.MANY_TO_ONE, ReferenceType.ONE_TO_ONE].includes(props[prop].reference) && value) { return EntityAssigner.assignReference<T>(entity, value, props[prop], entity.__em); } if (props[prop] && Utils.isCollection(entity[prop as keyof T], props[prop]) && Array.isArray(value)) { return EntityAssigner.assignCollection<T>(entity, entity[prop as keyof T], value, props[prop], entity.__em); } if (props[prop] && props[prop].reference === ReferenceType.SCALAR && SCALAR_TYPES.includes(props[prop].type)) { return entity[prop as keyof T] = entity.__em.getValidator().validateProperty(props[prop], value, entity); } if (options.mergeObjects && Utils.isObject(value)) { Utils.merge(entity[prop as keyof T], value); } else { entity[prop as keyof T] = value; } }); } private static assignReference<T extends IEntityType<T>>(entity: T, value: any, prop: EntityProperty, em: EntityManager): void { if (Utils.isEntity(value)) { entity[prop.name as keyof T] = value as T[keyof T]; return; } if (Utils.isPrimaryKey(value)) { entity[prop.name as keyof T] = em.getReference(prop.type, value); return; } if (Utils.isObject(value)) { entity[prop.name as keyof T] = em.create(prop.type, value) as T[keyof T]; return; } const name = entity.constructor.name; throw new Error(`Invalid reference value provided for '${name}.${prop.name}' in ${name}.assign(): ${JSON.stringify(value)}`); } private static assignCollection<T extends IEntityType<T>>(entity: T, collection: Collection<IEntity>, value: any[], prop: EntityProperty, em: EntityManager): void { const invalid: any[] = []; const items = value.map((item: any) => this.createCollectionItem(item, em, prop, invalid)); if (invalid.length > 0) { const name = entity.constructor.name; throw new Error(`Invalid collection values provided for '${name}.${prop.name}' in ${name}.assign(): ${JSON.stringify(invalid)}`); } collection.set(items, true); collection.setDirty(); } private static createCollectionItem(item: any, em: EntityManager, prop: EntityProperty, invalid: any[]): IEntity { if (Utils.isEntity(item)) { return item; } if (Utils.isPrimaryKey(item)) { return em.getReference(prop.type, item); } if (Utils.isObject(item)) { return em.create(prop.type, item); } invalid.push(item); return item; } } export interface AssignOptions { onlyProperties?: boolean; mergeObjects?: boolean; }