Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/constants/symbols.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// tslint:disable-next-line:variable-name
export const AttributeMetadata = Symbol('AttributeMetadata');
34 changes: 26 additions & 8 deletions src/decorators/attribute.decorator.ts
Original file line number Diff line number Diff line change
@@ -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) {
Expand All @@ -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 () {
Expand All @@ -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,
Expand Down
10 changes: 6 additions & 4 deletions src/models/json-api.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -26,12 +27,12 @@ export class JsonApiModel {
}

save(params?: any, headers?: Headers): Observable<this> {
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)) {
Expand All @@ -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)) {
Expand All @@ -62,7 +63,8 @@ export class JsonApiModel {
}
}
}
Reflect.defineMetadata('Attribute', attributesMetadata, this);

this[AttributeMetadata] = attributesMetadata;
}

get modelConfig(): ModelConfig {
Expand Down
5 changes: 3 additions & 2 deletions src/services/json-api-datastore.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<T extends JsonApiModel> = { new(datastore: JsonApiDatastore, data: any): T; };

Expand Down Expand Up @@ -371,7 +372,7 @@ export class JsonApiDatastore {
private resetMetadataAttributes<T extends JsonApiModel>(res: T, attributesMetadata: any, modelType: ModelType<T>) {
// 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)) {
Expand All @@ -383,7 +384,7 @@ export class JsonApiDatastore {
}
}

Reflect.defineMetadata('Attribute', attributesMetadata, res);
res[AttributeMetadata] = attributesMetadata;
return res;
}

Expand Down