diff --git a/lib/RdfObjectLoader.ts b/lib/RdfObjectLoader.ts index 413dcfd..253d7f2 100644 --- a/lib/RdfObjectLoader.ts +++ b/lib/RdfObjectLoader.ts @@ -12,6 +12,7 @@ import { Resource } from './Resource'; export class RdfObjectLoader { private readonly dataFactory: RDF.DataFactory; public readonly normalizeLists: boolean; + public readonly uniqueLiterals: boolean; public readonly context: Promise; public readonly resources: Record = {}; public contextResolved!: JsonLdContextNormalized; @@ -20,6 +21,7 @@ export class RdfObjectLoader { public constructor(args?: IRdfClassLoaderArgs) { this.dataFactory = args?.dataFactory || new DataFactory(); this.normalizeLists = !args || !('normalizeLists' in args) || Boolean(args.normalizeLists); + this.uniqueLiterals = Boolean(args?.uniqueLiterals); this.context = new ContextParser().parse(args && args.context || {}) .then(contextResolved => { @@ -37,6 +39,10 @@ export class RdfObjectLoader { * @return {Resource} A resource. */ public getOrMakeResource(term: RDF.Term): Resource { + if (this.uniqueLiterals && term.termType === 'Literal') { + return new Resource({ term, context: this.contextResolved }); + } + const termString: string = termToString(term); let resource: Resource = this.resources[termString]; if (!resource) { @@ -181,7 +187,7 @@ export class RdfObjectLoader { if (this.normalizeLists) { for (const listRoot of listMaterializer.getRoots()) { const listTerms = listMaterializer.getList(listRoot); - this.resources[termToString(listRoot)].list = listTerms!.map(term => this.resources[termToString(term)]); + this.resources[termToString(listRoot)].list = listTerms!.map(term => this.getOrMakeResource(term)); } } resolve(); @@ -221,4 +227,9 @@ export interface IRdfClassLoaderArgs { * The factory to create RDF terms and quads with. */ dataFactory?: RDF.DataFactory; + /** + * If set to true literals will not be cached. + * Defaults to false. + */ + uniqueLiterals?: boolean; } diff --git a/test/RdfObjectLoader-test.ts b/test/RdfObjectLoader-test.ts index 8ee905d..a52187a 100644 --- a/test/RdfObjectLoader-test.ts +++ b/test/RdfObjectLoader-test.ts @@ -501,4 +501,48 @@ describe('RdfObjectLoader', () => { }); }); }); + + describe('an instance with unique literals', (): void => { + let loader: RdfObjectLoader; + + beforeEach((): void => { + loader = new RdfObjectLoader({ uniqueLiterals: true }); + }); + + it('does not store literals in the resource cache.', async(): Promise => { + await loader.import(streamifyArray([ + quad('http://example.org/s', 'http://example.org/p', '"test"'), + ])); + const resourceP = loader.getOrMakeResource(DF.namedNode('http://example.org/p')); + const resourceS = loader.getOrMakeResource(DF.namedNode('http://example.org/s')); + expect(loader.resources).toEqual({ + 'http://example.org/p': resourceP, + 'http://example.org/s': resourceS, + }); + expect(loader.resources['"test"']).toBeUndefined(); + }); + + it('should normalize a list', async() => { + await loader.import(streamifyArray([ + quad('http://example.org/listResource', 'http://example.org/listPredicate', 'http://example.org/l0'), + quad('http://example.org/l0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '"A"'), + quad('http://example.org/l0', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://example.org/l1'), + quad('http://example.org/l1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '"B"'), + quad('http://example.org/l1', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', 'http://example.org/l2'), + quad('http://example.org/l2', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#first', '"C"'), + quad('http://example.org/l2', + 'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest', + 'http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'), + ])); + const valueA = loader.getOrMakeResource(DF.literal('A')); + const valueB = loader.getOrMakeResource(DF.literal('B')); + const valueC = loader.getOrMakeResource(DF.literal('C')); + const list = loader.resources['http://example.org/listResource'] + .propertiesUri['http://example.org/listPredicate'][0].list; + expect(list?.[0]).not.toBe(valueA); + expect(list?.[0].value).toEqual(valueA.value); + expect(list?.[1].value).toEqual(valueB.value); + expect(list?.[2].value).toEqual(valueC.value); + }); + }); });