diff --git a/src/N3Store.js b/src/N3Store.js index db39b0b7..88359f20 100644 --- a/src/N3Store.js +++ b/src/N3Store.js @@ -7,6 +7,16 @@ import N3Writer from './N3Writer'; const ITERATOR = Symbol('iter'); +function merge(target, source, depth = 4) { + if (depth === 0) + return Object.assign(target, source); + + for (const key in source) + target[key] = merge(target[key] || Object.create(null), source[key], depth - 1); + + return target; +} + // ## Constructor export class N3EntityIndex { constructor(options = {}) { @@ -792,6 +802,12 @@ export default class N3Store { addAll(quads) { if (Array.isArray(quads)) this.addQuads(quads); + else if (quads instanceof N3Store && quads._entityIndex === this._entityIndex) { + if (quads._size !== 0) { + this._graphs = merge(this._graphs, quads._graphs); + this._size = null; // Invalidate the cached size + } + } else { for (const quad of quads) this.add(quad); @@ -799,7 +815,6 @@ export default class N3Store { return this; } - /** * Returns `true` if the current dataset is a superset of the given dataset; in other words, returns `true` if * the given dataset is a subset of, i.e., is contained within, the current dataset. @@ -807,6 +822,9 @@ export default class N3Store { * Blank Nodes will be normalized. */ contains(other) { + if (other === this) + return true; + if (!(other instanceof N3Store) || this._entityIndex !== other._entityIndex) return other.every(quad => this.has(quad)); @@ -848,6 +866,9 @@ export default class N3Store { * Returns a new dataset that contains all quads from the current dataset that are not included in the given dataset. */ difference(other) { + if (other === this) + return new N3Store({ entityIndex: this._entityIndex }); + return this.filter(quad => !other.has(quad)); } @@ -877,6 +898,11 @@ export default class N3Store { * Returns a new dataset containing all quads from the current dataset that are also included in the given dataset. */ intersection(other) { + if (other === this) { + const store = new N3Store({ entityIndex: this._entityIndex }); + store._graphs = merge(Object.create(null), this._graphs); + store._size = this._size; + } return this.filter(quad => other.has(quad)); } @@ -947,7 +973,9 @@ export default class N3Store { */ union(quads) { const store = new N3Store({ entityIndex: this._entityIndex }); - store.addAll(this); + store._graphs = merge(Object.create(null), this._graphs); + store._size = this._size; + store.addAll(quads); return store; } diff --git a/test/N3Store-test.js b/test/N3Store-test.js index 15bab330..3fb3aaf9 100644 --- a/test/N3Store-test.js +++ b/test/N3Store-test.js @@ -2111,6 +2111,10 @@ describe('Store', () => { expect(store1.size).toEqual(2); expect(store2.size).toEqual(2); expect(store.size).toEqual(3); + + expect(store.union(store).size).toEqual(3); + expect(store.union(empty).size).toEqual(3); + expect(store1.union(empty).size).toEqual(2); }); }); @@ -2120,6 +2124,9 @@ describe('Store', () => { expect(store1.size).toEqual(2); expect(store2.size).toEqual(2); expect(store.size).toEqual(1); + + expect(store.difference(store).size).toEqual(0); + expect(store2.difference(store2).size).toEqual(0); }); }); @@ -2129,6 +2136,9 @@ describe('Store', () => { expect(store1.size).toEqual(2); expect(store2.size).toEqual(2); expect(store.size).toEqual(1); + + expect(store.intersection(store).size).toEqual(1); + expect(store2.intersection(store2).size).toEqual(2); }); });