Skip to content

Commit af98946

Browse files
maxi7587pablorsk
authored andcommitted
Fix to object (#240)
* fix-cache-ttl
1 parent d33303f commit af98946

9 files changed

+151
-16
lines changed

src/document-collection.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,19 @@ export class RelatedDocumentCollection<R extends Resource = Resource> extends Do
174174
});
175175
}
176176

177+
public setCacheLastUpdate(value = Date.now()) {
178+
this.cache_last_update = value;
179+
}
180+
181+
public setCacheLastUpdateAndPropagate(value = Date.now()) {
182+
this.setCacheLastUpdate(value);
183+
this.data.forEach(resource => {
184+
if (resource instanceof Resource) {
185+
resource.setCacheLastUpdate(value);
186+
}
187+
});
188+
}
189+
177190
public toObject(params?: IParamsCollection): IDataCollection {
178191
if (!this.builded) {
179192
return { data: this.data };

src/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ngx-jsonapi",
3-
"version": "2.1.9",
3+
"version": "2.1.10",
44
"description": "JSON API library for Angular",
55
"module": "ngx-jsonapi/@ngx-jsonapi/ngx-jsonapi.es5.js",
66
"es2015": "ngx-jsonapi/@ngx-jsonapi/ngx-jsonapi.js",

src/resource.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,4 +341,8 @@ export class Resource implements ICacheable {
341341
}
342342
}
343343
}
344+
345+
public setCacheLastUpdate(value = Date.now()) {
346+
this.cache_last_update = value;
347+
}
344348
}

src/service.spec.ts

Lines changed: 84 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ describe('service.all()', () => {
8686
await booksService.clearCacheMemory();
8787
test_response_subject.complete();
8888
test_response_subject = new BehaviorSubject(new HttpResponse());
89+
90+
// clear cachememory on every test
91+
let cachememory = CacheMemory.getInstance();
92+
(cachememory as any).resources = {};
93+
(cachememory as any).collections = {};
8994
});
9095

