Skip to content
Closed
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: 1 addition & 1 deletion src/models/json-api.model.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ describe('JsonApiModel', () => {
author.books.forEach((book: Book, index: number) => {
expect(book.author).toBeDefined();
expect(book.author).toEqual(author);
expect(book.author.books[index]).toEqual(author.books[index]);
expect(book.author!.books[index]).toEqual(author.books[index]);
});

});
Expand Down
27 changes: 23 additions & 4 deletions src/services/json-api-datastore.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@ describe('JsonApiDatastore', () => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.url).not.toEqual(`${BASE_URL}/${API_VERSION}`);
expect(c.request.url).toEqual(`${BASE_URL}/${API_VERSION}/` + 'authors?' +
encodeURIComponent('page[size]') + '=10&' +
encodeURIComponent('page[number]') + '=1&' +
encodeURIComponent('include') + '=comments&' +
encodeURIComponent('filter[title][keyword]') + '=Tolkien');
encodeURIComponent('page[size]') + '=10&' +
encodeURIComponent('page[number]') + '=1&' +
encodeURIComponent('include') + '=comments&' +
encodeURIComponent('filter[title][keyword]') + '=Tolkien');
expect(c.request.method).toEqual(RequestMethod.Get);
});
datastore.query(Author, {
Expand Down Expand Up @@ -459,5 +459,24 @@ describe('JsonApiDatastore', () => {
author.date_of_birth = parse('1965-07-31');
author.save().subscribe();
});

it('should remove the relationship', () => {
backend.connections.subscribe((c: MockConnection) => {
const obj = c.request.json().data;
expect(obj.relationships.author.data).toBeNull();
});

const book = datastore.createRecord(Book, {
title: BOOK_TITLE
});
book.author = new Author(datastore, {
id: AUTHOR_ID
});

book.author = null;

book.save().subscribe();

});
});
});
41 changes: 30 additions & 11 deletions src/services/json-api-datastore.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@ 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; };
export type ModelType<T extends JsonApiModel> = { new(datastore: JsonApiDatastore, data: any): T; [key: string]: any };

@Injectable()
export class JsonApiDatastore {
// tslint:disable-next-line:variable-name
private _headers: Headers;
// tslint:disable-next-line:variable-name
private _store: {[type: string]: {[id: string]: JsonApiModel}} = {};
private toQueryString: Function = this.datastoreConfig.overrides
&& this.datastoreConfig.overrides.toQueryString ?
private toQueryString: Function = this.datastoreConfig.overrides
&& this.datastoreConfig.overrides.toQueryString ?
this.datastoreConfig.overrides.toQueryString : this._toQueryString;
// tslint:enable:max-line-length

Expand Down Expand Up @@ -199,14 +199,15 @@ export class JsonApiDatastore {
return queryParams ? `${url}?${queryParams}` : url;
}

protected getRelationships(data: any): any {
protected getRelationships<T extends JsonApiModel>(model: T): any {
let relationships: any;
const data = <any>model;

for (const key in data) {
if (data.hasOwnProperty(key)) {
if (data[key] instanceof JsonApiModel) {
relationships = relationships || {};

if (data[key].id) {
relationships[key] = {
data: this.buildSingleRelationshipData(data[key])
Expand All @@ -226,9 +227,24 @@ export class JsonApiDatastore {
}
}

this.relationsToBeDeleted(model).forEach((toDelete) => {
relationships = relationships || {};
relationships[toDelete] = { data: null };
});

return relationships;
}

private relationsToBeDeleted<T extends JsonApiModel>(model: T | {[key: string]: any}) {
const belongsToMetadata: [{propertyName: string, relationship: string}] = Reflect.getMetadata('BelongsTo', model);
if (belongsToMetadata == null) {
return [];
}
return belongsToMetadata.filter((entity) => model.hasOwnProperty(entity.propertyName))
.filter((entity) => model[entity.propertyName] === null)
.map((entity) => entity.relationship);
}

protected isValidToManyRelation(objects: Array<any>): boolean {
const isJsonApiModel = objects.every((item) => item instanceof JsonApiModel);
const relationshipType: string = isJsonApiModel ? objects[0].modelConfig.type : '';
Expand All @@ -238,18 +254,19 @@ export class JsonApiDatastore {

protected buildSingleRelationshipData(model: JsonApiModel): any {
const relationshipType: string = model.modelConfig.type;
const relationShipData: { type: string, id?: string, attributes?: any } = { type: relationshipType };
const relationshipData: { type: string, id?: string, attributes?: any } = { type: relationshipType };

if (model.id) {
relationShipData.id = model.id;
relationshipData.id = model.id;
} else {
const attributesMetadata: any = Reflect.getMetadata('Attribute', model);
relationShipData.attributes = this.getDirtyAttributes(attributesMetadata, model);
relationshipData.attributes = this.getDirtyAttributes(attributesMetadata, model);
}

return relationShipData;
return relationshipData;
}


protected extractQueryData<T extends JsonApiModel>(
res: any,
modelType: ModelType<T>,
Expand Down Expand Up @@ -398,7 +415,7 @@ export class JsonApiDatastore {

if (propertyHasMany) {
relationshipModel[propertyHasMany.propertyName] = relationshipModel[propertyHasMany.propertyName] || [];

const indexOfModel = relationshipModel[propertyHasMany.propertyName].indexOf(model);

if (indexOfModel === -1) {
Expand All @@ -421,7 +438,7 @@ export class JsonApiDatastore {
protected transformSerializedNamesToPropertyNames<T extends JsonApiModel>(modelType: ModelType<T>, attributes: any) {
const serializedNameToPropertyName = this.getModelPropertyNames(modelType.prototype);
const properties: any = {};

Object.keys(serializedNameToPropertyName).forEach((serializedName) => {
if (attributes[serializedName] !== null && attributes[serializedName] !== undefined) {
properties[serializedNameToPropertyName[serializedName]] = attributes[serializedName];
Expand All @@ -434,4 +451,6 @@ export class JsonApiDatastore {
protected getModelPropertyNames(model: JsonApiModel) {
return Reflect.getMetadata('AttributeMapping', model);
}


}
3 changes: 1 addition & 2 deletions test/models/book.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,5 @@ export class Book extends JsonApiModel {
@BelongsTo()
firstChapter: Chapter;

@BelongsTo()
author: Author;
@BelongsTo() author: Author | null;
}