UNPKG

2.6 kBPlain TextView Raw
1
2import {IModelMapper, IModel} from "./Types";
3import {TypeStoreAttrKey, TypeStoreModelKey} from "./Constants";
4import {IModelAttributeOptions, IModelOptions} from "./decorations/ModelDecorations";
5
6const JSONFormattingSpace = (process.env.NODE_ENV !== 'production') ? 4 : 0
7
8export class ModelMapper<M extends IModel> implements IModelMapper<M> {
9
10
11 private modelAttrs:IModelAttributeOptions[]
12 private modelOpts:IModelOptions
13
14 constructor(private modelClazz:{new():M}) {
15 this.modelOpts = Reflect.getMetadata(TypeStoreModelKey,this.modelClazz)
16 this.modelAttrs = Reflect.getMetadata(TypeStoreAttrKey,this.modelClazz)
17 }
18
19 private attr(key:string) {
20 for (let it of this.modelAttrs) {
21 if (it.name === key) {
22 return it
23 }
24 }
25
26 return null
27 }
28
29 private attrTransient(key:string) {
30 const attr = this.attr(key)
31 return (
32 this.modelOpts &&
33 this.modelOpts.transientAttrs &&
34 this.modelOpts.transientAttrs.includes(key)
35 ) || (
36 attr && attr.transient === true
37 )
38 }
39
40 private attrPersists(key:string) {
41 return !this.attrTransient(key) && (this.modelOpts.onlyMapDefinedAttributes !== true || this.attr(key))
42 }
43
44 toJson(o:M):string {
45 return JSON.stringify(o,(key,value) => {
46 return (this.attrPersists(key)) ? value : undefined
47 },JSONFormattingSpace)
48 }
49
50 toObject(o:M):Object {
51 const obj = {}
52 const keys = Object.keys(o)
53
54 // Make sure key list is complete in case
55 // of definited props
56 for (let modelAttr of this.modelAttrs) {
57 const included = keys.includes(modelAttr.name)
58 if (modelAttr.transient && included)
59 keys.splice(keys.indexOf(modelAttr.name),1)
60 else if (!included)
61 keys.push(modelAttr.name)
62 }
63 for (let key of keys) {
64 if (this.attrPersists(key))
65 obj[key] = o[key]
66 }
67
68
69 return obj
70 }
71
72
73 fromJson(json:string,decorator = null):M {
74 const jsonObj = JSON.parse(json,(key,value) => {
75 return (!this.attrPersists(key)) ? undefined : value
76 })
77
78 const o = new this.modelClazz()
79 Object.assign(o,jsonObj)
80 if (decorator)
81 return decorator(jsonObj,o)
82
83 return o
84 }
85
86 fromObject(obj:Object,decorator = null):M {
87 const o = new this.modelClazz()
88 for (let key of Object.keys(obj)) {
89 if (this.attrPersists(key))
90 o[key] = obj[key]
91 }
92
93 if (decorator)
94 return decorator(obj,o)
95
96 return o
97 }
98}
99
100const mapperCache = new WeakMap<any,IModelMapper<IModel>>()
101
102export function getDefaultMapper<T extends IModel>(clazz:{new():T}):IModelMapper<T> {
103 let mapper = mapperCache.get(clazz) as IModelMapper<T>
104
105 if (!mapper) {
106 mapper = new ModelMapper(clazz)
107 mapperCache.set(clazz,(mapper))
108 }
109
110 return mapper
111
112}
\No newline at end of file