@graphity/mapper
Version:
Decorator-based transformer of plain object to class constructors for Javascript(& Typescript).
90 lines (81 loc) • 3.07 kB
text/typescript
import { MapperOptions, ValueTransformer } from '../interfaces/mapper'
import { MaybeArray } from '../interfaces/utils'
function applyTransformTo(value: any, transformers: ValueTransformer<any>[]) {
const dupTransformers = transformers.slice()
let result = value
while (dupTransformers.length) {
const transformer = dupTransformers.shift()
if (transformer && transformer.to) {
result = transformer.to(result)
}
}
return result
}
function applyTransformFrom(value: any, transformers: ValueTransformer<any>[]) {
const dupTransformers = transformers.slice().reverse()
let result = value
while (dupTransformers.length) {
const transformer = dupTransformers.shift()
if (transformer && transformer.from) {
result = transformer.from(result)
}
}
return result
}
export class Mapper<TEntity, TSource = any> {
public constructor(public readonly options: MapperOptions<TEntity>) {
}
public toEntity(rows: TSource[]): TEntity[]
public toEntity(rows: TSource): TEntity
public toEntity(rows: MaybeArray<TSource>): MaybeArray<TEntity> {
if (!Array.isArray(rows)) {
return this.toEntity([rows])[0]
}
return rows.map((row: any) => {
const entity: Partial<TEntity> = {}
for (const column of this.options.columns) {
const defaultValue = typeof column.default === 'function' ? column.default() : column.default
const value = typeof row[column.sourceKey] !== 'undefined'
? applyTransformTo(row[column.sourceKey], column.transformers)
: defaultValue
const isNull = value === null || typeof value === 'undefined'
if (!column.nullable && isNull) {
throw new Error(`column(${column.property}) is not nullable.`)
}
if (column.nullable) {
entity[column.property] = !isNull ? value : null
} else {
entity[column.property] = value
}
}
Object.setPrototypeOf(entity, this.options.ctor.prototype)
return entity as TEntity
})
}
public assign(entity: Partial<TEntity>[]): TEntity[]
public assign(entity: Partial<TEntity>): TEntity
public assign(entity: MaybeArray<Partial<TEntity>>): MaybeArray<TEntity> {
if (!Array.isArray(entity)) {
return Object.setPrototypeOf(entity, this.options.ctor.prototype)
}
return entity.map((row) => this.assign(row))
}
public toPlain(entities: TEntity[]): TSource[]
public toPlain(entities: TEntity): TSource
public toPlain(entities: Partial<TEntity>[]): TSource[]
public toPlain(entities: Partial<TEntity>): TSource
public toPlain(entities: any): MaybeArray<TSource> {
if (!Array.isArray(entities)) {
return this.toPlain([entities] as TEntity[])[0]
}
return entities.map((entity) => {
const row: any = {}
for (const column of this.options.columns) {
if (typeof entity[column.property] !== 'undefined') {
row[column.sourceKey] = applyTransformFrom(entity[column.property], column.transformers)
}
}
return row
})
}
}