From 7234b62ccc3a7fb02387d06dbe34f9f5a6e9ef67 Mon Sep 17 00:00:00 2001 From: Clemens John Date: Thu, 20 Oct 2016 15:24:15 +0200 Subject: [PATCH 1/7] Add support for more generic JsonApi document including links, data and meta attributes. Therefore refactor query and findRecord methods to return an instance of DocumentModel. Signed-off-by: Clemens John --- src/index.ts | 4 ++- src/models/document.model.ts | 22 +++++++++++++++ src/models/json-api.model.ts | 22 +++++++++++++-- src/models/link.model.ts | 21 ++++++++++++++ src/models/links.model.ts | 25 +++++++++++++++++ src/services/json-api-datastore.service.ts | 32 +++++++++++++++------- 6 files changed, 113 insertions(+), 13 deletions(-) create mode 100644 src/models/document.model.ts create mode 100644 src/models/link.model.ts create mode 100644 src/models/links.model.ts diff --git a/src/index.ts b/src/index.ts index 6457848e..b5c9184d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,8 +5,10 @@ export * from './decorators/json-api-model-config.decorator'; export * from './decorators/json-api-datastore-config.decorator'; export * from './models/json-api.model'; +export * from './models/document.model'; +export * from './models/links.model'; +export * from './models/link.model'; export * from './providers'; export * from './module'; - diff --git a/src/models/document.model.ts b/src/models/document.model.ts new file mode 100644 index 00000000..8331813f --- /dev/null +++ b/src/models/document.model.ts @@ -0,0 +1,22 @@ +import { LinksModel } from './links.model'; + +export class DocumentModel { + _links: LinksModel = new LinksModel; + _data: T; + + constructor(body: any) { + this._links.updateLinks(body.links); + } + + public links(name: string = null) { + return this._links.links(name); + } + + public data(): T { + return this._data; + } + + public setData(data: any) { + this._data = data; + } +} diff --git a/src/models/json-api.model.ts b/src/models/json-api.model.ts index 38b2da8d..ed17926a 100644 --- a/src/models/json-api.model.ts +++ b/src/models/json-api.model.ts @@ -3,17 +3,35 @@ import 'reflect-metadata'; import { Headers } from '@angular/http'; import { Observable } from 'rxjs/Observable'; import { JsonApiDatastore, ModelType } from '../services/json-api-datastore.service'; +import { DocumentModel } from './document.model'; +import { LinksModel } from './links.model'; +import { LinkModel } from './link.model'; export class JsonApiModel { id: string; + _links: LinksModel = new LinksModel; + _document: DocumentModel; [key: string]: any; - constructor(private _datastore: JsonApiDatastore, data?: any) { + constructor(private _datastore: JsonApiDatastore, data?: any, document: DocumentModel = null) { if (data) { this.id = data.id; _.extend(this, data.attributes); } + + if(document) { + this._document = document; + } + this._links.updateLinks(data.links); + } + + public document(): DocumentModel { + return this._document; + } + + public links(name: string = null) { + return this._links.links(name); } syncRelationships(data: any, included: any, level: number): void { @@ -133,7 +151,7 @@ export class JsonApiModel { if (peek) { return peek; } - let newObject: T = new modelType(this._datastore, data); + let newObject: T = new modelType(this._datastore, data, null); this._datastore.addToStore(newObject); return newObject; } diff --git a/src/models/link.model.ts b/src/models/link.model.ts new file mode 100644 index 00000000..77c81a26 --- /dev/null +++ b/src/models/link.model.ts @@ -0,0 +1,21 @@ +export class LinkModel { + private _href: string; + private _name: string; + //TODO: add meta + + constructor(name: string, link: any) { + this._name = name; + } + + name() { + return this._name; + } + + href() { + return this._href; + } + +/* meta() { + return this._meta; + }*/ +} diff --git a/src/models/links.model.ts b/src/models/links.model.ts new file mode 100644 index 00000000..13a6f441 --- /dev/null +++ b/src/models/links.model.ts @@ -0,0 +1,25 @@ +import { LinkModel } from './link.model'; + +export class LinksModel { + [key: string]: any; + + public updateLinks(links: any) { + //delete all properties of this object + Object.keys(this || {}).forEach((name) => { + console.log(name); + delete this[name]; + }); + + //assign new properties based on whats inside of links + Object.keys(links || {}).forEach((name) => { + this[name] = new LinkModel(name, links[name]); + }); + } + + public links(name: string = null) { + if(name) { + return this[name]; + } + return this; + } +} diff --git a/src/services/json-api-datastore.service.ts b/src/services/json-api-datastore.service.ts index cd664923..c7868793 100644 --- a/src/services/json-api-datastore.service.ts +++ b/src/services/json-api-datastore.service.ts @@ -7,8 +7,16 @@ import 'rxjs/add/operator/map'; import 'rxjs/add/operator/catch'; import 'rxjs/add/observable/throw'; import { JsonApiModel } from '../models/json-api.model'; +import { DocumentModel } from '../models/document.model'; -export type ModelType = { new(datastore: JsonApiDatastore, data: any): T; }; + +export type ModelType = { + new( + datastore: JsonApiDatastore, + data: any, + document: DocumentModel + ): T; +}; @Injectable() export class JsonApiDatastore { @@ -19,7 +27,7 @@ export class JsonApiDatastore { constructor(private http: Http) { } - query(modelType: ModelType, params?: any, headers?: Headers): Observable { + query(modelType: ModelType, params?: any, headers?: Headers): Observable> { let options: RequestOptions = this.getOptions(headers); let url: string = this.buildUrl(modelType, params); return this.http.get(url, options) @@ -27,7 +35,7 @@ export class JsonApiDatastore { .catch((res: any) => this.handleError(res)); } - findRecord(modelType: ModelType, id: string, params?: any, headers?: Headers): Observable { + findRecord(modelType: ModelType, id: string, params?: any, headers?: Headers): Observable> { let options: RequestOptions = this.getOptions(headers); let url: string = this.buildUrl(modelType, params, id); return this.http.get(url, options) @@ -36,7 +44,7 @@ export class JsonApiDatastore { } createRecord(modelType: ModelType, data?: any): T { - return new modelType(this, {attributes: data}); + return new modelType(this, {attributes: data}, null); } saveRecord(attributesMetadata: any, model?: T, params?: any, headers?: Headers): Observable { @@ -122,11 +130,12 @@ export class JsonApiDatastore { return relationships; } - private extractQueryData(res: any, modelType: ModelType): T[] { + private extractQueryData(res: any, modelType: ModelType): DocumentModel { let body: any = res.json(); let models: T[] = []; + let document: DocumentModel = new DocumentModel(body); body.data.forEach((data: any) => { - let model: T = new modelType(this, data); + let model: T = new modelType(this, data, document); this.addToStore(model); if (body.included) { model.syncRelationships(data, body.included, 0); @@ -134,22 +143,25 @@ export class JsonApiDatastore { } models.push(model); }); - return models; + document.setData(models); + return document; } - private extractRecordData(res: any, modelType: ModelType, model?: T): T { + private extractRecordData(res: any, modelType: ModelType, model?: T): DocumentModel { let body: any = res.json(); + let document: DocumentModel = new DocumentModel(body); if (model) { model.id = body.data.id; _.extend(model, body.data.attributes); } - model = model || new modelType(this, body.data); + model = model || new modelType(this, body.data, document); this.addToStore(model); if (body.included) { model.syncRelationships(body.data, body.included, 0); this.addToStore(model); } - return model; + document.setData(model); + return document; } protected handleError(error: any): ErrorObservable { From 2f09e5915505ed3973efb92596da8b834f1a4526 Mon Sep 17 00:00:00 2001 From: Clemens John Date: Thu, 20 Oct 2016 15:34:56 +0200 Subject: [PATCH 2/7] Fix indentation Signed-off-by: Clemens John --- src/models/document.model.ts | 30 +++++++++++++++--------------- src/models/link.model.ts | 30 +++++++++++++++--------------- src/models/links.model.ts | 34 +++++++++++++++++----------------- 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/models/document.model.ts b/src/models/document.model.ts index 8331813f..8b2e1c3f 100644 --- a/src/models/document.model.ts +++ b/src/models/document.model.ts @@ -1,22 +1,22 @@ import { LinksModel } from './links.model'; export class DocumentModel { - _links: LinksModel = new LinksModel; - _data: T; + _links: LinksModel = new LinksModel; + _data: T; - constructor(body: any) { - this._links.updateLinks(body.links); - } + constructor(body: any) { + this._links.updateLinks(body.links); + } + + public links(name: string = null) { + return this._links.links(name); + } - public links(name: string = null) { - return this._links.links(name); - } + public data(): T { + return this._data; + } - public data(): T { - return this._data; - } - - public setData(data: any) { - this._data = data; - } + public setData(data: any) { + this._data = data; + } } diff --git a/src/models/link.model.ts b/src/models/link.model.ts index 77c81a26..c14683d6 100644 --- a/src/models/link.model.ts +++ b/src/models/link.model.ts @@ -1,21 +1,21 @@ export class LinkModel { - private _href: string; - private _name: string; - //TODO: add meta + private _href: string; + private _name: string; + //TODO: add meta - constructor(name: string, link: any) { - this._name = name; - } + constructor(name: string, link: any) { + this._name = name; + } - name() { - return this._name; - } + name() { + return this._name; + } - href() { - return this._href; - } + href() { + return this._href; + } -/* meta() { - return this._meta; - }*/ + /* meta() { + return this._meta; +}*/ } diff --git a/src/models/links.model.ts b/src/models/links.model.ts index 13a6f441..58161ba4 100644 --- a/src/models/links.model.ts +++ b/src/models/links.model.ts @@ -1,25 +1,25 @@ import { LinkModel } from './link.model'; export class LinksModel { - [key: string]: any; + [key: string]: any; - public updateLinks(links: any) { - //delete all properties of this object - Object.keys(this || {}).forEach((name) => { - console.log(name); - delete this[name]; - }); + public updateLinks(links: any) { + //delete all properties of this object + Object.keys(this || {}).forEach((name) => { + console.log(name); + delete this[name]; + }); - //assign new properties based on whats inside of links - Object.keys(links || {}).forEach((name) => { - this[name] = new LinkModel(name, links[name]); - }); - } + //assign new properties based on whats inside of links + Object.keys(links || {}).forEach((name) => { + this[name] = new LinkModel(name, links[name]); + }); + } - public links(name: string = null) { - if(name) { - return this[name]; - } - return this; + public links(name: string = null) { + if(name) { + return this[name]; } + return this; + } } From df244bd2c83c8dcee03b1945c1836b6ad584feee Mon Sep 17 00:00:00 2001 From: Clemens John Date: Thu, 20 Oct 2016 15:35:14 +0200 Subject: [PATCH 3/7] Remove debug output Signed-off-by: Clemens John --- src/models/links.model.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/models/links.model.ts b/src/models/links.model.ts index 58161ba4..4db041be 100644 --- a/src/models/links.model.ts +++ b/src/models/links.model.ts @@ -6,7 +6,6 @@ export class LinksModel { public updateLinks(links: any) { //delete all properties of this object Object.keys(this || {}).forEach((name) => { - console.log(name); delete this[name]; }); From 1438d35b7c2132e6e918ceefc23b0b2fe789464f Mon Sep 17 00:00:00 2001 From: Clemens John Date: Mon, 24 Oct 2016 18:27:19 +0200 Subject: [PATCH 4/7] Use typescript accessors, remove _document property from JsonApiModel and ModelType because I could not get it working with generics. The data property of DocumentModel can be T or T[] and I think ModelType needs more refactoring to return T and initialize DocumentModel and DocumentModel at the same time. Signed-off-by: Clemens John --- src/models/document.model.ts | 14 +++++++------- src/models/json-api.model.ts | 20 +++++--------------- src/models/link.model.ts | 11 ++++------- src/models/links.model.ts | 7 ------- src/services/json-api-datastore.service.ts | 17 ++++++++--------- 5 files changed, 24 insertions(+), 45 deletions(-) diff --git a/src/models/document.model.ts b/src/models/document.model.ts index 8b2e1c3f..1fe3eb80 100644 --- a/src/models/document.model.ts +++ b/src/models/document.model.ts @@ -1,22 +1,22 @@ import { LinksModel } from './links.model'; export class DocumentModel { - _links: LinksModel = new LinksModel; - _data: T; + private _links: LinksModel = new LinksModel; + private _data: T; constructor(body: any) { this._links.updateLinks(body.links); } - - public links(name: string = null) { - return this._links.links(name); + + get links() { + return this._links; } - public data(): T { + get data(): T { return this._data; } - public setData(data: any) { + set data(data: T) { this._data = data; } } diff --git a/src/models/json-api.model.ts b/src/models/json-api.model.ts index ed17926a..7c72f813 100644 --- a/src/models/json-api.model.ts +++ b/src/models/json-api.model.ts @@ -3,35 +3,25 @@ import 'reflect-metadata'; import { Headers } from '@angular/http'; import { Observable } from 'rxjs/Observable'; import { JsonApiDatastore, ModelType } from '../services/json-api-datastore.service'; -import { DocumentModel } from './document.model'; import { LinksModel } from './links.model'; import { LinkModel } from './link.model'; export class JsonApiModel { id: string; - _links: LinksModel = new LinksModel; - _document: DocumentModel; + private _links: LinksModel = new LinksModel; [key: string]: any; - constructor(private _datastore: JsonApiDatastore, data?: any, document: DocumentModel = null) { + constructor(private _datastore: JsonApiDatastore, data?: any) { if (data) { this.id = data.id; _.extend(this, data.attributes); } - - if(document) { - this._document = document; - } this._links.updateLinks(data.links); } - public document(): DocumentModel { - return this._document; - } - - public links(name: string = null) { - return this._links.links(name); + get links() { + return this._links; } syncRelationships(data: any, included: any, level: number): void { @@ -151,7 +141,7 @@ export class JsonApiModel { if (peek) { return peek; } - let newObject: T = new modelType(this._datastore, data, null); + let newObject: T = new modelType(this._datastore, data); this._datastore.addToStore(newObject); return newObject; } diff --git a/src/models/link.model.ts b/src/models/link.model.ts index c14683d6..b1eebdfb 100644 --- a/src/models/link.model.ts +++ b/src/models/link.model.ts @@ -1,21 +1,18 @@ export class LinkModel { - private _href: string; private _name: string; + private _href: string; //TODO: add meta constructor(name: string, link: any) { this._name = name; + this._href = link; } - name() { + get name(): string { return this._name; } - href() { + get href(): string { return this._href; } - - /* meta() { - return this._meta; -}*/ } diff --git a/src/models/links.model.ts b/src/models/links.model.ts index 4db041be..acc23f02 100644 --- a/src/models/links.model.ts +++ b/src/models/links.model.ts @@ -14,11 +14,4 @@ export class LinksModel { this[name] = new LinkModel(name, links[name]); }); } - - public links(name: string = null) { - if(name) { - return this[name]; - } - return this; - } } diff --git a/src/services/json-api-datastore.service.ts b/src/services/json-api-datastore.service.ts index c7868793..73eec1d6 100644 --- a/src/services/json-api-datastore.service.ts +++ b/src/services/json-api-datastore.service.ts @@ -13,8 +13,7 @@ import { DocumentModel } from '../models/document.model'; export type ModelType = { new( datastore: JsonApiDatastore, - data: any, - document: DocumentModel + data: any ): T; }; @@ -44,7 +43,7 @@ export class JsonApiDatastore { } createRecord(modelType: ModelType, data?: any): T { - return new modelType(this, {attributes: data}, null); + return new modelType(this, {attributes: data}); } saveRecord(attributesMetadata: any, model?: T, params?: any, headers?: Headers): Observable { @@ -130,12 +129,12 @@ export class JsonApiDatastore { return relationships; } - private extractQueryData(res: any, modelType: ModelType): DocumentModel { + private extractQueryData(res: any, modelType: ModelType): DocumentModel { let body: any = res.json(); let models: T[] = []; - let document: DocumentModel = new DocumentModel(body); + let document: DocumentModel = new DocumentModel(body); body.data.forEach((data: any) => { - let model: T = new modelType(this, data, document); + let model: T = new modelType(this, data); this.addToStore(model); if (body.included) { model.syncRelationships(data, body.included, 0); @@ -143,7 +142,7 @@ export class JsonApiDatastore { } models.push(model); }); - document.setData(models); + document.data = models; return document; } @@ -154,13 +153,13 @@ export class JsonApiDatastore { model.id = body.data.id; _.extend(model, body.data.attributes); } - model = model || new modelType(this, body.data, document); + model = model || new modelType(this, body.data); this.addToStore(model); if (body.included) { model.syncRelationships(body.data, body.included, 0); this.addToStore(model); } - document.setData(model); + document.data = model; return document; } From c3b7c2ddfab785b94a3aa46072619b996a8dbb4b Mon Sep 17 00:00:00 2001 From: Clemens John Date: Sun, 15 Jan 2017 20:30:24 +0100 Subject: [PATCH 5/7] Make models code style compatible Signed-off-by: Clemens John --- src/models/link.model.ts | 2 +- src/models/links.model.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/models/link.model.ts b/src/models/link.model.ts index b1eebdfb..c4b10fa0 100644 --- a/src/models/link.model.ts +++ b/src/models/link.model.ts @@ -1,7 +1,7 @@ export class LinkModel { private _name: string; private _href: string; - //TODO: add meta + // TODO: add meta constructor(name: string, link: any) { this._name = name; diff --git a/src/models/links.model.ts b/src/models/links.model.ts index acc23f02..e48d0f73 100644 --- a/src/models/links.model.ts +++ b/src/models/links.model.ts @@ -4,12 +4,12 @@ export class LinksModel { [key: string]: any; public updateLinks(links: any) { - //delete all properties of this object + // delete all properties of this object Object.keys(this || {}).forEach((name) => { delete this[name]; }); - //assign new properties based on whats inside of links + // assign new properties based on whats inside of links Object.keys(links || {}).forEach((name) => { this[name] = new LinkModel(name, links[name]); }); From 1401814db3cf61dd4efc9c45196c7ef7bb4a0003 Mon Sep 17 00:00:00 2001 From: Clemens John Date: Sun, 15 Jan 2017 20:31:56 +0100 Subject: [PATCH 6/7] Make save and saveRecord return Observable> Signed-off-by: Clemens John --- src/models/json-api.model.ts | 3 ++- src/services/json-api-datastore.service.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/models/json-api.model.ts b/src/models/json-api.model.ts index 4c56e0d7..2e25fe00 100644 --- a/src/models/json-api.model.ts +++ b/src/models/json-api.model.ts @@ -4,6 +4,7 @@ import { Observable } from 'rxjs/Observable'; import { JsonApiDatastore, ModelType } from '../services/json-api-datastore.service'; import { LinksModel } from './links.model'; import { LinkModel } from './link.model'; +import { DocumentModel } from '../models/document.model'; export class JsonApiModel { @@ -30,7 +31,7 @@ export class JsonApiModel { } } - save(params?: any, headers?: Headers): Observable { + save(params?: any, headers?: Headers): Observable> { let attributesMetadata: any = Reflect.getMetadata('Attribute', this); return this._datastore.saveRecord(attributesMetadata, this, params, headers); } diff --git a/src/services/json-api-datastore.service.ts b/src/services/json-api-datastore.service.ts index c612c4ad..66318ced 100644 --- a/src/services/json-api-datastore.service.ts +++ b/src/services/json-api-datastore.service.ts @@ -46,7 +46,7 @@ export class JsonApiDatastore { return new modelType(this, {attributes: data}); } - saveRecord(attributesMetadata: any, model?: T, params?: any, headers?: Headers): Observable { + saveRecord(attributesMetadata: any, model?: T, params?: any, headers?: Headers): Observable> { let modelType = >model.constructor; let typeName: string = Reflect.getMetadata('JsonApiModelConfig', modelType).type; let options: RequestOptions = this.getOptions(headers); From c8c10dccef0c323e2ab0436af7fa95bd369cfcfa Mon Sep 17 00:00:00 2001 From: Clemens John Date: Sat, 28 Jan 2017 00:58:20 +0100 Subject: [PATCH 7/7] Fix the following error that occurs on 'npm install': Error: Error at /home/floh1111/angular2-jsonapi/node_modules/@types/lodash/index.d.ts:245:25: Cannot find name 'Partial'. Signed-off-by: Clemens John --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 24f55e3c..573b1e91 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "@angular/platform-browser-dynamic": "2.2.3", "@angular/platform-server": "2.2.3", "@types/jasmine": "2.5.38", - "@types/lodash": "^4.14.37", + "@types/lodash": "4.14.37", "@types/reflect-metadata": "0.0.4", "@types/selenium-webdriver": "^2.53.30", "codelyzer": "~2.0.0-beta.1",