Skip to content

Commit

Permalink
add use_default_graph_as_union
Browse files Browse the repository at this point in the history
  • Loading branch information
Hofstetter Benjamin (extern) committed Feb 17, 2025
1 parent ee93be8 commit 61dda03
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 23 deletions.
18 changes: 18 additions & 0 deletions samples/oxi-test.sparqlbook
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,23 @@
"language": "sparql",
"value": "# [endpoint=./rdf/a.ttl]\n\n\nDESCRIBE <http://example.org/A>\n",
"metadata": {}
},
{
"kind": 2,
"language": "sparql",
"value": "# [endpoint=./rdf/a.trig]\n# [use_default_graph_as_union=true]\n\n\nSELECT * WHERE {\n ?s ?p ?o\n}",
"metadata": {}
},
{
"kind": 2,
"language": "sparql",
"value": "# [endpoint=./rdf/a.trig]\n\n\nSELECT * WHERE {\n ?s ?p ?o\n}",
"metadata": {}
},
{
"kind": 2,
"language": "sparql",
"value": "# [endpoint=./rdf/a.trig]\n# [use_default_graph_as_union=false]\n\n\nSELECT * WHERE {\n ?s ?p ?o\n}",
"metadata": {}
}
]
14 changes: 14 additions & 0 deletions samples/rdf/a.trig
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@prefix ex: <http://example.org/> .

# Default graph
ex:subjectDG ex:predicate1 ex:object1 .

# Named graph 1
GRAPH <http://example.org/graph1> {
ex:subjectG1 ex:predicate2 ex:object2 .
}

# Named graph 2
GRAPH <http://example.org/graph2> {
ex:subjectG2 ex:predicate3 ex:object3 .
}
4 changes: 4 additions & 0 deletions src/extension/endpoint/file-endpoint/file-endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ export class FileEndpoint extends Endpoint {
return this.#url;
}

useDefaultGraphAsUnion() {
this.#store.setQueryOptions({ use_default_graph_as_union: true });
}

/**
* Adds a file to the endpoint.
*
Expand Down
21 changes: 20 additions & 1 deletion src/extension/endpoint/model/sparql-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { window } from "vscode";

import { SPARQLQueryKind } from "../enum/sparql-query-kind";
import { getSPARQLQueryKind } from "../sparql-utils";
import * as glob from 'glob';

export class SparqlQuery {
readonly #queryString: string;
Expand Down Expand Up @@ -64,6 +63,26 @@ export class SparqlQuery {
return this.#extractedEndpointCollection;
}

extractQueryOptions(): Map<string, string> {
const commentLines = this.#queryString
.split("\n")
.map((l) => l.trim())
.filter((l) => l.startsWith("#"));
const queryOptionsMap = new Map<string, string>();
commentLines.forEach((comment: string) => {
const optionExp = /\[([a-zA-Z_]+)=([^\]]+)\]/gm;
const match = optionExp.exec(comment);

if (match) {
if (match[1] !== 'endpoint') {
queryOptionsMap.set(match[1], match[2]);
}
}

});
return queryOptionsMap;

}
}


Expand Down
11 changes: 11 additions & 0 deletions src/extension/notebook/sparql-notebook-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { shrink } from '@zazuko/prefixes';
import { EndpointKind, SparqlQuery } from '../endpoint/model/sparql-query';
import { MimeType } from '../enum/mime-type';
import path = require('path');
import { Option } from '@vscode/webview-ui-toolkit';
export class SparqlNotebookController {
readonly controllerId = `${extensionId}-controller-id`;
readonly notebookType = extensionId;
Expand Down Expand Up @@ -241,6 +242,8 @@ export class SparqlNotebookController {
*/
private async _getDocumentOrConnectionClient(cell: SparqlNotebookCell, sparqlQuery: SparqlQuery): Promise<Endpoint | null> {
const documentEndpoints = sparqlQuery.extractEndpoint().getEndpoints();
const queryOptions = sparqlQuery.extractQueryOptions();


if (documentEndpoints.length > 0) {

Expand All @@ -254,6 +257,14 @@ export class SparqlNotebookController {
for (const extractFileEndpoint of documentEndpoints) {
await this.#loadFileToStore(extractFileEndpoint.endpoint, fileEndpoint);
}
if (queryOptions.size > 0) {
const hasUseDefaultGraphAsUnion = queryOptions.get('use_default_graph_as_union');
if (hasUseDefaultGraphAsUnion && hasUseDefaultGraphAsUnion === 'true') {
fileEndpoint.useDefaultGraphAsUnion();

}

}
return fileEndpoint;
}
}
Expand Down
64 changes: 42 additions & 22 deletions src/extension/sparql-store/sparql-store.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Quad, Store, defaultGraph } from 'oxigraph';
import { BlankNode, NamedNode, Quad, Store, defaultGraph } from 'oxigraph';
import { SPARQLQueryKind } from '../endpoint/enum/sparql-query-kind';
import { SparqlQuery } from '../endpoint/model/sparql-query';

