Skip to content

Commit 24e41e3

Browse files
authored
fix: use local cache instances (DEV-5409) (#700)
* refactor: deprecate old ontology and listcache * fix: introduce local cache instances * test: fix tests * chore: increase api version * refactor: bump version
1 parent 327dfe3 commit 24e41e3

File tree

9 files changed

+117
-44
lines changed

9 files changed

+117
-44
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@dasch-swiss/dsp-js",
3-
"version": "10.9.0",
3+
"version": "10.10.0",
44
"description": "JavaScript library that handles API requests to Knora",
55
"main": "index.js",
66
"files": [

src/api/v2/resource/resources-endpoint-v2.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { Observable } from "rxjs";
22
import { AjaxResponse } from "rxjs/ajax";
33
import { catchError, map, mergeMap } from "rxjs";
4+
import { ListNodeV2Cache } from "../../../cache/ListNodeV2Cache";
5+
import { OntologyCache } from "../../../cache/ontology-cache/OntologyCache";
46
import { KnoraApiConfig } from "../../../knora-api-config";
57
import { ApiResponseError } from "../../../models/api-response-error";
68
import { CanDoResponse } from "../../../models/v2/ontologies/read/can-do-response";
@@ -51,6 +53,11 @@ export class ResourcesEndpointV2 extends Endpoint {
5153
return acc + currentValue;
5254
});
5355

56+
// Create temporary caches for this request only
57+
// These will be garbage collected after the request completes
58+
const tempOntologyCache = new OntologyCache(this.knoraApiConfig, this.v2Endpoint);
59+
const tempListNodeCache = new ListNodeV2Cache(this.v2Endpoint);
60+
5461
return this.httpGet(resIris).pipe(
5562
mergeMap((ajaxResponse) => {
5663
// console.log(JSON.stringify(ajaxResponse.response));
@@ -59,7 +66,7 @@ export class ResourcesEndpointV2 extends Endpoint {
5966
return jsonld.compact(ajaxResponse.response, {});
6067
}), mergeMap((jsonldobj: object) => {
6168
// console.log(JSON.stringify(jsonldobj));
62-
return ResourcesConversionUtil.createReadResourceSequence(jsonldobj, this.v2Endpoint.ontologyCache, this.v2Endpoint.listNodeCache, this.jsonConvert);
69+
return ResourcesConversionUtil.createReadResourceSequence(jsonldobj, tempOntologyCache, tempListNodeCache, this.jsonConvert);
6370
}),
6471
catchError(error => {
6572
return this.handleError(error);
@@ -111,6 +118,11 @@ export class ResourcesEndpointV2 extends Endpoint {
111118

112119
});
113120

121+
// Create temporary caches for this request only
122+
// These will be garbage collected after the request completes
123+
const tempOntologyCache = new OntologyCache(this.knoraApiConfig, this.v2Endpoint);
124+
const tempListNodeCache = new ListNodeV2Cache(this.v2Endpoint);
125+
114126
return this.httpPost("", res, "json", {"X-Asset-Ingested": "true"}).pipe(
115127
mergeMap((ajaxResponse) => {
116128
// console.log(JSON.stringify(ajaxResponse.response));
@@ -119,7 +131,7 @@ export class ResourcesEndpointV2 extends Endpoint {
119131
return jsonld.compact(ajaxResponse.response, {});
120132
}), mergeMap((jsonldobj: object) => {
121133
// console.log(JSON.stringify(jsonldobj));
122-
return ResourcesConversionUtil.createReadResourceSequence(jsonldobj, this.v2Endpoint.ontologyCache, this.v2Endpoint.listNodeCache, this.jsonConvert);
134+
return ResourcesConversionUtil.createReadResourceSequence(jsonldobj, tempOntologyCache, tempListNodeCache, this.jsonConvert);
123135
}),
124136
map((resources: ReadResourceSequence) => resources.resources[0]),
125137
catchError(error => {

src/api/v2/resource/resources-endpoint.spec.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { of } from "rxjs";
22
import { AjaxError } from "rxjs/ajax";
3+
import { ListNodeV2Cache } from "../../../cache/ListNodeV2Cache";
4+
import { OntologyCache } from "../../../cache/ontology-cache/OntologyCache";
35
import { MockList } from "../../../../test/data/api/v2/mock-list";
46
import { MockOntology } from "../../../../test/data/api/v2/mock-ontology";
57
import { MockAjaxCall } from "../../../../test/mockajaxcall";
@@ -42,19 +44,21 @@ describe("ResourcesEndpoint", () => {
4244

4345
jasmine.Ajax.install();
4446

45-
knoraApiConnection = new KnoraApiConnection(config);
46-
47-
getResourceClassDefinitionFromCacheSpy = spyOn(knoraApiConnection.v2.ontologyCache, "getResourceClassDefinition").and.callFake(
48-
(resClassIri: string) => {
49-
return of(MockOntology.mockIResourceClassAndPropertyDefinitions(resClassIri));
50-
}
47+
// Mock cache methods at the prototype level
48+
// This ensures ALL cache instances (including temporary ones) get the mocks
49+
spyOn(OntologyCache.prototype, 'getResourceClassDefinition').and.callFake(
50+
(resClassIri: string) => of(MockOntology.mockIResourceClassAndPropertyDefinitions(resClassIri))
5151
);
5252

53-
getListNodeFromCacheSpy = spyOn(knoraApiConnection.v2.listNodeCache, "getNode").and.callFake(
54-
(listNodeIri: string) => {
55-
return of(MockList.mockNode(listNodeIri));
56-
}
53+
spyOn(ListNodeV2Cache.prototype, 'getNode').and.callFake(
54+
(listNodeIri: string) => of(MockList.mockNode(listNodeIri))
5755
);
56+
57+
knoraApiConnection = new KnoraApiConnection(config);
58+
59+
// Store references to the spies for test assertions
60+
getResourceClassDefinitionFromCacheSpy = OntologyCache.prototype.getResourceClassDefinition as jasmine.Spy;
61+
getListNodeFromCacheSpy = ListNodeV2Cache.prototype.getNode as jasmine.Spy;
5862
});
5963

6064
afterEach(() => {

src/api/v2/search/search-endpoint-v2.ts

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { AjaxResponse } from "rxjs/ajax";
22
import { catchError, map, mergeMap } from "rxjs";
3+
import { ListNodeV2Cache } from "../../../cache/ListNodeV2Cache";
4+
import { OntologyCache } from "../../../cache/ontology-cache/OntologyCache";
35
import { IFulltextSearchParams } from "../../../interfaces/models/v2/i-fulltext-search-params";
46
import { ILabelSearchParams } from "../../../interfaces/models/v2/i-label-search-params";
57
import { KnoraApiConfig } from "../../../knora-api-config";
@@ -86,6 +88,11 @@ export class SearchEndpointV2 extends Endpoint {
8688
doFulltextSearch(searchTerm: string, offset = 0, params?: IFulltextSearchParams) {
8789
// TODO: Do not hard-code the URL and http call params, generate this from Knora
8890

91+
// Create temporary caches for this request only
92+
// These will be garbage collected after the request completes
93+
const tempOntologyCache = new OntologyCache(this.knoraApiConfig, this.v2Endpoint);
94+
const tempListNodeCache = new ListNodeV2Cache(this.v2Endpoint);
95+
8996
return this.httpGet("/search/" + encodeURIComponent(searchTerm) + SearchEndpointV2.encodeFulltextParams(offset, params)).pipe(
9097
mergeMap((ajaxResponse) => {
9198
// console.log(JSON.stringify(ajaxResponse.response));
@@ -94,7 +101,7 @@ export class SearchEndpointV2 extends Endpoint {
94101
return jsonld.compact(ajaxResponse.response, {});
95102
}), mergeMap((jsonldobj: object) => {
96103
// console.log(JSON.stringify(jsonldobj));
97-
return ResourcesConversionUtil.createReadResourceSequence(jsonldobj, this.v2Endpoint.ontologyCache, this.v2Endpoint.listNodeCache, this.jsonConvert);
104+
return ResourcesConversionUtil.createReadResourceSequence(jsonldobj, tempOntologyCache, tempListNodeCache, this.jsonConvert);
98105
}),
99106
catchError(error => {
100107
return this.handleError(error);
@@ -137,6 +144,11 @@ export class SearchEndpointV2 extends Endpoint {
137144
// TODO: Do not hard-code the URL and http call params, generate this from Knora
138145
// TODO: check if content-type have to be set to text/plain
139146

147+
// Create temporary caches for this request only
148+
// These will be garbage collected after the request completes
149+
const tempOntologyCache = new OntologyCache(this.knoraApiConfig, this.v2Endpoint);
150+
const tempListNodeCache = new ListNodeV2Cache(this.v2Endpoint);
151+
140152
return this.httpPost("/searchextended", gravsearchQuery, "sparql").pipe(
141153
mergeMap((ajaxResponse) => {
142154
// console.log(JSON.stringify(ajaxResponse.response));
@@ -145,7 +157,7 @@ export class SearchEndpointV2 extends Endpoint {
145157
return jsonld.compact(ajaxResponse.response, {});
146158
}), mergeMap((jsonldobj: object) => {
147159
// console.log(JSON.stringify(jsonldobj));
148-
return ResourcesConversionUtil.createReadResourceSequence(jsonldobj, this.v2Endpoint.ontologyCache, this.v2Endpoint.listNodeCache, this.jsonConvert);
160+
return ResourcesConversionUtil.createReadResourceSequence(jsonldobj, tempOntologyCache, tempListNodeCache, this.jsonConvert);
149161
}),
150162
catchError(error => {
151163
return this.handleError(error);
@@ -184,11 +196,16 @@ export class SearchEndpointV2 extends Endpoint {
184196
* @param offset the offset to be used for paging
185197
*/
186198
doSearchIncomingLinks(resourceIri: string, offset = 0) {
199+
// Create temporary caches for this request only
200+
// These will be garbage collected after the request completes
201+
const tempOntologyCache = new OntologyCache(this.knoraApiConfig, this.v2Endpoint);
202+
const tempListNodeCache = new ListNodeV2Cache(this.v2Endpoint);
203+
187204
return this.httpGet(`/searchIncomingLinks/${encodeURIComponent(resourceIri)}?offset=${offset}`).pipe(
188205
mergeMap((response) => {
189206
return jsonld.compact(response.response, {});
190207
}), mergeMap((jsonld: object) => {
191-
return ResourcesConversionUtil.createReadResourceSequence(jsonld, this.v2Endpoint.ontologyCache, this.v2Endpoint.listNodeCache, this.jsonConvert);
208+
return ResourcesConversionUtil.createReadResourceSequence(jsonld, tempOntologyCache, tempListNodeCache, this.jsonConvert);
192209
}),
193210
catchError(err => {
194211
return this.handleError(err)
@@ -203,11 +220,16 @@ export class SearchEndpointV2 extends Endpoint {
203220
* @param offset the offset to be used for paging
204221
*/
205222
doSearchStillImageRepresentations(resourceIri: string, offset = 0) {
223+
// Create temporary caches for this request only
224+
// These will be garbage collected after the request completes
225+
const tempOntologyCache = new OntologyCache(this.knoraApiConfig, this.v2Endpoint);
226+
const tempListNodeCache = new ListNodeV2Cache(this.v2Endpoint);
227+
206228
return this.httpGet(`/searchStillImageRepresentations/${encodeURIComponent(resourceIri)}?offset=${offset}`).pipe(
207229
mergeMap((response) => {
208230
return jsonld.compact(response.response, {});
209231
}), mergeMap((jsonld: object) => {
210-
return ResourcesConversionUtil.createReadResourceSequence(jsonld, this.v2Endpoint.ontologyCache, this.v2Endpoint.listNodeCache, this.jsonConvert);
232+
return ResourcesConversionUtil.createReadResourceSequence(jsonld, tempOntologyCache, tempListNodeCache, this.jsonConvert);
211233
}),
212234
catchError(err => {
213235
return this.handleError(err)
@@ -240,11 +262,16 @@ export class SearchEndpointV2 extends Endpoint {
240262
* @param offset the offset to be used for paging
241263
*/
242264
doSearchIncomingRegions(resourceIri: string, offset = 0) {
265+
// Create temporary caches for this request only
266+
// These will be garbage collected after the request completes
267+
const tempOntologyCache = new OntologyCache(this.knoraApiConfig, this.v2Endpoint);
268+
const tempListNodeCache = new ListNodeV2Cache(this.v2Endpoint);
269+
243270
return this.httpGet(`/searchIncomingRegions/${encodeURIComponent(resourceIri)}?offset=${offset}`).pipe(
244271
mergeMap((response) => {
245272
return jsonld.compact(response.response, {});
246273
}), mergeMap((jsonld: object) => {
247-
return ResourcesConversionUtil.createReadResourceSequence(jsonld, this.v2Endpoint.ontologyCache, this.v2Endpoint.listNodeCache, this.jsonConvert);
274+
return ResourcesConversionUtil.createReadResourceSequence(jsonld, tempOntologyCache, tempListNodeCache, this.jsonConvert);
248275
}),
249276
catchError(err => {
250277
return this.handleError(err)
@@ -262,6 +289,11 @@ export class SearchEndpointV2 extends Endpoint {
262289
doSearchByLabel(searchTerm: string, offset = 0, params?: ILabelSearchParams) {
263290
// TODO: Do not hard-code the URL and http call params, generate this from Knora
264291

292+
// Create temporary caches for this request only
293+
// These will be garbage collected after the request completes
294+
const tempOntologyCache = new OntologyCache(this.knoraApiConfig, this.v2Endpoint);
295+
const tempListNodeCache = new ListNodeV2Cache(this.v2Endpoint);
296+
265297
return this.httpGet("/searchbylabel/" + encodeURIComponent(searchTerm) + SearchEndpointV2.encodeLabelParams(offset, params)).pipe(
266298
mergeMap((ajaxResponse) => {
267299
// console.log(JSON.stringify(ajaxResponse.response));
@@ -270,7 +302,7 @@ export class SearchEndpointV2 extends Endpoint {
270302
return jsonld.compact(ajaxResponse.response, {});
271303
}), mergeMap((jsonldobj: object) => {
272304
// console.log(JSON.stringify(jsonldobj));
273-
return ResourcesConversionUtil.createReadResourceSequence(jsonldobj, this.v2Endpoint.ontologyCache, this.v2Endpoint.listNodeCache, this.jsonConvert);
305+
return ResourcesConversionUtil.createReadResourceSequence(jsonldobj, tempOntologyCache, tempListNodeCache, this.jsonConvert);
274306
}),
275307
catchError(error => {
276308
return this.handleError(error);

src/api/v2/search/search-endpoint.spec.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { of } from "rxjs";
22
import { AjaxError } from "rxjs/ajax";
3+
import { ListNodeV2Cache } from "../../../cache/ListNodeV2Cache";
4+
import { OntologyCache } from "../../../cache/ontology-cache/OntologyCache";
35
import { MockList } from "../../../../test/data/api/v2/mock-list";
46
import { MockOntology } from "../../../../test/data/api/v2/mock-ontology";
57
import { MockAjaxCall } from "../../../../test/mockajaxcall";
@@ -22,20 +24,21 @@ describe("SearchEndpoint", () => {
2224
beforeEach(() => {
2325
jasmine.Ajax.install();
2426

25-
knoraApiConnection = new KnoraApiConnection(config);
26-
27-
getResourceClassSpy = spyOn(knoraApiConnection.v2.ontologyCache, "getResourceClassDefinition").and.callFake(
28-
(resClassIri: string) => {
29-
30-
return of(MockOntology.mockIResourceClassAndPropertyDefinitions(resClassIri));
31-
}
27+
// Mock cache methods at the prototype level
28+
// This ensures ALL cache instances (including temporary ones) get the mocks
29+
spyOn(OntologyCache.prototype, 'getResourceClassDefinition').and.callFake(
30+
(resClassIri: string) => of(MockOntology.mockIResourceClassAndPropertyDefinitions(resClassIri))
3231
);
3332

34-
getListNodeFromCacheSpy = spyOn(knoraApiConnection.v2.listNodeCache, "getNode").and.callFake(
35-
(listNodeIri: string) => {
36-
return of(MockList.mockNode(listNodeIri));
37-
}
33+
spyOn(ListNodeV2Cache.prototype, 'getNode').and.callFake(
34+
(listNodeIri: string) => of(MockList.mockNode(listNodeIri))
3835
);
36+
37+
knoraApiConnection = new KnoraApiConnection(config);
38+
39+
// Store references to the spies for test assertions
40+
getResourceClassSpy = OntologyCache.prototype.getResourceClassDefinition as jasmine.Spy;
41+
getListNodeFromCacheSpy = ListNodeV2Cache.prototype.getNode as jasmine.Spy;
3942
});
4043

4144
afterEach(() => {

src/api/v2/v2-endpoint.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,23 @@ export class V2Endpoint extends Endpoint {
3838

3939
readonly search: SearchEndpointV2;
4040

41+
/**
42+
* @deprecated This cache is kept for backwards compatibility with existing tests.
43+
* Production code should NOT use this cache - endpoints create temporary caches per request.
44+
* @category Internal
45+
*/
4146
readonly ontologyCache: OntologyCache;
4247

48+
/**
49+
* @deprecated This cache is kept for backwards compatibility with existing tests.
50+
* Production code should NOT use this cache - endpoints create temporary caches per request.
51+
* @category Internal
52+
*/
4353
readonly listNodeCache: ListNodeV2Cache;
4454

4555
/**
4656
* Sets up all endpoints for this endpoint.
47-
*
57+
*
4858
* @param knoraApiConfig the configuration for the DSP-API instance to connect to.
4959
* @param path this endpoint's path segment.
5060
*
@@ -62,7 +72,8 @@ export class V2Endpoint extends Endpoint {
6272
this.list = new ListsEndpointV2(knoraApiConfig, path);
6373
this.search = new SearchEndpointV2(knoraApiConfig, path, this);
6474

65-
// Instantiate caches
75+
// Initialize deprecated caches for test compatibility only
76+
// These are NOT used by production code - endpoints create temporary caches per request
6677
this.ontologyCache = new OntologyCache(knoraApiConfig, this);
6778
this.listNodeCache = new ListNodeV2Cache(this);
6879
}

src/api/v2/values/values-endpoint-v2.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { AjaxResponse } from "rxjs/ajax";
22
import { catchError, map, mergeMap } from "rxjs";
3+
import { ListNodeV2Cache } from "../../../cache/ListNodeV2Cache";
4+
import { OntologyCache } from "../../../cache/ontology-cache/OntologyCache";
35
import { KnoraApiConfig } from "../../../knora-api-config";
46
import { ReadResourceSequence } from "../../../models/v2/resources/read/read-resource-sequence";
57
import { ResourcesConversionUtil } from "../../../models/v2/resources/ResourcesConversionUtil";
@@ -40,6 +42,11 @@ export class ValuesEndpointV2 extends Endpoint {
4042
* @param valueUuid the value's UUID.
4143
*/
4244
getValue(resourceIri: string, valueUuid: string) {
45+
// Create temporary caches for this request only
46+
// These will be garbage collected after the request completes
47+
const tempOntologyCache = new OntologyCache(this.knoraApiConfig, this.v2Endpoint);
48+
const tempListNodeCache = new ListNodeV2Cache(this.v2Endpoint);
49+
4350
return this.httpGet("/" + encodeURIComponent(resourceIri) + "/" + encodeURIComponent(valueUuid)).pipe(
4451
mergeMap((ajaxResponse) => {
4552
// console.log(JSON.stringify(ajaxResponse.response));
@@ -48,7 +55,7 @@ export class ValuesEndpointV2 extends Endpoint {
4855
return jsonld.compact(ajaxResponse.response, {});
4956
}), mergeMap((jsonldobj: object) => {
5057
// console.log(JSON.stringify(jsonldobj));
51-
return ResourcesConversionUtil.createReadResourceSequence(jsonldobj, this.v2Endpoint.ontologyCache, this.v2Endpoint.listNodeCache, this.jsonConvert);
58+
return ResourcesConversionUtil.createReadResourceSequence(jsonldobj, tempOntologyCache, tempListNodeCache, this.jsonConvert);
5259
}),
5360
map((resources: ReadResourceSequence) => resources.resources[0]),
5461
catchError(error => {

0 commit comments

Comments
 (0)