From 87b420f908df17344a21560439beaaf0cd4ee2a5 Mon Sep 17 00:00:00 2001 From: Julian Gonggrijp Date: Tue, 19 Oct 2021 15:03:45 +0200 Subject: [PATCH] Generalize ItemGraph, consistently query the same graph (#501 #163) --- frontend/src/common-adapters/item-graph.ts | 35 ++++++++++++++++--- .../src/explorer/explorer-event-controller.ts | 4 +-- frontend/src/global/source-list.ts | 5 +-- frontend/src/panel-browse/browse-view.ts | 9 ++--- .../src/semantic-search/filter-input-view.ts | 2 +- frontend/src/utilities/prefetch-utilities.ts | 3 +- 6 files changed, 43 insertions(+), 15 deletions(-) diff --git a/frontend/src/common-adapters/item-graph.ts b/frontend/src/common-adapters/item-graph.ts index a6699da3..58c11be8 100644 --- a/frontend/src/common-adapters/item-graph.ts +++ b/frontend/src/common-adapters/item-graph.ts @@ -1,11 +1,11 @@ -import { extend } from 'lodash'; +import { extend, result, isString } from 'lodash'; import { item } from '../common-rdf/ns'; import Node from '../common-rdf/node'; import Graph from '../common-rdf/graph'; import { asURI } from '../utilities/linked-data-utilities'; -import { sparqlRoot } from 'config.json'; +import { nsRoot, sparqlRoot } from 'config.json'; /** * Using query parameters is DEPRECATED in favor of SPARQL queries. @@ -84,9 +84,36 @@ function isLiteralQuery(params: QueryParams): params is QueryParamsLiteral { * See also the query and sparqlQuery methods below for querying the server. */ export default class ItemGraph extends Graph { + sparqlEndpoint: string; + // Only defined if a query has been issued. promise: JQuery.jqXHR; + /** + * We allow client code to override `this.url` through the `graph` option. + For convenience, it is also possible to pass just the graph URL directly + as the only argument. + * + * From `this.url`, we derive the matching `this.sparqlEndpoint`. + */ + constructor(graph: string); + constructor(models?: Node[] | Object[], options?: any); + constructor(models?: Node[] | Object[] | string, options?) { + if (isString(models)) { + options = { graph: models }; + models = null; + } + super(models, options); + } + + preinitialize(models?, options?: any): void { + super.preinitialize(models, options); + if (options.graph) this.url = options.graph; + const url = result(this, 'url') as string; + const graphName = url.slice(nsRoot.length, -1); + this.sparqlEndpoint = `${sparqlRoot}${graphName}/query`; + } + /** * DEPRECATED you still need this for the download parameter, but use * sparqlQuery instead if you don't use that parameter. @@ -113,8 +140,8 @@ export default class ItemGraph extends Graph { * result from the given CONSTRUCT query. For best results, make sure that * the query produces complete items. */ - sparqlQuery(query: string, fromGraph: string): JQuery.jqXHR { - return this.promise = this.fetch({ url: sparqlRoot + fromGraph, data: $.param({ query: query }), remove: false }); + sparqlQuery(query: string): JQuery.jqXHR { + return this.promise = this.fetch({ url: this.sparqlEndpoint, data: $.param({ query: query }), remove: false }); } /** diff --git a/frontend/src/explorer/explorer-event-controller.ts b/frontend/src/explorer/explorer-event-controller.ts index b887cd38..61d1332a 100644 --- a/frontend/src/explorer/explorer-event-controller.ts +++ b/frontend/src/explorer/explorer-event-controller.ts @@ -92,7 +92,7 @@ class ExplorerEventController { const items = new ItemGraph(); model.when( 'query', - (model, query) => items.sparqlQuery(modelToQuery(query), 'item/query') + (model, query) => items.sparqlQuery(modelToQuery(query)), ); if (model.isNew()) model.save(); const collection = new FlatItemCollection(items); @@ -339,7 +339,7 @@ export default ExplorerEventController; export function getItems(source: Node): ItemGraph { const sparqlItems = new ItemGraph(); let queryString = itemsForSourceQuery(asURI(source), {}); - sparqlItems.sparqlQuery(queryString, 'item/query'); + sparqlItems.sparqlQuery(queryString); return sparqlItems; } diff --git a/frontend/src/global/source-list.ts b/frontend/src/global/source-list.ts index 45c584a5..7b08ff1d 100644 --- a/frontend/src/global/source-list.ts +++ b/frontend/src/global/source-list.ts @@ -1,13 +1,14 @@ +import Collection from '../core/collection'; import ItemGraph from '../common-adapters/item-graph'; import ldChannel from '../common-rdf/radio'; -import Collection from '../core/collection'; +import { source } from '../common-rdf/ns'; import { parseResponse, nodeListFactory, userNodesFactory } from '../utilities/prefetch-utilities'; const sourceList = new Collection(); sourceList.parse = parseResponse; const getNodeList = nodeListFactory(); -const userSources = new ItemGraph(); +const userSources = new ItemGraph(source()); const getUserNodes = userNodesFactory(); /** diff --git a/frontend/src/panel-browse/browse-view.ts b/frontend/src/panel-browse/browse-view.ts index 04653acc..c23a3313 100644 --- a/frontend/src/panel-browse/browse-view.ts +++ b/frontend/src/panel-browse/browse-view.ts @@ -7,6 +7,7 @@ import { CompositeView } from "../core/view"; import { randomNodesQuery } from "../sparql/compile-query"; import explorerChannel from '../explorer/explorer-radio'; import ldChannel from '../common-rdf/radio'; +import { item, source } from '../common-rdf/ns'; import Collection from '../core/collection'; import FlatItem from '../common-adapters/flat-item-model'; @@ -36,9 +37,9 @@ export default class BrowseView extends CompositeView { queryingItems: boolean; async initialize(options: ViewOptions) { - this.sparqlItems = new ItemGraph(); - this.queryingItems = options.queryMode === 'items'? true : false; - this.endpoint = this.queryingItems? 'item/query' : 'source/query'; + this.queryingItems = options.queryMode === 'items'; + const graphName = this.queryingItems? item() : source(); + this.sparqlItems = new ItemGraph(graphName); if (options.landing) { this.title = "My " + options.queryMode; await this.getUserNodes(); @@ -64,7 +65,7 @@ export default class BrowseView extends CompositeView { async getRandomNodes(nodes: Collection) { const randomNodes = sampleSize(nodes.models, nSamples); const randomQuery = randomNodesQuery(randomNodes.slice(-randomNodes.length, -1), randomNodes.pop(), {}); - this.sparqlItems.sparqlQuery(randomQuery, this.endpoint); + this.sparqlItems.sparqlQuery(randomQuery); } async getUserNodes() { diff --git a/frontend/src/semantic-search/filter-input-view.ts b/frontend/src/semantic-search/filter-input-view.ts index 5ca60084..7a425c76 100644 --- a/frontend/src/semantic-search/filter-input-view.ts +++ b/frontend/src/semantic-search/filter-input-view.ts @@ -40,7 +40,7 @@ export default class FilterInput extends CompositeView { const rangeId = range.first().id; if (!rangeId.startsWith(xsd())) { items = new ItemGraph(); - items.sparqlQuery(filterInputQueryTemplate({ type: rangeId }), 'item/query'); + items.sparqlQuery(filterInputQueryTemplate({ type: rangeId })); this.subviews.push(new Select2Picker({ collection: items })); } } diff --git a/frontend/src/utilities/prefetch-utilities.ts b/frontend/src/utilities/prefetch-utilities.ts index 1b1b40c1..9a418908 100644 --- a/frontend/src/utilities/prefetch-utilities.ts +++ b/frontend/src/utilities/prefetch-utilities.ts @@ -14,12 +14,11 @@ export function userNodesFactory() { function getUserNodes(userNodes: ItemGraph, queryingItems: boolean): PromiseLike { if (!promise) { - const endpoint = queryingItems ? 'item/query' : 'source/query'; promise = nodesByUserQuery(queryingItems, {}).then( (query) => { if (!query) { return handleError('user not authenticated'); } - return userNodes.sparqlQuery(query, endpoint).then( + return userNodes.sparqlQuery(query).then( () => handleSuccess(userNodes), handleError ); });