diff --git a/src/constants/symbols.ts b/src/constants/symbols.ts new file mode 100644 index 00000000..1d314c43 --- /dev/null +++ b/src/constants/symbols.ts @@ -0,0 +1,2 @@ +// tslint:disable-next-line:variable-name +export const AttributeMetadata = Symbol('AttributeMetadata'); diff --git a/src/decorators/attribute.decorator.ts b/src/decorators/attribute.decorator.ts index 80dc51d1..31782fa2 100644 --- a/src/decorators/attribute.decorator.ts +++ b/src/decorators/attribute.decorator.ts @@ -1,4 +1,5 @@ import { format, parse } from 'date-fns'; +import { AttributeMetadata } from '../constants/symbols'; export function Attribute(serializedName?: string) { return function (target: any, propertyName: string) { @@ -16,26 +17,43 @@ export function Attribute(serializedName?: string) { return value; }; - const saveAnnotations = function (hasDirtyAttributes: boolean, oldValue: any, newValue: any, isNew: boolean) { - const annotations = Reflect.getMetadata('Attribute', target) || {}; - const targetType = Reflect.getMetadata('design:type', target, propertyName); + const saveAnnotations = function () { + const metadata = Reflect.getMetadata('Attribute', target) || {}; + + metadata[propertyName] = { + marked: true + }; + + Reflect.defineMetadata('Attribute', metadata, target); const mappingMetadata = Reflect.getMetadata('AttributeMapping', target) || {}; const serializedPropertyName = serializedName !== undefined ? serializedName : propertyName; mappingMetadata[serializedPropertyName] = propertyName; Reflect.defineMetadata('AttributeMapping', mappingMetadata, target); + }; + + const setMetadata = function ( + hasDirtyAttributes: boolean, + instance: any, + oldValue: any, + newValue: any, + isNew: boolean + ) { + const targetType = Reflect.getMetadata('design:type', target, propertyName); + + if (!instance[AttributeMetadata]) { + instance[AttributeMetadata] = {}; + } const propertyHasDirtyAttributes = typeof oldValue === 'undefined' && !isNew ? false : hasDirtyAttributes; - annotations[propertyName] = { + instance[AttributeMetadata][propertyName] = { newValue, oldValue, serializedName, hasDirtyAttributes: propertyHasDirtyAttributes, serialisationValue: converter(targetType, newValue, true) }; - - Reflect.defineMetadata('Attribute', annotations, target); }; const getter = function () { @@ -47,13 +65,13 @@ export function Attribute(serializedName?: string) { const convertedValue = converter(targetType, newVal); if (convertedValue !== this['_' + propertyName]) { - saveAnnotations(true, this['_' + propertyName], newVal, !this.id); + setMetadata(true, this, this['_' + propertyName], newVal, !this.id); this['_' + propertyName] = convertedValue; } }; if (delete target[propertyName]) { - saveAnnotations(false, undefined, target[propertyName], target.id); + saveAnnotations(); Object.defineProperty(target, propertyName, { get: getter, set: setter, diff --git a/src/models/json-api.model.ts b/src/models/json-api.model.ts index 089db8f3..5721360a 100644 --- a/src/models/json-api.model.ts +++ b/src/models/json-api.model.ts @@ -5,6 +5,7 @@ import { Observable } from 'rxjs/Observable'; import { JsonApiDatastore, ModelType } from '../services/json-api-datastore.service'; import { ModelConfig } from '../interfaces/model-config.interface'; import * as _ from 'lodash'; +import { AttributeMetadata } from '../constants/symbols'; export class JsonApiModel { id: string; @@ -26,12 +27,12 @@ export class JsonApiModel { } save(params?: any, headers?: Headers): Observable { - const attributesMetadata: any = Reflect.getMetadata('Attribute', this); + const attributesMetadata: any = this[AttributeMetadata]; return this._datastore.saveRecord(attributesMetadata, this, params, headers); } get hasDirtyAttributes() { - const attributesMetadata: any = Reflect.getMetadata('Attribute', this); + const attributesMetadata: any = this[AttributeMetadata]; let hasDirtyAttributes = false; for (const propertyName in attributesMetadata) { if (attributesMetadata.hasOwnProperty(propertyName)) { @@ -47,7 +48,7 @@ export class JsonApiModel { } rollbackAttributes(): void { - const attributesMetadata: any = Reflect.getMetadata('Attribute', this); + const attributesMetadata: any = this[AttributeMetadata]; let metadata: any; for (const propertyName in attributesMetadata) { if (attributesMetadata.hasOwnProperty(propertyName)) { @@ -62,7 +63,8 @@ export class JsonApiModel { } } } - Reflect.defineMetadata('Attribute', attributesMetadata, this); + + this[AttributeMetadata] = attributesMetadata; } get modelConfig(): ModelConfig { diff --git a/src/services/json-api-datastore.service.ts b/src/services/json-api-datastore.service.ts index 28bbd15f..73731c85 100644 --- a/src/services/json-api-datastore.service.ts +++ b/src/services/json-api-datastore.service.ts @@ -13,6 +13,7 @@ import { JsonApiQueryData } from '../models/json-api-query-data'; import * as qs from 'qs'; import { DatastoreConfig } from '../interfaces/datastore-config.interface'; import { ModelConfig } from '../interfaces/model-config.interface'; +import { AttributeMetadata } from '../constants/symbols'; export type ModelType = { new(datastore: JsonApiDatastore, data: any): T; }; @@ -371,7 +372,7 @@ export class JsonApiDatastore { private resetMetadataAttributes(res: T, attributesMetadata: any, modelType: ModelType) { // TODO check why is attributesMetadata from the arguments never used // tslint:disable-next-line:no-param-reassign - attributesMetadata = Reflect.getMetadata('Attribute', res); + attributesMetadata = res[AttributeMetadata]; for (const propertyName in attributesMetadata) { if (attributesMetadata.hasOwnProperty(propertyName)) { @@ -383,7 +384,7 @@ export class JsonApiDatastore { } } - Reflect.defineMetadata('Attribute', attributesMetadata, res); + res[AttributeMetadata] = attributesMetadata; return res; }