From b647bdb05741e6d8d05fbd0522c63d00e7892250 Mon Sep 17 00:00:00 2001 From: Mihael Safaric Date: Tue, 5 Jun 2018 14:23:54 +0200 Subject: [PATCH 1/9] Test the first two levels of belongsTo nesting --- src/models/json-api.model.spec.ts | 34 +++++++++++++++ test/datastore-with-config.service.ts | 4 +- test/datastore.service.ts | 4 +- test/fixtures/author.fixture.ts | 61 +++++++++++++++------------ test/fixtures/chapter.fixture.ts | 33 +++++++++++++++ test/fixtures/section.fixture.ts | 19 +++++++++ test/models/chapter.model.ts | 4 ++ test/models/section.model.ts | 16 +++++++ 8 files changed, 146 insertions(+), 29 deletions(-) create mode 100644 test/fixtures/chapter.fixture.ts create mode 100644 test/fixtures/section.fixture.ts create mode 100644 test/models/section.model.ts diff --git a/src/models/json-api.model.spec.ts b/src/models/json-api.model.spec.ts index 96ea0b83..55171ea3 100644 --- a/src/models/json-api.model.spec.ts +++ b/src/models/json-api.model.spec.ts @@ -148,5 +148,39 @@ describe('JsonApiModel', () => { }); }); }); + + describe('parseBelongsTo', () => { + it('should parse the first level of belongTo relationships', () => { + const REL = 'books'; + const BOOK_NUMBER = 2; + const CHAPTERS_NUMBER = 4; + const DATA = getAuthorData(REL, BOOK_NUMBER); + const INCLUDED = getIncludedBooks(BOOK_NUMBER, 'books.chapters,books.firstChapter', 5); + + author = new Author(datastore, DATA); + author.syncRelationships(DATA, INCLUDED, 0); + + expect(author.books[0].firstChapter).toBeDefined(); + }); + + it('should parse the second level of belongTo relationships', () => { + const REL = 'books'; + const BOOK_NUMBER = 2; + const CHAPTERS_NUMBER = 4; + const DATA = getAuthorData(REL, BOOK_NUMBER); + const INCLUDED = getIncludedBooks( + BOOK_NUMBER, + 'books.chapters,books.firstChapter,books.firstChapter.firstSection', + 5 + ); + + author = new Author(datastore, DATA); + author.syncRelationships(DATA, INCLUDED, 0); + + console.log(author.books[0].firstChapter.firstSection); + + expect(author.books[0].firstChapter.firstSection).toBeDefined(); + }); + }); }); }); diff --git a/test/datastore-with-config.service.ts b/test/datastore-with-config.service.ts index 9dcc548a..26243bd2 100644 --- a/test/datastore-with-config.service.ts +++ b/test/datastore-with-config.service.ts @@ -4,6 +4,7 @@ import { JsonApiDatastore, JsonApiDatastoreConfig, DatastoreConfig } from '../sr import { Author } from './models/author.model'; import { Book } from './models/book.model'; import { Chapter } from './models/chapter.model'; +import { Section } from './models/section.model'; const BASE_URL = 'http://localhost:8080'; const API_VERSION = 'v1'; @@ -17,7 +18,8 @@ export const API_VERSION_FROM_CONFIG = 'v2'; models: { authors: Author, books: Book, - chapters: Chapter + chapters: Chapter, + sections: Section } }) export class DatastoreWithConfig extends JsonApiDatastore { diff --git a/test/datastore.service.ts b/test/datastore.service.ts index 2ab8032b..ff40775c 100644 --- a/test/datastore.service.ts +++ b/test/datastore.service.ts @@ -4,6 +4,7 @@ import { JsonApiDatastore, JsonApiDatastoreConfig } from '../src'; import { Author } from './models/author.model'; import { Book } from './models/book.model'; import { Chapter } from './models/chapter.model'; +import { Section } from './models/section.model'; export const BASE_URL = 'http://localhost:8080'; export const API_VERSION = 'v1'; @@ -14,7 +15,8 @@ export const API_VERSION = 'v1'; models: { authors: Author, books: Book, - chapters: Chapter + chapters: Chapter, + sections: Section } }) export class Datastore extends JsonApiDatastore { diff --git a/test/fixtures/author.fixture.ts b/test/fixtures/author.fixture.ts index 58233f1c..13258c15 100644 --- a/test/fixtures/author.fixture.ts +++ b/test/fixtures/author.fixture.ts @@ -1,4 +1,6 @@ import {getSampleBook} from './book.fixture'; +import { getSampleChapter } from './chapter.fixture'; +import { getSampleSection } from './section.fixture'; export const AUTHOR_ID = '1'; export const AUTHOR_NAME = 'J. R. R. Tolkien'; @@ -56,45 +58,50 @@ export function getIncludedBooks(totalBooks: number, relationship?: string, tota for (let i = 1; i <= totalBooks; i++) { const book: any = getSampleBook(i, AUTHOR_ID); + responseArray.push(book); if (relationship && relationship.indexOf('books.chapters') !== -1) { book.relationships.chapters.data = []; for (let ic = 1; ic <= totalChapters; ic++) { chapterId++; book.relationships.chapters.data.push({ - id: '' + chapterId, + id: `${chapterId}`, type: 'chapters' }); - responseArray.push({ - id: '' + chapterId, - type: 'chapters', - attributes: { - title: CHAPTER_TITLE, - ordering: chapterId, - created_at: '2016-10-01T12:54:32Z', - updated_at: '2016-10-01T12:54:32Z' - }, - relationships: { - book: { - links: { - self: '/v1/authors/288/relationships/book', - related: '/v1/authors/288/book' - }, - data: { - id: '' + i, - type: 'books' - } - } - }, - links: { - self: '/v1/authors/288' - } - }); + const chapter = getSampleChapter(i, `${chapterId}`, CHAPTER_TITLE); + + responseArray.push(chapter); } } - responseArray.push(book); + + if (relationship && relationship.indexOf('books.firstChapter') !== -1) { + const firstChapterId = '1'; + + book.relationships.firstChapter = { + data: { + id: firstChapterId, + type: 'chapters' + } + }; + + const findFirstChapterInclude = responseArray.find((chapter) => chapter.id === firstChapterId); + + if (!findFirstChapterInclude) { + const chapter = getSampleChapter(i, `${firstChapterId}`, CHAPTER_TITLE); + responseArray.push(chapter); + } + } + + if (relationship && relationship.indexOf('books.firstChapter.firstSection') !== -1) { + const section = getSampleSection('1', '1'); + responseArray.push(section); + } } return responseArray; } + +function includeBooks() { + +} \ No newline at end of file diff --git a/test/fixtures/chapter.fixture.ts b/test/fixtures/chapter.fixture.ts new file mode 100644 index 00000000..27126ec1 --- /dev/null +++ b/test/fixtures/chapter.fixture.ts @@ -0,0 +1,33 @@ +export function getSampleChapter(i: number, chapterId: string, chapterTitle: string = 'Dummy title') { + return { + id: chapterId, + type: 'chapters', + attributes: { + title: chapterTitle, + ordering: parseInt(chapterId, 10), + created_at: '2016-10-01T12:54:32Z', + updated_at: '2016-10-01T12:54:32Z' + }, + relationships: { + book: { + links: { + self: '/v1/authors/288/relationships/book', + related: '/v1/authors/288/book' + }, + data: { + id: '' + i, + type: 'books' + } + }, + firstSection: { + data: { + id: '1', + type: 'sections' + } + } + }, + links: { + self: '/v1/authors/288' + } + }; +} diff --git a/test/fixtures/section.fixture.ts b/test/fixtures/section.fixture.ts new file mode 100644 index 00000000..63f33dd4 --- /dev/null +++ b/test/fixtures/section.fixture.ts @@ -0,0 +1,19 @@ +export function getSampleSection(sectionId: string, chapterId: string, content: string = 'Dummy content') { + return { + id: sectionId, + type: 'sections', + attributes: { + content, + created_at: '2016-10-01T12:54:32Z', + updated_at: '2016-10-01T12:54:32Z' + }, + relationships: { + chapter: { + data: { + id: chapterId, + type: 'chapters' + } + } + } + }; +} diff --git a/test/models/chapter.model.ts b/test/models/chapter.model.ts index eeff789c..e4838279 100644 --- a/test/models/chapter.model.ts +++ b/test/models/chapter.model.ts @@ -3,6 +3,7 @@ import { JsonApiModelConfig } from '../../src/decorators/json-api-model-config.d import { JsonApiModel } from '../../src/models/json-api.model'; import { Attribute } from '../../src/decorators/attribute.decorator'; import { BelongsTo } from '../../src/decorators/belongs-to.decorator'; +import { Section } from './section.model'; @JsonApiModelConfig({ type: 'chapters' @@ -23,4 +24,7 @@ export class Chapter extends JsonApiModel { @BelongsTo() book: Book; + + @BelongsTo() + firstSection: Section; } diff --git a/test/models/section.model.ts b/test/models/section.model.ts new file mode 100644 index 00000000..4aa39402 --- /dev/null +++ b/test/models/section.model.ts @@ -0,0 +1,16 @@ +import { JsonApiModelConfig } from '../../src/decorators/json-api-model-config.decorator'; +import { JsonApiModel } from '../../src/models/json-api.model'; +import { Attribute } from '../../src/decorators/attribute.decorator'; +import { BelongsTo } from '../../src/decorators/belongs-to.decorator'; +import { Chapter } from './chapter.model'; + +@JsonApiModelConfig({ + type: 'sections' +}) +export class Section extends JsonApiModel { + @Attribute() + content: string; + + @BelongsTo() + chapter: Chapter; +} From ec1f2637f694036403deaa163e3c8a899310a519 Mon Sep 17 00:00:00 2001 From: Mihael Safaric Date: Tue, 5 Jun 2018 14:37:55 +0200 Subject: [PATCH 2/9] Add specs for third level of belongsTo relationships --- src/models/json-api.model.spec.ts | 22 +++++++++++++++++++++- test/datastore-with-config.service.ts | 4 +++- test/datastore.service.ts | 4 +++- test/fixtures/author.fixture.ts | 8 +++++++- test/fixtures/paragraph.fixture.ts | 19 +++++++++++++++++++ test/fixtures/section.fixture.ts | 6 ++++++ test/models/paragraph.model.ts | 16 ++++++++++++++++ test/models/section.model.ts | 4 ++++ 8 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 test/fixtures/paragraph.fixture.ts create mode 100644 test/models/paragraph.model.ts diff --git a/src/models/json-api.model.spec.ts b/src/models/json-api.model.spec.ts index 55171ea3..055e6859 100644 --- a/src/models/json-api.model.spec.ts +++ b/src/models/json-api.model.spec.ts @@ -149,7 +149,7 @@ describe('JsonApiModel', () => { }); }); - describe('parseBelongsTo', () => { + fdescribe('parseBelongsTo', () => { it('should parse the first level of belongTo relationships', () => { const REL = 'books'; const BOOK_NUMBER = 2; @@ -181,6 +181,26 @@ describe('JsonApiModel', () => { expect(author.books[0].firstChapter.firstSection).toBeDefined(); }); + + it('should parse the third level of belongTo relationships', () => { + const REL = 'books'; + const BOOK_NUMBER = 2; + const CHAPTERS_NUMBER = 4; + const DATA = getAuthorData(REL, BOOK_NUMBER); + const INCLUDED = getIncludedBooks( + BOOK_NUMBER, + // tslint:disable-next-line:max-line-length + 'books.chapters,books.firstChapter,books.firstChapter.firstSection,books.firstChapter.firstSection.firstParagraph', + 5 + ); + + author = new Author(datastore, DATA); + author.syncRelationships(DATA, INCLUDED, 0); + + console.log(author.books[0].firstChapter.firstSection.firstParagraph); + + expect(author.books[0].firstChapter.firstSection.firstParagraph).toBeDefined(); + }); }); }); }); diff --git a/test/datastore-with-config.service.ts b/test/datastore-with-config.service.ts index 26243bd2..ad562b9b 100644 --- a/test/datastore-with-config.service.ts +++ b/test/datastore-with-config.service.ts @@ -5,6 +5,7 @@ import { Author } from './models/author.model'; import { Book } from './models/book.model'; import { Chapter } from './models/chapter.model'; import { Section } from './models/section.model'; +import { Paragraph } from './models/paragraph.model'; const BASE_URL = 'http://localhost:8080'; const API_VERSION = 'v1'; @@ -19,7 +20,8 @@ export const API_VERSION_FROM_CONFIG = 'v2'; authors: Author, books: Book, chapters: Chapter, - sections: Section + paragraphs: Paragraph, + sections: Section, } }) export class DatastoreWithConfig extends JsonApiDatastore { diff --git a/test/datastore.service.ts b/test/datastore.service.ts index ff40775c..78274c04 100644 --- a/test/datastore.service.ts +++ b/test/datastore.service.ts @@ -5,6 +5,7 @@ import { Author } from './models/author.model'; import { Book } from './models/book.model'; import { Chapter } from './models/chapter.model'; import { Section } from './models/section.model'; +import { Paragraph } from './models/paragraph.model'; export const BASE_URL = 'http://localhost:8080'; export const API_VERSION = 'v1'; @@ -16,7 +17,8 @@ export const API_VERSION = 'v1'; authors: Author, books: Book, chapters: Chapter, - sections: Section + paragraphs: Paragraph, + sections: Section, } }) export class Datastore extends JsonApiDatastore { diff --git a/test/fixtures/author.fixture.ts b/test/fixtures/author.fixture.ts index 13258c15..d966dd6f 100644 --- a/test/fixtures/author.fixture.ts +++ b/test/fixtures/author.fixture.ts @@ -1,6 +1,7 @@ import {getSampleBook} from './book.fixture'; import { getSampleChapter } from './chapter.fixture'; import { getSampleSection } from './section.fixture'; +import { getSampleParagraph } from './paragraph.fixture'; export const AUTHOR_ID = '1'; export const AUTHOR_NAME = 'J. R. R. Tolkien'; @@ -97,6 +98,11 @@ export function getIncludedBooks(totalBooks: number, relationship?: string, tota const section = getSampleSection('1', '1'); responseArray.push(section); } + + if (relationship && relationship.indexOf('books.firstChapter.firstSection.firstParagraph') !== -1) { + const paragraph = getSampleParagraph('1', '1'); + responseArray.push(paragraph); + } } return responseArray; @@ -104,4 +110,4 @@ export function getIncludedBooks(totalBooks: number, relationship?: string, tota function includeBooks() { -} \ No newline at end of file +} diff --git a/test/fixtures/paragraph.fixture.ts b/test/fixtures/paragraph.fixture.ts new file mode 100644 index 00000000..ada4501a --- /dev/null +++ b/test/fixtures/paragraph.fixture.ts @@ -0,0 +1,19 @@ +export function getSampleParagraph(paragraphId: string, sectionId: string, content: string = 'Dummy content') { + return { + id: paragraphId, + type: 'paragraphs', + attributes: { + content, + created_at: '2016-10-01T12:54:32Z', + updated_at: '2016-10-01T12:54:32Z' + }, + relationships: { + section: { + data: { + id: sectionId, + type: 'sections' + } + } + } + }; +} diff --git a/test/fixtures/section.fixture.ts b/test/fixtures/section.fixture.ts index 63f33dd4..19907872 100644 --- a/test/fixtures/section.fixture.ts +++ b/test/fixtures/section.fixture.ts @@ -13,6 +13,12 @@ export function getSampleSection(sectionId: string, chapterId: string, content: id: chapterId, type: 'chapters' } + }, + firstParagraph: { + data: { + id: '1', + type: 'paragraphs' + } } } }; diff --git a/test/models/paragraph.model.ts b/test/models/paragraph.model.ts new file mode 100644 index 00000000..6c976428 --- /dev/null +++ b/test/models/paragraph.model.ts @@ -0,0 +1,16 @@ +import { JsonApiModelConfig } from '../../src/decorators/json-api-model-config.decorator'; +import { JsonApiModel } from '../../src/models/json-api.model'; +import { Attribute } from '../../src/decorators/attribute.decorator'; +import { BelongsTo } from '../../src/decorators/belongs-to.decorator'; +import { Chapter } from './chapter.model'; + +@JsonApiModelConfig({ + type: 'paragraphs' +}) +export class Paragraph extends JsonApiModel { + @Attribute() + content: string; + + @BelongsTo() + section: Section; +} diff --git a/test/models/section.model.ts b/test/models/section.model.ts index 4aa39402..68ce0569 100644 --- a/test/models/section.model.ts +++ b/test/models/section.model.ts @@ -3,6 +3,7 @@ import { JsonApiModel } from '../../src/models/json-api.model'; import { Attribute } from '../../src/decorators/attribute.decorator'; import { BelongsTo } from '../../src/decorators/belongs-to.decorator'; import { Chapter } from './chapter.model'; +import { Paragraph } from './paragraph.model'; @JsonApiModelConfig({ type: 'sections' @@ -11,6 +12,9 @@ export class Section extends JsonApiModel { @Attribute() content: string; + @BelongsTo() + firstParagraph: Paragraph; + @BelongsTo() chapter: Chapter; } From fb0af505c34fbcf71780c56f99c2b26c6fa0fae5 Mon Sep 17 00:00:00 2001 From: Mihael Safaric Date: Tue, 5 Jun 2018 14:53:12 +0200 Subject: [PATCH 3/9] Add specs for fourth level of belongsTo relationships --- src/models/json-api.model.spec.ts | 28 ++++++++++++++++++++------- test/datastore-with-config.service.ts | 2 ++ test/datastore.service.ts | 2 ++ test/fixtures/author.fixture.ts | 10 ++++++---- test/fixtures/paragraph.fixture.ts | 6 ++++++ test/fixtures/sentence.fixture.ts | 19 ++++++++++++++++++ test/models/paragraph.model.ts | 6 +++++- test/models/sentence.model.ts | 16 +++++++++++++++ 8 files changed, 77 insertions(+), 12 deletions(-) create mode 100644 test/fixtures/sentence.fixture.ts create mode 100644 test/models/sentence.model.ts diff --git a/src/models/json-api.model.spec.ts b/src/models/json-api.model.spec.ts index 055e6859..f8d643ba 100644 --- a/src/models/json-api.model.spec.ts +++ b/src/models/json-api.model.spec.ts @@ -150,7 +150,7 @@ describe('JsonApiModel', () => { }); fdescribe('parseBelongsTo', () => { - it('should parse the first level of belongTo relationships', () => { + it('should parse the first level of belongsTo relationships', () => { const REL = 'books'; const BOOK_NUMBER = 2; const CHAPTERS_NUMBER = 4; @@ -163,7 +163,7 @@ describe('JsonApiModel', () => { expect(author.books[0].firstChapter).toBeDefined(); }); - it('should parse the second level of belongTo relationships', () => { + it('should parse the second level of belongsTo relationships', () => { const REL = 'books'; const BOOK_NUMBER = 2; const CHAPTERS_NUMBER = 4; @@ -177,12 +177,10 @@ describe('JsonApiModel', () => { author = new Author(datastore, DATA); author.syncRelationships(DATA, INCLUDED, 0); - console.log(author.books[0].firstChapter.firstSection); - expect(author.books[0].firstChapter.firstSection).toBeDefined(); }); - it('should parse the third level of belongTo relationships', () => { + it('should parse the third level of belongsTo relationships', () => { const REL = 'books'; const BOOK_NUMBER = 2; const CHAPTERS_NUMBER = 4; @@ -197,10 +195,26 @@ describe('JsonApiModel', () => { author = new Author(datastore, DATA); author.syncRelationships(DATA, INCLUDED, 0); - console.log(author.books[0].firstChapter.firstSection.firstParagraph); - expect(author.books[0].firstChapter.firstSection.firstParagraph).toBeDefined(); }); + + it('should parse the fourth level of belongsTo relationships', () => { + const REL = 'books'; + const BOOK_NUMBER = 2; + const CHAPTERS_NUMBER = 4; + const DATA = getAuthorData(REL, BOOK_NUMBER); + const INCLUDED = getIncludedBooks( + BOOK_NUMBER, + // tslint:disable-next-line:max-line-length + 'books.chapters,books.firstChapter,books.firstChapter.firstSection,books.firstChapter.firstSection.firstParagraph,books.firstChapter.firstSection.firstParagraph.firstSentence', + 5 + ); + + author = new Author(datastore, DATA); + author.syncRelationships(DATA, INCLUDED, 0); + + expect(author.books[0].firstChapter.firstSection.firstParagraph.firstSentence).toBeDefined(); + }); }); }); }); diff --git a/test/datastore-with-config.service.ts b/test/datastore-with-config.service.ts index ad562b9b..f0c52d28 100644 --- a/test/datastore-with-config.service.ts +++ b/test/datastore-with-config.service.ts @@ -6,6 +6,7 @@ import { Book } from './models/book.model'; import { Chapter } from './models/chapter.model'; import { Section } from './models/section.model'; import { Paragraph } from './models/paragraph.model'; +import { Sentence } from './models/sentence.model'; const BASE_URL = 'http://localhost:8080'; const API_VERSION = 'v1'; @@ -22,6 +23,7 @@ export const API_VERSION_FROM_CONFIG = 'v2'; chapters: Chapter, paragraphs: Paragraph, sections: Section, + sentences: Sentence, } }) export class DatastoreWithConfig extends JsonApiDatastore { diff --git a/test/datastore.service.ts b/test/datastore.service.ts index 78274c04..ca1fb9c6 100644 --- a/test/datastore.service.ts +++ b/test/datastore.service.ts @@ -6,6 +6,7 @@ import { Book } from './models/book.model'; import { Chapter } from './models/chapter.model'; import { Section } from './models/section.model'; import { Paragraph } from './models/paragraph.model'; +import { Sentence } from './models/sentence.model'; export const BASE_URL = 'http://localhost:8080'; export const API_VERSION = 'v1'; @@ -19,6 +20,7 @@ export const API_VERSION = 'v1'; chapters: Chapter, paragraphs: Paragraph, sections: Section, + sentences: Sentence, } }) export class Datastore extends JsonApiDatastore { diff --git a/test/fixtures/author.fixture.ts b/test/fixtures/author.fixture.ts index d966dd6f..cb3f8a1b 100644 --- a/test/fixtures/author.fixture.ts +++ b/test/fixtures/author.fixture.ts @@ -2,6 +2,7 @@ import {getSampleBook} from './book.fixture'; import { getSampleChapter } from './chapter.fixture'; import { getSampleSection } from './section.fixture'; import { getSampleParagraph } from './paragraph.fixture'; +import { getSampleSentence } from './sentence.fixture'; export const AUTHOR_ID = '1'; export const AUTHOR_NAME = 'J. R. R. Tolkien'; @@ -103,11 +104,12 @@ export function getIncludedBooks(totalBooks: number, relationship?: string, tota const paragraph = getSampleParagraph('1', '1'); responseArray.push(paragraph); } + + if (relationship && relationship.indexOf('books.firstChapter.firstSection.firstParagraph.firstSentence') !== -1) { + const sentence = getSampleSentence('1', '1'); + responseArray.push(sentence); + } } return responseArray; } - -function includeBooks() { - -} diff --git a/test/fixtures/paragraph.fixture.ts b/test/fixtures/paragraph.fixture.ts index ada4501a..e5057b95 100644 --- a/test/fixtures/paragraph.fixture.ts +++ b/test/fixtures/paragraph.fixture.ts @@ -13,6 +13,12 @@ export function getSampleParagraph(paragraphId: string, sectionId: string, conte id: sectionId, type: 'sections' } + }, + firstSentence: { + data: { + id: '1', + type: 'sentences' + } } } }; diff --git a/test/fixtures/sentence.fixture.ts b/test/fixtures/sentence.fixture.ts new file mode 100644 index 00000000..159649cb --- /dev/null +++ b/test/fixtures/sentence.fixture.ts @@ -0,0 +1,19 @@ +export function getSampleSentence(sentenceId: string, paragraphId: string, content: string = 'Dummy content') { + return { + id: sentenceId, + type: 'sentences', + attributes: { + content, + created_at: '2016-10-01T12:54:32Z', + updated_at: '2016-10-01T12:54:32Z' + }, + relationships: { + paragraph: { + data: { + id: paragraphId, + type: 'paragraphs' + } + } + } + }; +} diff --git a/test/models/paragraph.model.ts b/test/models/paragraph.model.ts index 6c976428..e4a83293 100644 --- a/test/models/paragraph.model.ts +++ b/test/models/paragraph.model.ts @@ -2,7 +2,8 @@ import { JsonApiModelConfig } from '../../src/decorators/json-api-model-config.d import { JsonApiModel } from '../../src/models/json-api.model'; import { Attribute } from '../../src/decorators/attribute.decorator'; import { BelongsTo } from '../../src/decorators/belongs-to.decorator'; -import { Chapter } from './chapter.model'; +import { Sentence } from './sentence.model'; +import { Section } from './section.model'; @JsonApiModelConfig({ type: 'paragraphs' @@ -13,4 +14,7 @@ export class Paragraph extends JsonApiModel { @BelongsTo() section: Section; + + @BelongsTo() + firstSentence: Sentence; } diff --git a/test/models/sentence.model.ts b/test/models/sentence.model.ts new file mode 100644 index 00000000..bb246e06 --- /dev/null +++ b/test/models/sentence.model.ts @@ -0,0 +1,16 @@ +import { JsonApiModelConfig } from '../../src/decorators/json-api-model-config.decorator'; +import { JsonApiModel } from '../../src/models/json-api.model'; +import { Attribute } from '../../src/decorators/attribute.decorator'; +import { BelongsTo } from '../../src/decorators/belongs-to.decorator'; +import { Paragraph } from './paragraph.model'; + +@JsonApiModelConfig({ + type: 'sentences' +}) +export class Sentence extends JsonApiModel { + @Attribute() + content: string; + + @BelongsTo() + paragraph: Paragraph; +} From c5006cea043935f6aaadf8b3eef663606c7c442a Mon Sep 17 00:00:00 2001 From: Mihael Safaric Date: Tue, 5 Jun 2018 15:41:42 +0200 Subject: [PATCH 4/9] Fix syncing belongsTo relationships --- src/models/json-api.model.ts | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/models/json-api.model.ts b/src/models/json-api.model.ts index 7c7e193a..b1db6cfe 100644 --- a/src/models/json-api.model.ts +++ b/src/models/json-api.model.ts @@ -18,10 +18,10 @@ export class JsonApiModel { } } - syncRelationships(data: any, included: any, level: number): void { + syncRelationships(data: any, included: any, level: number, remainingModels?: Array): void { if (data) { this.parseHasMany(data, included, level); - this.parseBelongsTo(data, included, level); + this.parseBelongsTo(data, included); } } @@ -110,7 +110,7 @@ export class JsonApiModel { } } - private parseBelongsTo(data: any, included: any, level: number): void { + private parseBelongsTo(data: any, included: Array): void { const belongsTo: any = Reflect.getMetadata('BelongsTo', this); if (belongsTo) { @@ -128,7 +128,7 @@ export class JsonApiModel { dataRelationship, included, typeName, - level + included ); if (relationshipModel) { @@ -171,19 +171,20 @@ export class JsonApiModel { private getBelongsToRelationship( modelType: ModelType, data: any, - included: any, + included: Array, typeName: string, - level: number + remainingModels: Array ): T | null { const id: string = data.id; - const relationshipData: any = find(included, { id, type: typeName }); + const relationshipData: any = find(remainingModels, { id, type: typeName }); if (relationshipData) { const newObject: T = this.createOrPeek(modelType, relationshipData); - if (level <= 2) { - newObject.syncRelationships(relationshipData, included, level + 1); - } + const indexOfNewlyFoundModel = remainingModels.indexOf(relationshipData); + remainingModels.splice(indexOfNewlyFoundModel, 1); + + newObject.syncRelationships(relationshipData, included, 0, remainingModels); return newObject; } From be351d36ace86e5cd4c3194d6f5b2812b6b7e1c4 Mon Sep 17 00:00:00 2001 From: Mihael Safaric Date: Tue, 5 Jun 2018 17:24:38 +0200 Subject: [PATCH 5/9] Improve parsing belongsTo relationships --- src/models/json-api.model.spec.ts | 2 +- src/models/json-api.model.ts | 28 +++++++++++++++++++--------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/models/json-api.model.spec.ts b/src/models/json-api.model.spec.ts index f8d643ba..3d5a559a 100644 --- a/src/models/json-api.model.spec.ts +++ b/src/models/json-api.model.spec.ts @@ -149,7 +149,7 @@ describe('JsonApiModel', () => { }); }); - fdescribe('parseBelongsTo', () => { + describe('parseBelongsTo', () => { it('should parse the first level of belongsTo relationships', () => { const REL = 'books'; const BOOK_NUMBER = 2; diff --git a/src/models/json-api.model.ts b/src/models/json-api.model.ts index b1db6cfe..a377bbc8 100644 --- a/src/models/json-api.model.ts +++ b/src/models/json-api.model.ts @@ -20,8 +20,14 @@ export class JsonApiModel { syncRelationships(data: any, included: any, level: number, remainingModels?: Array): void { if (data) { - this.parseHasMany(data, included, level); - this.parseBelongsTo(data, included); + let modelsForProcessing = remainingModels; + + if (!modelsForProcessing) { + modelsForProcessing = [].concat(included); + } + + this.parseHasMany(data, included, level, modelsForProcessing); + this.parseBelongsTo(data, included, modelsForProcessing); } } @@ -71,7 +77,7 @@ export class JsonApiModel { } - private parseHasMany(data: any, included: any, level: number): void { + private parseHasMany(data: any, included: any, level: number, remainingModels: Array): void { const hasMany: any = Reflect.getMetadata('HasMany', this); if (hasMany) { @@ -92,7 +98,7 @@ export class JsonApiModel { if (modelType) { // tslint:disable-next-line:max-line-length - const relationshipModels: JsonApiModel[] = this.getHasManyRelationship(modelType, relationship.data, included, typeName, level); + const relationshipModels: JsonApiModel[] = this.getHasManyRelationship(modelType, relationship.data, included, typeName, level, remainingModels); if (relationshipModels.length > 0) { allModels = allModels.concat(relationshipModels); } @@ -110,7 +116,7 @@ export class JsonApiModel { } } - private parseBelongsTo(data: any, included: Array): void { + private parseBelongsTo(data: any, included: Array, remainingModels: Array): void { const belongsTo: any = Reflect.getMetadata('BelongsTo', this); if (belongsTo) { @@ -122,13 +128,14 @@ export class JsonApiModel { const typeName: string = dataRelationship.type; // tslint:disable-next-line:max-line-length const modelType: ModelType = Reflect.getMetadata('JsonApiDatastoreConfig', this._datastore.constructor).models[typeName]; + if (modelType) { const relationshipModel = this.getBelongsToRelationship( modelType, dataRelationship, included, typeName, - included + remainingModels ); if (relationshipModel) { @@ -148,7 +155,8 @@ export class JsonApiModel { data: any, included: any, typeName: string, - level: number + level: number, + remainingModels: Array ): Array { const relationshipList: Array = []; @@ -159,7 +167,7 @@ export class JsonApiModel { const newObject: T = this.createOrPeek(modelType, relationshipData); if (level <= 2) { - newObject.syncRelationships(relationshipData, included, level + 1); + newObject.syncRelationships(relationshipData, included, level + 1, remainingModels); } relationshipList.push(newObject); } @@ -176,7 +184,8 @@ export class JsonApiModel { remainingModels: Array ): T | null { const id: string = data.id; - const relationshipData: any = find(remainingModels, { id, type: typeName }); + + const relationshipData: any = remainingModels.find((x) => x.id === id && x.type === typeName); if (relationshipData) { const newObject: T = this.createOrPeek(modelType, relationshipData); @@ -188,6 +197,7 @@ export class JsonApiModel { return newObject; } + return this._datastore.peekRecord(modelType, id); } From 8e112c0682083e6e437a72c1a2f140f84e89cf6e Mon Sep 17 00:00:00 2001 From: Mihael Safaric Date: Tue, 5 Jun 2018 17:31:46 +0200 Subject: [PATCH 6/9] Remove hardcoded nesting levels while parsing hasMany relationships --- src/models/json-api.model.spec.ts | 18 +++++++++--------- src/models/json-api.model.ts | 21 +++++++++++---------- src/services/json-api-datastore.service.ts | 4 ++-- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/models/json-api.model.spec.ts b/src/models/json-api.model.spec.ts index 3d5a559a..7ab29bbe 100644 --- a/src/models/json-api.model.spec.ts +++ b/src/models/json-api.model.spec.ts @@ -72,7 +72,7 @@ describe('JsonApiModel', () => { const BOOK_NUMBER = 4; const DATA = getAuthorData('books', BOOK_NUMBER); author = new Author(datastore, DATA); - author.syncRelationships(DATA, getIncludedBooks(BOOK_NUMBER), 0); + author.syncRelationships(DATA, getIncludedBooks(BOOK_NUMBER)); expect(author).toBeDefined(); expect(author.id).toBe(AUTHOR_ID); expect(author.books).toBeDefined(); @@ -90,7 +90,7 @@ describe('JsonApiModel', () => { const DATA = getAuthorData('books', BOOK_NUMBER); author = new Author(datastore, DATA); datastore.addToStore(author); - author.syncRelationships(DATA, getIncludedBooks(BOOK_NUMBER), 0); + author.syncRelationships(DATA, getIncludedBooks(BOOK_NUMBER)); author.books.forEach((book: Book, index: number) => { expect(book.author).toBeDefined(); expect(book.author).toEqual(author); @@ -106,7 +106,7 @@ describe('JsonApiModel', () => { const DATA = getAuthorData(REL, BOOK_NUMBER); const INCLUDED = getIncludedBooks(BOOK_NUMBER, REL, CHAPTERS_NUMBER); author = new Author(datastore, DATA); - author.syncRelationships(DATA, INCLUDED, 0); + author.syncRelationships(DATA, INCLUDED); expect(author).toBeDefined(); expect(author.id).toBe(AUTHOR_ID); expect(author.books).toBeDefined(); @@ -135,13 +135,13 @@ describe('JsonApiModel', () => { const INCLUDED = getIncludedBooks(BOOK_NUMBER); const NEW_BOOK_TITLE = 'The Hobbit'; author = new Author(datastore, DATA); - author.syncRelationships(DATA, INCLUDED, 0); + author.syncRelationships(DATA, INCLUDED); INCLUDED.forEach((model) => { if (model.type === 'books') { model.attributes.title = NEW_BOOK_TITLE; } }); - author.syncRelationships(DATA, INCLUDED, 0); + author.syncRelationships(DATA, INCLUDED); author.books.forEach((book) => { expect(book.title).toBe(NEW_BOOK_TITLE); }); @@ -158,7 +158,7 @@ describe('JsonApiModel', () => { const INCLUDED = getIncludedBooks(BOOK_NUMBER, 'books.chapters,books.firstChapter', 5); author = new Author(datastore, DATA); - author.syncRelationships(DATA, INCLUDED, 0); + author.syncRelationships(DATA, INCLUDED); expect(author.books[0].firstChapter).toBeDefined(); }); @@ -175,7 +175,7 @@ describe('JsonApiModel', () => { ); author = new Author(datastore, DATA); - author.syncRelationships(DATA, INCLUDED, 0); + author.syncRelationships(DATA, INCLUDED); expect(author.books[0].firstChapter.firstSection).toBeDefined(); }); @@ -193,7 +193,7 @@ describe('JsonApiModel', () => { ); author = new Author(datastore, DATA); - author.syncRelationships(DATA, INCLUDED, 0); + author.syncRelationships(DATA, INCLUDED); expect(author.books[0].firstChapter.firstSection.firstParagraph).toBeDefined(); }); @@ -211,7 +211,7 @@ describe('JsonApiModel', () => { ); author = new Author(datastore, DATA); - author.syncRelationships(DATA, INCLUDED, 0); + author.syncRelationships(DATA, INCLUDED); expect(author.books[0].firstChapter.firstSection.firstParagraph.firstSentence).toBeDefined(); }); diff --git a/src/models/json-api.model.ts b/src/models/json-api.model.ts index a377bbc8..73cf67be 100644 --- a/src/models/json-api.model.ts +++ b/src/models/json-api.model.ts @@ -18,7 +18,7 @@ export class JsonApiModel { } } - syncRelationships(data: any, included: any, level: number, remainingModels?: Array): void { + syncRelationships(data: any, included: any, remainingModels?: Array): void { if (data) { let modelsForProcessing = remainingModels; @@ -26,7 +26,7 @@ export class JsonApiModel { modelsForProcessing = [].concat(included); } - this.parseHasMany(data, included, level, modelsForProcessing); + this.parseHasMany(data, included, modelsForProcessing); this.parseBelongsTo(data, included, modelsForProcessing); } } @@ -77,7 +77,7 @@ export class JsonApiModel { } - private parseHasMany(data: any, included: any, level: number, remainingModels: Array): void { + private parseHasMany(data: any, included: any, remainingModels: Array): void { const hasMany: any = Reflect.getMetadata('HasMany', this); if (hasMany) { @@ -98,7 +98,7 @@ export class JsonApiModel { if (modelType) { // tslint:disable-next-line:max-line-length - const relationshipModels: JsonApiModel[] = this.getHasManyRelationship(modelType, relationship.data, included, typeName, level, remainingModels); + const relationshipModels: JsonApiModel[] = this.getHasManyRelationship(modelType, relationship.data, included, typeName, remainingModels); if (relationshipModels.length > 0) { allModels = allModels.concat(relationshipModels); } @@ -155,20 +155,21 @@ export class JsonApiModel { data: any, included: any, typeName: string, - level: number, remainingModels: Array ): Array { const relationshipList: Array = []; data.forEach((item: any) => { - const relationshipData: any = find(included, { id: item.id, type: typeName }); + const relationshipData: any = remainingModels.find((x) => x.id === item.id && x.type === typeName); if (relationshipData) { const newObject: T = this.createOrPeek(modelType, relationshipData); - if (level <= 2) { - newObject.syncRelationships(relationshipData, included, level + 1, remainingModels); - } + const indexOfNewlyFoundModel = remainingModels.indexOf(relationshipData); + remainingModels.splice(indexOfNewlyFoundModel, 1); + + newObject.syncRelationships(relationshipData, included, remainingModels); + relationshipList.push(newObject); } }); @@ -193,7 +194,7 @@ export class JsonApiModel { const indexOfNewlyFoundModel = remainingModels.indexOf(relationshipData); remainingModels.splice(indexOfNewlyFoundModel, 1); - newObject.syncRelationships(relationshipData, included, 0, remainingModels); + newObject.syncRelationships(relationshipData, included, remainingModels); return newObject; } diff --git a/src/services/json-api-datastore.service.ts b/src/services/json-api-datastore.service.ts index 20ceae06..04ac3e68 100644 --- a/src/services/json-api-datastore.service.ts +++ b/src/services/json-api-datastore.service.ts @@ -263,7 +263,7 @@ export class JsonApiDatastore { this.addToStore(model); if (body.included) { - model.syncRelationships(data, body.included, 0); + model.syncRelationships(data, body.included); this.addToStore(model); } @@ -309,7 +309,7 @@ export class JsonApiDatastore { const deserializedModel = model || this.deserializeModel(modelType, body.data); this.addToStore(deserializedModel); if (body.included) { - deserializedModel.syncRelationships(body.data, body.included, 0); + deserializedModel.syncRelationships(body.data, body.included); this.addToStore(deserializedModel); } From 74a26c4bdb7ba97746bae4053f65d180fcffd592 Mon Sep 17 00:00:00 2001 From: Mihael Safaric Date: Tue, 5 Jun 2018 17:33:45 +0200 Subject: [PATCH 7/9] Use lodash find instead of the native one --- src/models/json-api.model.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/models/json-api.model.ts b/src/models/json-api.model.ts index 73cf67be..50155a33 100644 --- a/src/models/json-api.model.ts +++ b/src/models/json-api.model.ts @@ -160,7 +160,7 @@ export class JsonApiModel { const relationshipList: Array = []; data.forEach((item: any) => { - const relationshipData: any = remainingModels.find((x) => x.id === item.id && x.type === typeName); + const relationshipData: any = find(remainingModels, { id: item.id, type: typeName }); if (relationshipData) { const newObject: T = this.createOrPeek(modelType, relationshipData); @@ -186,7 +186,7 @@ export class JsonApiModel { ): T | null { const id: string = data.id; - const relationshipData: any = remainingModels.find((x) => x.id === id && x.type === typeName); + const relationshipData: any = find(remainingModels, { id, type: typeName }); if (relationshipData) { const newObject: T = this.createOrPeek(modelType, relationshipData); From 5e6269607057f11d0599993f88510085604f5790 Mon Sep 17 00:00:00 2001 From: Mihael Safaric Date: Tue, 5 Jun 2018 21:08:28 +0200 Subject: [PATCH 8/9] Update package-lock --- package-lock.json | 734 ---------------------------------------------- 1 file changed, 734 deletions(-) diff --git a/package-lock.json b/package-lock.json index 17370e07..6698e4c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -299,12 +299,6 @@ "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=", "dev": true }, - "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", - "dev": true - }, "asn1.js": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", @@ -325,12 +319,6 @@ "util": "0.10.3" } }, - "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", - "dev": true - }, "async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", @@ -343,24 +331,6 @@ "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", "dev": true }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", - "dev": true - }, - "aws4": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", - "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==", - "dev": true - }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", @@ -402,16 +372,6 @@ "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", "dev": true }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, "beeper": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", @@ -469,15 +429,6 @@ "type-is": "1.6.15" } }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -632,12 +583,6 @@ "map-obj": "1.0.1" } }, - "caseless": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", - "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", - "dev": true - }, "center-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", @@ -914,15 +859,6 @@ "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz" } }, - "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", - "dev": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, "commander": { "version": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", @@ -952,57 +888,6 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "concat-stream": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz", - "integrity": "sha1-U/fUPFHF5D+ByP3QMyHGMb5o1hE=", - "dev": true, - "requires": { - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "readable-stream": "2.0.6", - "typedarray": "0.0.6" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "readable-stream": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - } - } - }, "connect": { "version": "3.6.5", "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.5.tgz", @@ -1661,15 +1546,6 @@ "sha.js": "2.4.11" } }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "dev": true, - "requires": { - "boom": "2.10.1" - } - }, "crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", @@ -1704,23 +1580,6 @@ "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", "dev": true }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, "date-fns": { "version": "1.29.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.29.0.tgz", @@ -1756,12 +1615,6 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, "depd": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", @@ -1878,16 +1731,6 @@ } } }, - "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -2046,11 +1889,6 @@ "is-arrayish": "0.2.1" } }, - "es6-promise": { - "version": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.0.5.tgz", - "integrity": "sha512-4QUVu8ljexIQebW0h+5EhEqVKvh8p7Wu3zi3AqPmX3tFL2bf6MnZ2ytC/3xuUt1mo6kE2GSYNmjWyDo2SjkAsg==", - "dev": true - }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -2216,46 +2054,6 @@ "is-extglob": "1.0.0" } }, - "extract-zip": { - "version": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.5.0.tgz", - "integrity": "sha512-Ht7oUiEXWnX5BvLzMX/UBNIjrAs53lhXtNxMNeUe8Nv0S8rfy5UGqsKOXpP8ZQMWLvheOvRqYYShBoj6fTO9bg==", - "dev": true, - "requires": { - "concat-stream": "1.5.0", - "debug": "0.7.4", - "mkdirp": "0.5.0", - "yauzl": "2.4.1" - }, - "dependencies": { - "debug": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", - "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=", - "dev": true - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mkdirp": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", - "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, "fancy-log": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz", @@ -2273,15 +2071,6 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "fd-slicer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", - "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", - "dev": true, - "requires": { - "pend": "1.2.0" - } - }, "filename-regex": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", @@ -2441,23 +2230,6 @@ "for-in": "1.0.2" } }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "dev": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.6", - "mime-types": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz" - } - }, "fs-access": { "version": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", "integrity": "sha512-05cXDIwNbFaoFWaz5gNHlUTbH5whiss/hr/ibzPd4MH3cR4w0ZKeIPiVdbyJurg3O5r/Bjpvn9KOb1/rPMf3nA==", @@ -2466,16 +2238,6 @@ "null-check": "1.0.0" } }, - "fs-extra": { - "version": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha512-VerQV6vEKuhDWD2HGOybV6v5I73syoc/cXAbKlgTC7M/oFVEtklWlp9QH2Ijw3IaWDOQcMkldSPa7zXy79Z/UQ==", - "dev": true, - "requires": { - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "jsonfile": "2.4.0", - "klaw": "1.3.1" - } - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3386,44 +3148,12 @@ } } }, - "generate-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", - "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", - "dev": true - }, - "generate-object-property": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "dev": true, - "requires": { - "is-property": "1.0.2" - } - }, "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", "dev": true }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", @@ -3745,96 +3475,6 @@ } } }, - "har-validator": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", - "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "commander": "2.15.1", - "is-my-json-valid": "2.17.2", - "pinkie-promise": "2.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "2.0.4" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", @@ -3904,44 +3544,6 @@ "minimalistic-assert": "1.0.1" } }, - "hasha": { - "version": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", - "integrity": "sha512-jZ38TU/EBiGKrmyTNNZgnvCZHNowiRI4+w/I9noMlekHTZH3KyGgvJLmhSgykeAQ9j2SYPDosM0Bg3wHfzibAQ==", - "dev": true, - "requires": { - "is-stream": "1.1.0", - "pinkie-promise": "2.0.1" - }, - "dependencies": { - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "2.0.4" - } - } - } - }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -3953,12 +3555,6 @@ "minimalistic-crypto-utils": "1.0.1" } }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true - }, "hosted-git-info": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", @@ -3987,17 +3583,6 @@ "requires-port": "1.0.0" } }, - "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "dev": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.1", - "sshpk": "1.14.1" - } - }, "https-browserify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz", @@ -4147,33 +3732,6 @@ "is-extglob": "1.0.0" } }, - "is-my-ip-valid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", - "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", - "dev": true - }, - "is-my-json-valid": { - "version": "2.17.2", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", - "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", - "dev": true, - "requires": { - "generate-function": "2.0.0", - "generate-object-property": "1.2.0", - "is-my-ip-valid": "1.0.0", - "jsonpointer": "4.0.1", - "xtend": "4.0.1" - }, - "dependencies": { - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true - } - } - }, "is-number": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", @@ -4212,24 +3770,6 @@ "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", "dev": true }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", @@ -4271,12 +3811,6 @@ } } }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, "istanbul": { "version": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", "integrity": "sha512-nMtdn4hvK0HjUlzr1DrKSUY8ychprt8dzHOgY2KXsIhHu5PuQQEOTM27gV9Xblyon7aUH/TSFIjRHEODF/FRPg==", @@ -4364,24 +3898,11 @@ } } }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true, - "optional": true - }, "json-loader": { "version": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.4.tgz", "integrity": "sha512-UR2AoqXOuhwApRPGe9YUuU3ARd2fQ4gfZvCpJjZ2ZrKOrt3+DbLg5QXa1W5rUvdUIuhMHyxniMr+u4bHjWMVYQ==", "dev": true }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, "json-stable-stringify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", @@ -4391,59 +3912,18 @@ "jsonify": "0.0.0" } }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, "json3": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", "dev": true }, - "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", - "dev": true, - "requires": { - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz" - } - }, "jsonify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", "dev": true }, - "jsonpointer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", - "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", - "dev": true - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, "karma": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/karma/-/karma-1.7.1.tgz", @@ -4520,15 +4000,6 @@ "integrity": "sha1-IuTAa/mhguUpTR9wXjczgRuBCs8=", "dev": true }, - "karma-phantomjs-launcher": { - "version": "https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-1.0.4.tgz", - "integrity": "sha1-0jyjSAG9qYY60xjju0vUBisTrNI=", - "dev": true, - "requires": { - "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "phantomjs-prebuilt": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.14.tgz" - } - }, "karma-remap-istanbul": { "version": "https://registry.npmjs.org/karma-remap-istanbul/-/karma-remap-istanbul-0.6.0.tgz", "integrity": "sha1-l/O3cAZSVPm0ck8tm+SjouG69vw=", @@ -4597,11 +4068,6 @@ } } }, - "kew": { - "version": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", - "integrity": "sha512-IG6nm0+QtAMdXt9KvbgbGdvY50RSrw+U4sGZg+KlrSKPJEwVE5JVoI3d7RWfSMdBQneRheeAOj3lIjX5VL/9RQ==", - "dev": true - }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -4611,15 +4077,6 @@ "is-buffer": "1.1.6" } }, - "klaw": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", - "dev": true, - "requires": { - "graceful-fs": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz" - } - }, "lazy-cache": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", @@ -5418,12 +4875,6 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", - "dev": true - }, "object-assign": { "version": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", "integrity": "sha512-Lbc7GfN7XFaK30bzUN3cDYLOkT0dH05S0ax1QikylHUD9+Z9PRF3G1iYwX3kcz+6AlzTFGkUgMxz6l3aUwbwTA==", @@ -5651,28 +5102,6 @@ "sha.js": "2.4.11" } }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true - }, - "phantomjs-prebuilt": { - "version": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.14.tgz", - "integrity": "sha1-1T0xH8+30dCN2yQBRVjxGIxRbaA=", - "dev": true, - "requires": { - "es6-promise": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.0.5.tgz", - "extract-zip": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.5.0.tgz", - "fs-extra": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "hasha": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", - "kew": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", - "progress": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", - "request": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", - "request-progress": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", - "which": "https://registry.npmjs.org/which/-/which-1.2.14.tgz" - } - }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -5718,11 +5147,6 @@ "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true }, - "progress": { - "version": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", - "integrity": "sha512-UdA8mJ4weIkUBO224tIarHzuHs4HuYiJvsuGT7j/SPQiUJVjYvNDBIPa0hAorduOfjGohB/qHWRa/lrrWX/mXw==", - "dev": true - }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -6031,49 +5455,6 @@ "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", "dev": true }, - "request": { - "version": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", - "integrity": "sha512-e7MIJshe1eZAmRqg4ryaO0N9G0fs+/gpDe5FlbnIFy6zZznRSwdRFrLp63if0Yt43vrI5wowOqHv1qJdVocdOQ==", - "dev": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.7.0", - "caseless": "0.11.0", - "combined-stream": "1.0.6", - "extend": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "2.0.6", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", - "oauth-sign": "0.8.2", - "qs": "6.3.2", - "stringstream": "0.0.5", - "tough-cookie": "2.3.4", - "tunnel-agent": "0.4.3", - "uuid": "3.2.1" - }, - "dependencies": { - "qs": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", - "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=", - "dev": true - } - } - }, - "request-progress": { - "version": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", - "integrity": "sha512-dxdraeZVUNEn9AvLrxkgB2k6buTlym71dJk1fk4v8j3Ou3RKNm07BcgbHdj2lLgYGfqX71F+awb1MR+tWPFJzA==", - "dev": true, - "requires": { - "throttleit": "1.0.0" - } - }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -6177,15 +5558,6 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, "socket.io": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.3.tgz", @@ -6396,30 +5768,6 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "sshpk": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", - "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", - "dev": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, "statuses": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", @@ -6465,12 +5813,6 @@ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", - "dev": true - }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -6514,12 +5856,6 @@ "integrity": "sha512-hRjOGCWR8mjc40XPPvG51OMy+myPWcK8c3GxkmjTMxmy7sN05uFFUvKZW+nUB69vAIrUb7tH9j09GMSqAr4VWQ==", "dev": true }, - "throttleit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", - "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", - "dev": true - }, "through2": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.1.tgz", @@ -6612,23 +5948,6 @@ "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", "dev": true }, - "tough-cookie": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", - "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", - "dev": true, - "requires": { - "punycode": "1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - } - } - }, "trim-newlines": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", @@ -6850,19 +6169,6 @@ "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", "dev": true }, - "tunnel-agent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", - "dev": true - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true, - "optional": true - }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -6882,12 +6188,6 @@ "mime-types": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz" } }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, "typescript": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3.tgz", @@ -6980,12 +6280,6 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", "dev": true }, - "uuid": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", - "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", - "dev": true - }, "validate-npm-package-license": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", @@ -6996,25 +6290,6 @@ "spdx-expression-parse": "3.0.0" } }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "1.3.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, "vinyl": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", @@ -7425,15 +6700,6 @@ } } }, - "yauzl": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", - "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", - "dev": true, - "requires": { - "fd-slicer": "1.0.1" - } - }, "yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", From 82df9cc403b58caad02b5a14e74d4dc238f8d165 Mon Sep 17 00:00:00 2001 From: Mihael Safaric Date: Tue, 5 Jun 2018 21:08:48 +0200 Subject: [PATCH 9/9] Fix has many relationships sync --- src/models/json-api.model.spec.ts | 5 +++-- src/models/json-api.model.ts | 29 +++++++++++++++++++++++------ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/models/json-api.model.spec.ts b/src/models/json-api.model.spec.ts index 7ab29bbe..158ca68f 100644 --- a/src/models/json-api.model.spec.ts +++ b/src/models/json-api.model.spec.ts @@ -136,12 +136,13 @@ describe('JsonApiModel', () => { const NEW_BOOK_TITLE = 'The Hobbit'; author = new Author(datastore, DATA); author.syncRelationships(DATA, INCLUDED); - INCLUDED.forEach((model) => { + const newIncluded = INCLUDED.concat([]); + newIncluded.forEach((model) => { if (model.type === 'books') { model.attributes.title = NEW_BOOK_TITLE; } }); - author.syncRelationships(DATA, INCLUDED); + author.syncRelationships(DATA, newIncluded); author.books.forEach((book) => { expect(book.title).toBe(NEW_BOOK_TITLE); }); diff --git a/src/models/json-api.model.ts b/src/models/json-api.model.ts index 50155a33..f48b49ca 100644 --- a/src/models/json-api.model.ts +++ b/src/models/json-api.model.ts @@ -10,6 +10,8 @@ export class JsonApiModel { id: string; [key: string]: any; + lastSyncModels: Array; + // tslint:disable-next-line:variable-name constructor(private _datastore: JsonApiDatastore, data?: any) { if (data) { @@ -19,6 +21,10 @@ export class JsonApiModel { } syncRelationships(data: any, included: any, remainingModels?: Array): void { + if (this.lastSyncModels === included) { + return; + } + if (data) { let modelsForProcessing = remainingModels; @@ -29,6 +35,8 @@ export class JsonApiModel { this.parseHasMany(data, included, modelsForProcessing); this.parseBelongsTo(data, included, modelsForProcessing); } + + this.lastSyncModels = included; } save(params?: any, headers?: Headers): Observable { @@ -97,8 +105,14 @@ export class JsonApiModel { const modelType: ModelType = Reflect.getMetadata('JsonApiDatastoreConfig', this._datastore.constructor).models[typeName]; if (modelType) { - // tslint:disable-next-line:max-line-length - const relationshipModels: JsonApiModel[] = this.getHasManyRelationship(modelType, relationship.data, included, typeName, remainingModels); + const relationshipModels: JsonApiModel[] = this.getHasManyRelationship( + modelType, + relationship.data, + included, + typeName, + remainingModels + ); + if (relationshipModels.length > 0) { allModels = allModels.concat(relationshipModels); } @@ -166,13 +180,15 @@ export class JsonApiModel { const newObject: T = this.createOrPeek(modelType, relationshipData); const indexOfNewlyFoundModel = remainingModels.indexOf(relationshipData); - remainingModels.splice(indexOfNewlyFoundModel, 1); + const modelsForProcessing = remainingModels.concat([]); + modelsForProcessing.splice(indexOfNewlyFoundModel, 1); - newObject.syncRelationships(relationshipData, included, remainingModels); + newObject.syncRelationships(relationshipData, included, modelsForProcessing); relationshipList.push(newObject); } }); + return relationshipList; } @@ -192,9 +208,10 @@ export class JsonApiModel { const newObject: T = this.createOrPeek(modelType, relationshipData); const indexOfNewlyFoundModel = remainingModels.indexOf(relationshipData); - remainingModels.splice(indexOfNewlyFoundModel, 1); + const modelsForProcessing = remainingModels.concat([]); + modelsForProcessing.splice(indexOfNewlyFoundModel, 1); - newObject.syncRelationships(relationshipData, included, remainingModels); + newObject.syncRelationships(relationshipData, included, modelsForProcessing); return newObject; }