|
| 1 | +import { BinaryAttribute, MapperForType, NumberAttribute, StringAttribute } from '../../../mapper' |
| 2 | +import { |
| 3 | + wrapMapperForDynamoListJsArray, |
| 4 | + wrapMapperForDynamoListJsSet, |
| 5 | + wrapMapperForDynamoSetJsArray, |
| 6 | + wrapMapperForDynamoSetJsSet, |
| 7 | +} from '../../../mapper/wrap-mapper-for-collection.function' |
| 8 | +import { ModelConstructor } from '../../../model' |
| 9 | +import { PropertyMetadata, TypeInfo } from '../../metadata' |
| 10 | +import { getMetadataType } from '../../util' |
| 11 | +import { initOrUpdateProperty } from '../property/init-or-update-property.function' |
| 12 | +import { CollectionPropertyDataBase } from './collection-property-data.model' |
| 13 | + |
| 14 | +type DecoratorFn = (target: object, propertyKey: string | symbol) => void |
| 15 | + |
| 16 | +export function CollectionProperty<R, T extends StringAttribute | NumberAttribute | BinaryAttribute>(opts: CollectionPropertyDataBase<R, T> = {}): DecoratorFn { |
| 17 | + return (target: object, propertyKey: string | symbol) => { |
| 18 | + if (typeof propertyKey === 'string') { |
| 19 | + |
| 20 | + const type: ModelConstructor<any> = getMetadataType(target, propertyKey) |
| 21 | + |
| 22 | + if (type !== Set && type !== Array) { |
| 23 | + throw new Error(`[${target.constructor.name}::${propertyKey}] The CollectionProperty decorator is meant for properties of type Set or Array`) |
| 24 | + } |
| 25 | + |
| 26 | + const meta: Partial<PropertyMetadata<any>> & { typeInfo: TypeInfo } = { |
| 27 | + name: propertyKey, |
| 28 | + nameDb: opts && opts.name || propertyKey, |
| 29 | + typeInfo: { |
| 30 | + type, |
| 31 | + isCustom: true, |
| 32 | + }, |
| 33 | + isSortedCollection: !!opts.sorted, |
| 34 | + } |
| 35 | + |
| 36 | + const hasItemType = 'itemType' in opts && !!opts.itemType |
| 37 | + const hasItemMapper = 'itemMapper' in opts && !!opts.itemMapper |
| 38 | + |
| 39 | + if (hasItemMapper && hasItemType) { |
| 40 | + throw new Error(`[${target.constructor.name}::${propertyKey}] provide either itemType or itemMapper, not both`) |
| 41 | + } |
| 42 | + |
| 43 | + if (hasItemType) { |
| 44 | + meta.typeInfo.genericType = opts.itemType |
| 45 | + } |
| 46 | + |
| 47 | + if (hasItemMapper) { |
| 48 | + const itemMapper = <MapperForType<any, any>>opts.itemMapper |
| 49 | + |
| 50 | + const wrappedMapper: MapperForType<any, any> = type === Array |
| 51 | + ? !!opts.sorted |
| 52 | + ? wrapMapperForDynamoListJsArray(itemMapper) |
| 53 | + : wrapMapperForDynamoSetJsArray(itemMapper) |
| 54 | + : !!opts.sorted |
| 55 | + ? wrapMapperForDynamoListJsSet(itemMapper) |
| 56 | + : wrapMapperForDynamoSetJsSet(itemMapper) |
| 57 | + |
| 58 | + meta.mapper = () => wrappedMapper |
| 59 | + meta.mapperForSingleItem = () => itemMapper |
| 60 | + } |
| 61 | + |
| 62 | + initOrUpdateProperty(meta, target, propertyKey) |
| 63 | + } |
| 64 | + } |
| 65 | +} |
0 commit comments