Expand All @@ -10,18 +10,35 @@ export enum RdfMimeType {
nQuads = 'application/n-quads',
}

const allowedQueryOptions = ['use_default_graph_as_union'];


interface QueryOptions {
base_iri: string, // base IRI to resolve relative IRIs in the query
use_default_graph_as_union: boolean, // the default graph in the query is the union of all the dataset graphs
default_graph: (NamedNode | BlankNode)[], // the default graph of the query is the union of the store default graph and the http://example.com graph
named_graphs: (NamedNode | BlankNode)[], // we restrict the available named graphs to the two listed
results_format: string, // the response will be serialized a string in the JSON format (media types like application/sparql-results+json also work)
}

/**
* This is the local SPARQL endpoint that is used to execute SPARQL queries on the local RDF store.
* It is based on the Oxigraph.
*/
export class SparqlStore {
// the oxigraph store
readonly #store: Store;
#queryOptions: Partial<QueryOptions> = {};


constructor() {
this.#store = new Store();
}

setQueryOptions(options: Partial<QueryOptions>) {
this.#queryOptions = { ...this.setQueryOptions, ...options };
}

/**
* Execute a SPARQL CONSTRUCT query and return the result as a turtle string.
*
Expand All @@ -33,10 +50,10 @@ export class SparqlStore {
if (query.kind !== SPARQLQueryKind.construct) {
throw new Error('Query is not a CONSTRUCT query');
}
const options = this.#queryOptions;
options.results_format = RdfMimeType.turtle;

const queryResult = this.#store.query(query.queryString, {
results_format: RdfMimeType.turtle,
}) as string;
const queryResult = this.#store.query(query.queryString, options) as string;

return queryResult;
}
Expand All @@ -53,7 +70,8 @@ export class SparqlStore {
throw new Error('Query is not a CONSTRUCT query');
}

const queryResult = this.#store.query(query.queryString) as Quad[];
const options = this.#queryOptions;
const queryResult = this.#store.query(query.queryString, options) as Quad[];

return queryResult;
}
Expand All @@ -70,9 +88,9 @@ export class SparqlStore {
throw new Error('Query is not a SELECT query');
}

const queryResult = this.#store.query(query.queryString, {
results_format: 'json',
}) as string;
const options = this.#queryOptions;
options.results_format = 'json';
const queryResult = this.#store.query(query.queryString, options) as string;

return queryResult;
}
Expand All @@ -87,9 +105,9 @@ export class SparqlStore {
if (query.kind !== SPARQLQueryKind.ask) {
throw new Error('Query is not an ASK query');
}
const result = this.#store.query(query.queryString, {
results_format: "json",
}) as string;
const options = this.#queryOptions;
options.results_format = "json";
const result = this.#store.query(query.queryString, options) as string;
return result;
}

Expand All @@ -104,9 +122,9 @@ export class SparqlStore {
throw new Error('Query is not a DESCRIBE query');
}

const queryResult = this.#store.query(query.queryString, {
results_format: RdfMimeType.turtle,
}) as string;
const options = this.#queryOptions;
options.results_format = RdfMimeType.turtle;
const queryResult = this.#store.query(query.queryString, options) as string;

return queryResult;
}
Expand All @@ -115,8 +133,8 @@ export class SparqlStore {
if (query.kind !== SPARQLQueryKind.describe) {
throw new Error('Query is not a DESCRIBE query');
}

const queryResult = this.#store.query(query.queryString) as Quad[];
const options = this.#queryOptions;
const queryResult = this.#store.query(query.queryString, options) as Quad[];

return queryResult;
}
Expand Down Expand Up @@ -163,9 +181,11 @@ export class SparqlStore {
}


/**
const fakeHttpResult = {
headers: { "content-type": "application/sparql-results+json" },
data: JSON.parse(res)
};
*/

interface QueryOptions {
base_iri: string, // base IRI to resolve relative IRIs in the query
use_default_graph_as_union: boolean, // the default graph in the query is the union of all the dataset graphs
default_graph: (NamedNode | BlankNode)[], // the default graph of the query is the union of the store default graph and the http://example.com graph
named_graphs: (NamedNode | BlankNode)[], // we restrict the available named graphs to the two listed
results_format: string, // the response will be serialized a string in the JSON format (media types like application/sparql-results+json also work)
}

0 comments on commit 61dda03

Please sign in to comment.