UNPKG

sparnatural

Version:

Visual client-side SPARQL query builder and knowledge graph exploration tool

255 lines 11.7 kB
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _SparqlTreeDataProvider_instances, _SparqlTreeDataProvider_getParser; import { sameTerm } from "../../SparnaturalQueryIfc"; export class BaseSparqlListDataProvider { constructor(sparqlHandler) { this.sparqlHandler = sparqlHandler; } init(lang, defaultLang, typePredicate) { this.lang = lang; this.defaultLang = defaultLang; this.typePredicate = typePredicate; } doExecuteWithCallback(sparqlQuery, callback, errorCallback) { // 2. execute it this.sparqlHandler.executeSparql(sparqlQuery, (data) => { // 3. parse the results let result = new Array; for (let index = 0; index < data.results.bindings.length; index++) { const solution = data.results.bindings[index]; // this is to avoid corner-cases with GraphDB queries returning only count=0 in aggregation queries. // we need at least 2 bindings anyway if (Object.keys(solution).length > 1) { if (solution.uri) { // if we find a "uri" column... // read uri key & label key result[result.length] = { term: solution.uri, label: solution.label.value, group: solution.group?.value, itemLabel: solution.itemLabel?.value }; } else if (solution.value) { // if we find a "value" column... // read value key & label key result[result.length] = { term: solution.value, label: solution.label.value, group: solution.group?.value, itemLabel: solution.itemLabel?.value }; } else { // try to determine the payload column by taking the column other than label let columnName = this.getRdfTermColumn(solution); if (columnName) { result[result.length] = { term: solution[columnName], label: solution.label.value, group: solution.group?.value, itemLabel: solution.itemLabel?.value }; } else { throw Error("Could not determine which column to read from the result set"); } } } } // 4. call the callback callback(result); }, errorCallback); } getRdfTermColumn(aBindingSet) { let foundKey = undefined; for (const key of Object.keys(aBindingSet)) { if (key != "label") { if (!foundKey) { foundKey = key; } else { // it means there are more than one column, don't know which one to take, break return undefined; } } } return foundKey; } } /** * Implementation of ListDataProviderIfc that executes a SPARQL query against an endpoint, * and read the 'uri' and 'label' columns. */ export class SparqlListDataProvider extends BaseSparqlListDataProvider { constructor(sparqlHandler, queryBuilder) { super(sparqlHandler); this.queryBuilder = queryBuilder; } getListContent(domainType, predicate, rangeType, callback, errorCallback) { // 1. create the SPARQL let sparql = this.queryBuilder.buildSparqlQuery(domainType, predicate, rangeType, this.lang, this.defaultLang, this.typePredicate); // 2. execute it super.doExecuteWithCallback(sparql, callback, errorCallback); } } export class SparqlValuesListDataProvider extends BaseSparqlListDataProvider { constructor(sparqlHandler, queryBuilder) { super(sparqlHandler); this.queryBuilder = queryBuilder; } getListContent(values, callback, errorCallback) { // 1. create the SPARQL let sparql = this.queryBuilder.buildSparqlQuery(values, this.lang, this.defaultLang, this.typePredicate); // 2. execute it super.doExecuteWithCallback(sparql, callback, errorCallback); } } /** * Implementation of AutocompleteDataProviderIfc that executes a SPARQL query against an endpoint, * and read the 'uri' and 'label' columns. */ export class SparqlAutocompleDataProvider { constructor(sparqlHandler, queryBuilder) { this.queryBuilder = queryBuilder; this.sparqlHandler = sparqlHandler; } init(lang, defaultLang, typePredicate) { this.lang = lang; this.defaultLang = defaultLang; this.typePredicate = typePredicate; } getAutocompleteSuggestions(domain, predicate, range, key, callback, errorCallback) { if (key.startsWith("http") && SparqlAutocompleDataProvider.isValidUrl(key, ["http", "https"])) { // valid URI given, return it directly let result = new Array; result.push({ term: { type: "uri", value: key }, label: key }); callback(result); return; } // 1. create the SPARQL let sparql = this.queryBuilder.buildSparqlQuery(domain, predicate, range, key, this.lang, this.defaultLang, this.typePredicate); // 2. execute it this.sparqlHandler.executeSparql(sparql, (data) => { // 3. parse the results let result = new Array; for (let index = 0; index < data.results.bindings.length; index++) { const solution = data.results.bindings[index]; if (solution.uri) { // read uri key & label key result[result.length] = { term: solution.uri, label: solution.label.value, group: solution.group?.value }; } else if (solution.value) { result[result.length] = { term: solution.value, label: solution.label.value, group: solution.group?.value }; } else { // try to determine the payload column by taking the column other than label let columnName = this.getRdfTermColumn(solution); if (columnName) { result[result.length] = { term: solution[columnName], label: solution.label.value }; } else { throw Error("Could not determine which column to read from the result set"); } } } // 4. call the callback callback(result); }, errorCallback); } getRdfTermColumn(aBindingSet) { let foundKey = undefined; for (const key of Object.keys(aBindingSet)) { if (key != "label") { if (!foundKey) { foundKey = key; } else { // it means there are more than one column, don't know which one to take, break return undefined; } return foundKey; } } } static isValidUrl(s, protocols) { try { let url = new URL(s); return protocols ? url.protocol ? protocols.map(x => `${x.toLowerCase()}:`).includes(url.protocol) : false : true; } catch (err) { return false; } } ; } export class SparqlTreeDataProvider { constructor(sparqlHandler, queryBuilder) { _SparqlTreeDataProvider_instances.add(this); this.queryBuilder = queryBuilder; this.sparqlHandler = sparqlHandler; } init(lang, defaultLang, typePredicate) { this.lang = lang; this.defaultLang = defaultLang; this.typePredicate = typePredicate; } getRoots(domainType, predicate, rangeType, callback, errorCallback) { // 1. create the SPARQL let sparql = this.queryBuilder.buildRootsSparqlQuery(domainType, predicate, rangeType, this.lang, this.defaultLang, this.typePredicate); // 2. execute it this.sparqlHandler.executeSparql(sparql, __classPrivateFieldGet(this, _SparqlTreeDataProvider_instances, "m", _SparqlTreeDataProvider_getParser).call(this, callback), errorCallback); } getChildren(node, domainType, predicate, rangeType, callback, errorCallback) { // 1. create the SPARQL let sparql = this.queryBuilder.buildChildrenSparqlQuery(node, domainType, predicate, rangeType, this.lang, this.defaultLang, this.typePredicate); // 2. execute it this.sparqlHandler.executeSparql(sparql, __classPrivateFieldGet(this, _SparqlTreeDataProvider_instances, "m", _SparqlTreeDataProvider_getParser).call(this, callback), errorCallback); } } _SparqlTreeDataProvider_instances = new WeakSet(), _SparqlTreeDataProvider_getParser = function _SparqlTreeDataProvider_getParser(callback) { return (data) => { // 3. parse the results let result = new Array; for (let index = 0; index < data.results.bindings.length; index++) { const solution = data.results.bindings[index]; result[result.length] = { term: solution.uri, label: solution.label.value, itemLabel: solution.itemLabel?.value, // make sure to parse the value as a boolean so that it is not a string // we also test on "1" because Virtuoso returns this as a result instead of a true boolean hasChildren: solution.hasChildren ? ((solution.hasChildren.value === "true" || solution.hasChildren.value == 1) ? true : false) : true, disabled: solution.count ? solution.count.value == 0 : false }; } // 4. call the callback callback(result); }; }; /** * @param items Merges the datasource items based on their equality, in the case that multiple groups * (= multiple datasets) return the same RDF term (= the same URI or literal value). In that case a single result is kept, * with a group that is the concatenation of the groups of the merged items. * @returns a new list of datasource items in which the items have been merge based on their rdfTerm equality. */ export function mergeDatasourceResults(items) { let result = new Array(); // iterate on each item items.forEach(item => { // if it wasn't already added... if (!result.some(itemInResult => sameTerm(itemInResult.term, item.term))) { // find all items with the same URI let sameTerms = items.filter(i => sameTerm(item.term, i.term)); // add the first identical item of this in our result table, with a merged group let newTerm = { term: sameTerms[0].term, label: sameTerms[0].label, itemLabel: sameTerms[0].itemLabel, group: sameTerms.map(i => i.group).join(" + ") }; result.push(newTerm); } }); return result; } //# sourceMappingURL=SparqlDataProviders.js.map