link-rdflib
Version:
an RDF library for node.js, patched for speed.
993 lines (796 loc) • 30 kB
JavaScript
"use strict";
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
/* Identity management and indexing for RDF
*
* This file provides IndexedFormula a formula (set of triples) which
* indexed by predicate, subject and object.
*
* It "smushes" (merges into a single node) things which are identical
* according to owl:sameAs or an owl:InverseFunctionalProperty
* or an owl:FunctionalProperty
*
*
* 2005-10 Written Tim Berners-Lee
* 2007 Changed so as not to munge statements from documents when smushing
*
*
*/
/** @module store */
var ArrayIndexOf = require('./util').ArrayIndexOf;
var Formula = require('./formula'); // const log = require('./log')
var RDFArrayRemove = require('./util').RDFArrayRemove;
var Statement = require('./statement');
var NamedNode = require('./named-node');
var Node = require('./node');
var ns = require('./ns');
var Variable = require('./variable'); // Handle Functional Property
function handleFP(formula, subj, pred, obj) {
var o1 = formula.any(subj, pred, undefined);
if (!o1) {
return false; // First time with this value
} // log.warn("Equating "+o1.uri+" and "+obj.uri + " because FP "+pred.uri); //@@
formula.equate(o1, obj);
return true;
} // handleFP
// Handle Inverse Functional Property
function handleIFP(formula, subj, pred, obj) {
var s1 = formula.any(undefined, pred, obj);
if (!s1) {
return false; // First time with this value
} // log.warn("Equating "+s1.uri+" and "+subj.uri + " because IFP "+pred.uri); //@@
formula.equate(s1, subj);
return true;
} // handleIFP
function handleRDFType(formula, subj, pred, obj, why) {
if (formula.typeCallback) {
formula.typeCallback(formula, obj, why);
}
var x = formula.classActions[obj.hashString()];
var done = false;
if (x) {
for (var i = 0; i < x.length; i++) {
done = done || x[i](formula, subj, pred, obj, why);
}
}
return done; // statement given is not needed if true
}
/**
* Indexed Formula aka Store
*/
var IndexedFormula =
/*#__PURE__*/
function (_Formula) {
_inherits(IndexedFormula, _Formula);
// IN future - allow pass array of statements to constructor
/**
* @constructor
* @param {Array<String>} features - What sort of autmatic processing to do? Array of string
* @param {Boolean} features.sameAs - Smush together A and B nodes whenever { A sameAs B }
*/
function IndexedFormula(features) {
var _this;
_classCallCheck(this, IndexedFormula);
_this = _possibleConstructorReturn(this, _getPrototypeOf(IndexedFormula).call(this));
_this.propertyActions = []; // Array of functions to call when getting statement with {s X o}
// maps <uri> to [f(F,s,p,o),...]
_this.classActions = []; // Array of functions to call when adding { s type X }
_this.redirections = []; // redirect to lexically smaller equivalent symbol
_this.aliases = []; // reverse mapping to redirection: aliases for this
_this.HTTPRedirects = []; // redirections we got from HTTP
_this.subjectIndex = []; // Array of statements with this X as subject
_this.predicateIndex = []; // Array of statements with this X as subject
_this.objectIndex = []; // Array of statements with this X as object
_this.whyIndex = []; // Array of statements with X as provenance
_this.index = [_this.subjectIndex, _this.predicateIndex, _this.objectIndex, _this.whyIndex];
_this.namespaces = {}; // Dictionary of namespace prefixes
_this.features = features || ['sameAs', 'InverseFunctionalProperty', 'FunctionalProperty'];
_this.initPropertyActions(_this.features);
_this.defaultGraphIRI = Statement.defaultGraph;
return _this;
}
_createClass(IndexedFormula, [{
key: "substitute",
value: function substitute(bindings) {
var statementsCopy = this.statements.map(function (ea) {
return ea.substitute(bindings);
});
var y = new IndexedFormula();
y.add(statementsCopy);
return y;
}
}, {
key: "applyPatch",
value: function applyPatch(patch, target, patchCallback) {
// patchCallback(err)
var Query = require('./query').Query;
var targetKB = this;
var ds;
var binding = null; // /////////// Debug strings
/*
var bindingDebug = function (b) {
var str = ''
var v
for (v in b) {
if (b.hasOwnProperty(v)) {
str += ' ' + v + ' -> ' + b[v]
}
}
return str
}
*/
var doPatch = function doPatch(onDonePatch) {
if (patch['delete']) {
ds = patch['delete']; // console.log(bindingDebug(binding))
// console.log('ds before substitute: ' + ds)
if (binding) ds = ds.substitute(binding); // console.log('applyPatch: delete: ' + ds)
ds = ds.statements;
var bad = [];
var ds2 = ds.map(function (st) {
// Find the actual statemnts in the store
var sts = targetKB.statementsMatching(st.subject, st.predicate, st.object, target);
if (sts.length === 0) {
// log.info("NOT FOUND deletable " + st)
bad.push(st);
return null;
} else {
// log.info("Found deletable " + st)
return sts[0];
}
});
if (bad.length) {
// console.log('Could not find to delete ' + bad.length + 'statements')
// console.log('despite ' + targetKB.statementsMatching(bad[0].subject, bad[0].predicate)[0])
return patchCallback('Could not find to delete: ' + bad.join('\n or '));
}
ds2.map(function (st) {
targetKB.remove(st);
});
}
if (patch['insert']) {
// log.info("doPatch insert "+patch['insert'])
ds = patch['insert'];
if (binding) ds = ds.substitute(binding);
ds = ds.statements;
ds.map(function (st) {
st.why = target;
targetKB.add(st.subject, st.predicate, st.object, st.why);
});
}
onDonePatch();
};
if (patch.where) {
// log.info("Processing WHERE: " + patch.where + '\n')
var query = new Query('patch');
query.pat = patch.where;
query.pat.statements.map(function (st) {
st.why = target;
});
var bindingsFound = [];
targetKB.query(query, function onBinding(binding) {
bindingsFound.push(binding); // console.log(' got a binding: ' + bindingDebug(binding))
}, targetKB.fetcher, function onDone() {
if (bindingsFound.length === 0) {
return patchCallback('No match found to be patched:' + patch.where);
}
if (bindingsFound.length > 1) {
return patchCallback('Patch ambiguous. No patch done.');
}
binding = bindingsFound[0];
doPatch(patchCallback);
});
} else {
doPatch(patchCallback);
}
}
}, {
key: "declareExistential",
value: function declareExistential(x) {
if (!this._existentialVariables) this._existentialVariables = [];
this._existentialVariables.push(x);
return x;
}
}, {
key: "initPropertyActions",
value: function initPropertyActions(features) {
// If the predicate is #type, use handleRDFType to create a typeCallback on the object
this.propertyActions[ns.rdf('type').hashString()] = [handleRDFType]; // Assumption: these terms are not redirected @@fixme
if (ArrayIndexOf(features, 'sameAs') >= 0) {
this.propertyActions[ns.owl('sameAs').hashString()] = [function (formula, subj, pred, obj, why) {
// log.warn("Equating "+subj.uri+" sameAs "+obj.uri); //@@
formula.equate(subj, obj);
return true; // true if statement given is NOT needed in the store
}]; // sameAs -> equate & don't add to index
}
if (ArrayIndexOf(features, 'InverseFunctionalProperty') >= 0) {
this.classActions[ns.owl('InverseFunctionalProperty').hashString()] = [function (formula, subj, pred, obj, addFn) {
// yes subj not pred!
return formula.newPropertyAction(subj, handleIFP);
}]; // IFP -> handleIFP, do add to index
}
if (ArrayIndexOf(features, 'FunctionalProperty') >= 0) {
this.classActions[ns.owl('FunctionalProperty')] = [function (formula, subj, proj, obj, addFn) {
return formula.newPropertyAction(subj, handleFP);
}]; // FP => handleFP, do add to index
}
}
/**
* Adds a statement to the store
* @param st {Statement} The statement to add
* @return {this}
*/
}, {
key: "addStatement",
value: function addStatement(st) {
if (!st.why) {
throw new Error('Statement without graph given');
}
if (this.predicateCallback) {
this.predicateCallback(this, st.predicate, st.why);
} // Action return true if the statement does not need to be added
var predHash = this.canon(st.predicate).sI;
var actions = this.propertyActions[predHash]; // Predicate hash
var done = false;
if (actions) {
// alert('type: '+typeof actions +' @@ actions='+actions)
for (i = 0; i < actions.length; i++) {
done = done || actions[i](this, st.subject, st.predicate, st.object, st.why);
}
} // Takes time but saves duplicates
if (this.holds(st)) {
return null; // @@better to return self in all cases?
} // If we are tracking provenance, every thing should be loaded into the store
// if (done) return new Statement(subj, pred, obj, why)
// Don't put it in the store
// still return this statement for owl:sameAs input
var hash = [this.canon(st.subject).sI, predHash, this.canon(st.object).sI, this.canon(st.why).sI];
var i, ix, h;
for (var _i = 0; _i < 4; _i++) {
ix = this.index[_i];
h = hash[_i];
if (!ix[h]) {
ix[h] = [];
}
ix[h].push(st); // Set of things with this as subject, etc
}
this.statements.push(st);
return st;
}
/**
* Adds a triple (quad) to the store.
*
* @param {Term} subj - The thing about which the fact a relationship is asserted
* @param {namedNode} pred - The relationship which is asserted
* @param {Term} obj - The object of the relationship, e.g. another thing or avalue
* @param {namedNode} why - The document in which the triple (S,P,O) was or will be stored on the web
* @returns {Statement} The statement added to the store
*/
}, {
key: "add",
value: function add(subj, pred, obj, why) {
if (typeof pred === "undefined") {
if (Array.isArray(subj)) {
for (var i = 0; i < subj.length; i++) {
this.add(subj[i]);
}
} else if (subj instanceof Statement) {
this.addStatement(subj);
} else if (subj instanceof IndexedFormula) {
this.add(subj.statements);
}
return this;
}
var st = Statement.from(subj, pred, obj, why);
this.addStatement(st);
return st;
}
/**
* Returns the symbol with canonical URI as smushed
*/
}, {
key: "canon",
value: function canon(term) {
if (!term) {
return term;
}
var y = this.redirections[term.hashString()];
if (!y) {
return term;
}
return y;
}
}, {
key: "check",
value: function check() {
this.checkStatementList(this.statements);
for (var p = 0; p < 4; p++) {
var ix = this.index[p];
for (var key in ix) {
if (ix.hasOwnProperty(key)) {
this.checkStatementList(ix[key], p);
}
}
}
}
/**
* Self-consistency checking for diagnostis only
* Is each statement properly indexed?
*/
}, {
key: "checkStatementList",
value: function checkStatementList(sts, from) {
var names = ['subject', 'predicate', 'object', 'why'];
var origin = ' found in ' + names[from] + ' index.';
var st;
for (var j = 0; j < sts.length; j++) {
st = sts[j];
var term = [st.subject, st.predicate, st.object, st.why];
var arrayContains = function arrayContains(a, x) {
for (var i = 0; i < a.length; i++) {
if (a[i].subject.sameTerm(x.subject) && a[i].predicate.sameTerm(x.predicate) && a[i].object.sameTerm(x.object) && a[i].why.sameTerm(x.why)) {
return true;
}
}
};
for (var p = 0; p < 4; p++) {
var c = this.canon(term[p]);
var h = c.hashString();
if (!this.index[p][h]) {// throw new Error('No ' + name[p] + ' index for statement ' + st + '@' + st.why + origin)
} else {
if (!arrayContains(this.index[p][h], st)) {// throw new Error('Index for ' + name[p] + ' does not have statement ' + st + '@' + st.why + origin)
}
}
}
if (!arrayContains(this.statements, st)) {
throw new Error('Statement list does not statement ' + st + '@' + st.why + origin);
}
}
}
}, {
key: "close",
value: function close() {
return this;
}
/**
* replaces @template with @target and add appropriate triples (no triple
* removed)
* one-direction replication
* @method copyTo
*/
}, {
key: "copyTo",
value: function copyTo(template, target, flags) {
if (!flags) flags = [];
var statList = this.statementsMatching(template);
if (ArrayIndexOf(flags, 'two-direction') !== -1) {
statList.concat(this.statementsMatching(undefined, undefined, template));
}
for (var i = 0; i < statList.length; i++) {
var st = statList[i];
switch (st.object.termType) {
case 'NamedNode':
this.add(target, st.predicate, st.object);
break;
case 'Literal':
case 'BlankNode':
case 'Collection':
this.add(target, st.predicate, st.object.copy(this));
}
if (ArrayIndexOf(flags, 'delete') !== -1) {
this.remove(st);
}
}
}
/**
* simplify graph in store when we realize two identifiers are equivalent
* We replace the bigger with the smaller.
*/
}, {
key: "equate",
value: function equate(u1, u2) {
// log.warn("Equating "+u1+" and "+u2); // @@
// @@JAMBO Must canonicalize the uris to prevent errors from a=b=c
// 03-21-2010
u1 = this.canon(u1);
u2 = this.canon(u2);
var d = u1.compareTerm(u2);
if (!d) {
return true; // No information in {a = a}
} // var big
// var small
if (d < 0) {
// u1 less than u2
return this.replaceWith(u2, u1);
} else {
return this.replaceWith(u1, u2);
}
}
}, {
key: "formula",
value: function formula(features) {
return new IndexedFormula(features);
}
/**
* Returns the number of statements contained in this IndexedFormula.
* (Getter proxy to this.statements).
* Usage:
* ```
* var kb = rdf.graph()
* kb.length // -> 0
* ```
* @returns {Number}
*/
}, {
key: "match",
/**
* Returns any quads matching the given arguments.
* Standard RDFJS Taskforce method for Source objects, implemented as an
* alias to `statementsMatching()`
* @method match
* @param subject {Node}
* @param predicate {Node}
* @param object {Node}
* @param graph {NamedNode}
*/
value: function match(subject, predicate, object, graph) {
return this.statementsMatching(subject, predicate, object, graph);
}
/**
* Find out whether a given URI is used as symbol in the formula
*/
}, {
key: "mentionsURI",
value: function mentionsURI(uri) {
var hash = '<' + uri + '>';
return !!this.subjectIndex[hash] || !!this.objectIndex[hash] || !!this.predicateIndex[hash];
} // Existentials are BNodes - something exists without naming
}, {
key: "newExistential",
value: function newExistential(uri) {
if (!uri) return this.bnode();
var x = this.sym(uri);
return this.declareExistential(x);
}
}, {
key: "newPropertyAction",
value: function newPropertyAction(pred, action) {
// log.debug("newPropertyAction: "+pred)
var hash = pred.hashString();
if (!this.propertyActions[hash]) {
this.propertyActions[hash] = [];
}
this.propertyActions[hash].push(action); // Now apply the function to to statements already in the store
var toBeFixed = this.statementsMatching(undefined, pred, undefined);
var done = false;
for (var i = 0; i < toBeFixed.length; i++) {
// NOT optimized - sort toBeFixed etc
done = done || action(this, toBeFixed[i].subject, pred, toBeFixed[i].object);
}
return done;
} // Universals are Variables
}, {
key: "newUniversal",
value: function newUniversal(uri) {
var x = this.sym(uri);
if (!this._universalVariables) this._universalVariables = [];
this._universalVariables.push(x);
return x;
} // convenience function used by N3 parser
}, {
key: "variable",
value: function variable(name) {
return new Variable(name);
}
/**
* Find an unused id for a file being edited: return a symbol
* (Note: Slow iff a lot of them -- could be O(log(k)) )
*/
}, {
key: "nextSymbol",
value: function nextSymbol(doc) {
for (var i = 0;; i++) {
var uri = doc.uri + '#n' + i;
if (!this.mentionsURI(uri)) return this.sym(uri);
}
}
}, {
key: "query",
value: function query(myQuery, callback, fetcher, onDone) {
var indexedFormulaQuery = require('./query').indexedFormulaQuery;
return indexedFormulaQuery.call(this, myQuery, callback, fetcher, onDone);
}
/**
* Finds a statement object and removes it
*/
}, {
key: "remove",
value: function remove(st) {
if (st instanceof Array) {
for (var i = 0; i < st.length; i++) {
this.remove(st[i]);
}
return this;
}
if (st instanceof IndexedFormula) {
return this.remove(st.statements);
}
var sts = this.statementsMatching(st.subject, st.predicate, st.object, st.why, true);
if (!sts.length) {
throw new Error('Statement to be removed is not on store: ' + st);
}
this.removeStatement(sts[0]);
return this;
}
/**
* Removes all statemnts in a doc
*/
}, {
key: "removeDocument",
value: function removeDocument(doc) {
var sts = this.statementsMatching(undefined, undefined, undefined, doc).slice(); // Take a copy as this is the actual index
for (var i = 0; i < sts.length; i++) {
this.removeStatement(sts[i]);
}
return this;
}
/**
* remove all statements matching args (within limit) *
*/
}, {
key: "removeMany",
value: function removeMany(subj, pred, obj, why, limit) {
// log.debug("entering removeMany w/ subj,pred,obj,why,limit = " + subj +", "+ pred+", " + obj+", " + why+", " + limit)
var sts = this.statementsMatching(subj, pred, obj, why, false); // This is a subtle bug that occcured in updateCenter.js too.
// The fact is, this.statementsMatching returns this.whyIndex instead of a copy of it
// but for perfromance consideration, it's better to just do that
// so make a copy here.
var statements = [];
for (var i = 0; i < sts.length; i++) {
statements.push(sts[i]);
}
if (limit) statements = statements.slice(0, limit);
for (i = 0; i < statements.length; i++) {
this.remove(statements[i]);
}
}
}, {
key: "removeMatches",
value: function removeMatches(subject, predicate, object, why) {
this.removeStatements(this.statementsMatching(subject, predicate, object, why));
return this;
}
/**
* Remove a particular statement object from the store
*
* st a statement which is already in the store and indexed.
* Make sure you only use this for these.
* Otherwise, you should use remove() above.
*/
}, {
key: "removeStatement",
value: function removeStatement(st) {
// log.debug("entering remove w/ st=" + st)
var term = [st.subject, st.predicate, st.object, st.why];
for (var p = 0; p < 4; p++) {
var c = this.canon(term[p]);
var h = c.hashString();
if (!this.index[p][h]) {// log.warn ("Statement removal: no index '+p+': "+st)
} else {
RDFArrayRemove(this.index[p][h], st);
}
}
RDFArrayRemove(this.statements, st);
return this;
}
}, {
key: "removeStatements",
value: function removeStatements(sts) {
for (var i = 0; i < sts.length; i++) {
this.remove(sts[i]);
}
return this;
}
/**
* Replace big with small, obsoleted with obsoleting.
*/
}, {
key: "replaceWith",
value: function replaceWith(big, small) {
// log.debug("Replacing "+big+" with "+small) // @@
var oldhash = big.hashString();
var newhash = small.hashString();
var moveIndex = function moveIndex(ix) {
var oldlist = ix[oldhash];
if (!oldlist) {
return; // none to move
}
var newlist = ix[newhash];
if (!newlist) {
ix[newhash] = oldlist;
} else {
ix[newhash] = oldlist.concat(newlist);
}
delete ix[oldhash];
}; // the canonical one carries all the indexes
for (var i = 0; i < 4; i++) {
moveIndex(this.index[i]);
}
this.redirections[oldhash] = small;
if (big.uri) {
// @@JAMBO: must update redirections,aliases from sub-items, too.
if (!this.aliases[newhash]) {
this.aliases[newhash] = [];
}
this.aliases[newhash].push(big); // Back link
if (this.aliases[oldhash]) {
for (i = 0; i < this.aliases[oldhash].length; i++) {
this.redirections[this.aliases[oldhash][i].hashString()] = small;
this.aliases[newhash].push(this.aliases[oldhash][i]);
}
}
this.add(small, this.sym('http://www.w3.org/2007/ont/link#uri'), big, Statement.defaultGraph); // If two things are equal, and one is requested, we should request the other.
if (this.fetcher) {
this.fetcher.nowKnownAs(big, small);
}
}
moveIndex(this.classActions);
moveIndex(this.propertyActions); // log.debug("Equate done. "+big+" to be known as "+small)
return true; // true means the statement does not need to be put in
}
/**
* Return all equivalent URIs by which this is known
*/
}, {
key: "allAliases",
value: function allAliases(x) {
var a = this.aliases[this.canon(x).hashString()] || [];
a.push(this.canon(x));
return a;
}
/**
* Compare by canonical URI as smushed
*/
}, {
key: "sameThings",
value: function sameThings(x, y) {
if (x.sameTerm(y)) {
return true;
}
var x1 = this.canon(x); // alert('x1='+x1)
if (!x1) return false;
var y1 = this.canon(y); // alert('y1='+y1); //@@
if (!y1) return false;
return x1.uri === y1.uri;
}
}, {
key: "setPrefixForURI",
value: function setPrefixForURI(prefix, nsuri) {
// TODO: This is a hack for our own issues, which ought to be fixed
// post-release
// See http://dig.csail.mit.edu/cgi-bin/roundup.cgi/$rdf/issue227
if (prefix === 'tab' && this.namespaces['tab']) {
return;
} // There are files around with long badly generated prefixes like this
if (prefix.slice(0, 2) === 'ns' || prefix.slice(0, 7) === 'default') {
return;
}
this.namespaces[prefix] = nsuri;
}
/** Search the Store
*
* ALL CONVENIENCE LOOKUP FUNCTIONS RELY ON THIS!
* @param {Node} subject - A node to search for as subject, or if null, a wildcard
* @param {Node} predicate - A node to search for as predicate, or if null, a wildcard
* @param {Node} object - A node to search for as object, or if null, a wildcard
* @param {Node} graph - A node to search for as graph, or if null, a wildcard
* @param {Boolean?} justOne - flag - stop when found one rather than get all of them?
* @returns {Array<Node>} - An array of nodes which match the wildcard position
*/
}, {
key: "statementsMatching",
value: function statementsMatching(subj, pred, obj, why, justOne) {
// log.debug("Matching {"+subj+" "+pred+" "+obj+"}")
var pat = [subj, pred, obj, why];
var pattern = [];
var hash = [];
var wild = []; // wildcards
var given = []; // Not wild
var p;
var list;
for (p = 0; p < 4; p++) {
pattern[p] = this.canon(pat[p]);
if (!pattern[p]) {
wild.push(p);
} else {
given.push(p);
hash[p] = pattern[p].hashString();
}
}
if (given.length === 0) {
return this.statements;
}
if (given.length === 1) {
// Easy too, we have an index for that
p = given[0];
list = this.index[p][hash[p]];
if (list && justOne) {
if (list.length > 1) {
list = list.slice(0, 1);
}
}
list = list || [];
return list;
} // Now given.length is 2, 3 or 4.
// We hope that the scale-free nature of the data will mean we tend to get
// a short index in there somewhere!
var best = 1e10; // really bad
var iBest;
var i;
for (i = 0; i < given.length; i++) {
p = given[i]; // Which part we are dealing with
list = this.index[p][hash[p]];
if (!list) {
return []; // No occurrences
}
if (list.length < best) {
best = list.length;
iBest = i; // (not p!)
}
} // Ok, we have picked the shortest index but now we have to filter it
var pBest = given[iBest];
var possibles = this.index[pBest][hash[pBest]];
var check = given.slice(0, iBest).concat(given.slice(iBest + 1)); // remove iBest
var results = [];
var parts = ['subject', 'predicate', 'object', 'why'];
for (var j = 0; j < possibles.length; j++) {
var st = possibles[j];
for (i = 0; i < check.length; i++) {
// for each position to be checked
p = check[i];
if (this.canon(st[parts[p]]) !== pattern[p]) {
st = null;
break;
}
}
if (st != null) {
results.push(st);
if (justOne) break;
}
}
return results;
}
/**
* A list of all the URIs by which this thing is known
*/
}, {
key: "uris",
value: function uris(term) {
var cterm = this.canon(term);
var terms = this.aliases[cterm.hashString()];
if (!cterm.uri) return [];
var res = [cterm.uri];
if (terms) {
for (var i = 0; i < terms.length; i++) {
res.push(terms[i].uri);
}
}
return res;
}
}, {
key: "length",
get: function get() {
return this.statements.length;
}
}]);
return IndexedFormula;
}(Formula);
IndexedFormula.defaultGraphURI = Statement.defaultGraph;
IndexedFormula.handleRDFType = handleRDFType;
module.exports = IndexedFormula;