9196
it(`without cached collection emits source ^new-server|`, async () => {
@@ -179,13 +184,14 @@ describe('service.all()', () => {
179184
test_response_subject.next(new HttpResponse({ body: TestFactory.getCollectionDocumentData(Book) }));
180185
booksService.collections_ttl = 5; // live
181186
await booksService.all().toPromise();
182-
CacheMemory.getInstance().deprecateCollections(''); // kill only memory cache
187+
let cachememory = CacheMemory.getInstance(); // kill only memory cache
188+
(cachememory as any).resources = {}; // kill memory cache
189+
(cachememory as any).collections = {}; // kill memory cache
183190

184191
let http_request_spy = spyOn(HttpClient.prototype, 'request').and.callThrough();
185192
let expected = [
186193
// expected emits
187-
// source_resource: 'server' because we dont touch child elements
188-
{ builded: true, loaded: false, source: 'new', source_resource: 'server' },
194+
{ builded: false, loaded: false, source: 'new', source_resource: undefined },
189195
{ builded: true, loaded: true, source: 'store', source_resource: 'store' }
190196
];
191197

@@ -199,7 +205,44 @@ describe('service.all()', () => {
199205
}
200206
}),
201207
map(emit => {
202-
return { builded: emit.builded, loaded: emit.loaded, source: emit.source, source_resource: emit.data[0].source };
208+
if (emit.data.length > 0) {
209+
return { builded: emit.builded, loaded: emit.loaded, source: emit.source, source_resource: emit.data[0].source };
210+
} else {
211+
return { builded: emit.builded, loaded: emit.loaded, source: emit.source, source_resource: undefined };
212+
}
213+
}),
214+
toArray()
215+
)
216+
.toPromise();
217+
expect(emits).toMatchObject(expected);
218+
expect(http_request_spy).toHaveBeenCalledTimes(0);
219+
});
220+
221+
it(`with cached on store (live) collection wihtout includes emits source ^new-store|`, async () => {
222+
// caching collection
223+
test_response_subject.next(new HttpResponse({ body: TestFactory.getCollectionDocumentData(Book) }));
224+
booksService.collections_ttl = 5; // live
225+
await booksService.all({ include: ['author'] }).toPromise();
226+
let cachememory = CacheMemory.getInstance(); // kill only memory cache
227+
(cachememory as any).resources = {}; // kill memory cache
228+
(cachememory as any).collections = {}; // kill memory cache
229+
230+
let http_request_spy = spyOn(HttpClient.prototype, 'request').and.callThrough();
231+
let expected = [
232+
// expected emits
233+
{ builded: false, loaded: false, source: 'new', source_resource: undefined },
234+
{ builded: true, loaded: true, source: 'store', source_resource: 'store' }
235+
];
236+
237+
let emits = await booksService
238+
.all()
239+
.pipe(
240+
map(emit => {
241+
if (emit.data.length > 0) {
242+
return { builded: emit.builded, loaded: emit.loaded, source: emit.source, source_resource: emit.data[0].source };
243+
} else {
244+
return { builded: emit.builded, loaded: emit.loaded, source: emit.source, source_resource: undefined };
245+
}
203246
}),
204247
toArray()
205248
)
@@ -213,13 +256,39 @@ describe('service.all()', () => {
213256
test_response_subject.next(new HttpResponse({ body: TestFactory.getCollectionDocumentData(Book) }));
214257
booksService.collections_ttl = 0; // dead
215258
await booksService.all().toPromise();
216-
booksService.clearCacheMemory(); // kill only memory cache
259+
CacheMemory.getInstance().deprecateCollections('');
260+
261+
let http_request_spy = spyOn(HttpClient.prototype, 'request').and.callThrough();
262+
let expected = [
263+
// expected emits
264+
{ builded: true, loaded: false, source: 'new' }, // @TODO: builded should be false
265+
{ builded: true, loaded: true, source: 'server' }
266+
];
267+
268+
let emits = await booksService
269+
.all()
270+
.pipe(
271+
map(emit => {
272+
return { builded: emit.builded, loaded: emit.loaded, source: emit.source };
273+
}),
274+
toArray()
275+
)
276+
.toPromise();
277+
expect(emits).toMatchObject(expected);
278+
expect(http_request_spy).toHaveBeenCalledTimes(1);
279+
});
280+
281+
it(`with cached on store (dead, no collection_ttl defined) collection emits source ^new-store-server|`, async () => {
282+
// caching collection
283+
test_response_subject.next(new HttpResponse({ body: TestFactory.getCollectionDocumentData(Book) }));
284+
delete booksService.collections_ttl; // dead
285+
await booksService.all().toPromise();
286+
CacheMemory.getInstance().deprecateCollections('');
217287

218288
let http_request_spy = spyOn(HttpClient.prototype, 'request').and.callThrough();
219289
let expected = [
220290
// expected emits
221291
{ builded: true, loaded: false, source: 'new' }, // @TODO: builded should be false
222-
// { builded: true, loaded: false, source: 'store' }, // @todo
223292
{ builded: true, loaded: true, source: 'server' }
224293
];
225294

@@ -320,6 +389,7 @@ describe('service.all() and next service.get()', () => {
320389
});
321390

322391
it(`with cached collection on memory and next request get() without include`, async () => {
392+
Author.test_ttl = 100000;
323393
let http_request_spy = spyOn(HttpClient.prototype, 'request').and.callThrough();
324394
let all_authors_body = TestFactory.getCollectionDocumentData(Author, 1, ['books']);
325395
test_response_subject.next(new HttpResponse({ body: all_authors_body }));
@@ -346,8 +416,7 @@ describe('service.all() and next service.get()', () => {
346416
)
347417
.toPromise();
348418

349-
// @TODO: fix this error!!!
350-
// expect(author_emits).toMatchObject(expected); // ERROR!!! [{ loaded: false, source: 'memory' }, { loaded: false, source: 'store' }]
419+
expect(author_emits).toMatchObject(expected);
351420
// expect(received_author.relationships.books.data[0].attributes).toBeFalsy(); // ERROR!!!
352421
expect(http_request_spy).toHaveBeenCalledTimes(1); // on all() request
353422
});
@@ -385,7 +454,7 @@ describe('service.all() and next service.get()', () => {
385454
.toPromise();
386455

387456
// @TODO: fix this error!!!
388-
// expect(author_emits).toMatchObject(expected); // ERROR!!! [{ loaded: false, source: 'new' }, { loaded: false, source: 'store' }]
457+
expect(author_emits).toMatchObject(expected);
389458
// expect(received_author.relationships.books.data[0].attributes).toBeFalsy(); // ERROR!!!
390459
expect(http_request_spy).toHaveBeenCalledTimes(1); // on all() request
391460
});
@@ -395,6 +464,7 @@ describe('service.get()', () => {
395464
let core: Core;
396465
let booksService: BooksService;
397466
let authorsService: AuthorsService;
467+
let photosService: PhotosService;
398468
beforeEach(async () => {
399469
core = new Core(
400470
new JsonapiConfig(),
@@ -406,6 +476,8 @@ describe('service.get()', () => {
406476
await booksService.clearCacheMemory();
407477
authorsService = new AuthorsService();
408478
authorsService.register();
479+
photosService = new PhotosService();
480+
photosService.register();
409481
await authorsService.clearCacheMemory();
410482
test_response_subject.complete();
411483
test_response_subject = new BehaviorSubject(new HttpResponse());
@@ -589,17 +661,16 @@ describe('service.get()', () => {
589661
{ loaded: true, source: 'server' }
590662
];
591663
let emits = await booksService
592-
.get('1', { ttl: 1000 })
664+
.get('1')
593665
.pipe(
594666
map(emit => {
595667
return { loaded: emit.loaded, source: emit.source };
596668
}),
597669
toArray()
598670
)
599671
.toPromise();
600-
// @TODO: fix library
601-
// expect(emits).toMatchObject(expected); // ERROR!!! [{ loaded: true, source: 'memory' }, { loaded: true, source: 'server' }]
602-
// expect(http_request_spy).toHaveBeenCalledTimes(1); // ERROR: receiving 0...
672+
expect(emits).toMatchObject(expected);
673+
expect(http_request_spy).toHaveBeenCalledTimes(1);
603674
});
604675

605676
it(`with cached on store (live) resource emits source ^new-store|`, async () => {

src/service.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ export class Service<R extends Resource = Resource> {
124124

125125
return;
126126
}
127+
128+
throw new Error('Resource is dead!');
127129
}
128130

129131
// if you change this logic, maybe you need to change getAllFromServer()
@@ -193,7 +195,14 @@ export class Service<R extends Resource = Resource> {
193195
return <R>resource;
194196
}
195197

198+
/**
199+
* deprecated since 2.2
200+
*/
196201
public async clearCacheMemory(): Promise<boolean> {
202+
return this.clearCache();
203+
}
204+
205+
public async clearCache(): Promise<boolean> {
197206
let path = new PathBuilder();
198207
path.applyParams(this);
199208

@@ -240,6 +249,10 @@ export class Service<R extends Resource = Resource> {
240249
public all(params: IParamsCollection = {}): Observable<DocumentCollection<R>> {
241250
let builded_params: IBuildedParamsCollection = { ...Base.ParamsCollection, ...params };
242251

252+
if (!builded_params.ttl && builded_params.ttl !== 0) {
253+
builded_params.ttl = this.collections_ttl;
254+
}
255+
243256
let path = new PathCollectionBuilder();
244257
path.applyParams(this, builded_params);
245258

@@ -260,7 +273,9 @@ export class Service<R extends Resource = Resource> {
260273
this.getAllFromLocal(builded_params, path, temporary_collection)
261274
.then(() => {
262275
subject.next(temporary_collection);
263-
setTimeout(() => subject.complete(), 0);
276+
setTimeout(() => {
277+
subject.complete();
278+
}, 0);
264279
})
265280
.catch(() => {
266281
temporary_collection.setLoaded(false);
@@ -305,6 +320,8 @@ export class Service<R extends Resource = Resource> {
305320

306321
return;
307322
}
323+
324+
throw new Error('Collection is dead!');
308325
}
309326

310327
// if you change this logic, maybe you need to change getGetFromServer()
@@ -329,6 +346,7 @@ export class Service<R extends Resource = Resource> {
329346
}
330347
temporary_collection.fill(<IDataCollection>success);
331348
temporary_collection.cache_last_update = Date.now();
349+
temporary_collection.setCacheLastUpdateAndPropagate();
332350
temporary_collection.setSourceAndPropagate('server');
333351
temporary_collection.setLoadedAndPropagate(true);
334352

src/services/json-ripper.spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ describe('JsonRipper for collections', () => {
140140
author1.relationships.books.data[1].id = '2';
141141
let book1 = author1.relationships.books.data[0];
142142
book1.addRelationship(author1, 'author');
143-
console.log(author1.relationships.books.data[1]);
144143

145144
/* Is private now
146145
it('A collection is converted to objects for a DataProvider', () => {

src/tests/factories/authors.service.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ export class Author extends Resource {
2121
};
2222
public type = 'authors';
2323
public ttl = 0;
24+
public static test_ttl;
25+
26+
public constructor() {
27+
super();
28+
29+
if (Author.test_ttl || Author.test_ttl === 0) {
30+
this.ttl = Author.test_ttl;
31+
}
32+
}
2433
}
2534

2635
export class AuthorsService extends Service<Author> {

src/tests/factories/books.service.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ export class Book extends Resource {
2121
};
2222
public type = 'books';
2323
public ttl = 0;
24+
public static test_ttl;
25+
26+
public constructor() {
27+
super();
28+
29+
if (Book.test_ttl || Book.test_ttl === 0) {
30+
this.ttl = Book.test_ttl;
31+
}
32+
}
2433
}
2534

2635
export class BooksService extends Service<Book> {

src/tests/factories/photos.service.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,18 @@ export class Photo extends Resource {
99
created_at: new Date(),
1010
updated_at: new Date()
1111
};
12+
13+
public type = 'photos';
14+
public ttl = 0;
15+
public static test_ttl;
16+
17+
public constructor() {
18+
super();
19+
20+
if (Photo.test_ttl || Photo.test_ttl === 0) {
21+
this.ttl = Photo.test_ttl;
22+
}
23+
}
1224
}
1325

1426
export class PhotosService extends Service<Photo> {

0 commit comments

Comments
 (0)