Skip to content

Commit

Permalink
feat(component): get component values and min/max values
Browse files Browse the repository at this point in the history
  • Loading branch information
vhf committed Sep 18, 2019
1 parent 67beba7 commit cefd4e5
Show file tree
Hide file tree
Showing 3 changed files with 272 additions and 8 deletions.
32 changes: 32 additions & 0 deletions examples/component-values-min-max.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// run this example with: $ ts-node examples/component-values.ts
import { inspect } from "util";
import { DataCubeEntryPoint } from "../src/entrypoint";

function prettyPrint(obj) {
return inspect(obj, false, 10000, true);
}

(async () => {
const entryPoint = new DataCubeEntryPoint("https://ld.stadt-zuerich.ch/query");
const dataCubes = await entryPoint.dataCubes();
const datacube = dataCubes.find((cube) => cube.iri.endsWith("BEW-RAUM-ZEIT"));

const dimensions = await datacube.dimensions();
const time = dimensions.find((dimension) => dimension.iri.value.endsWith("/ZEIT"));
const timeMinMax = await datacube.componentMinMax(time);
/*
{
min: Literal {
value: '1408-12-31',
datatype: NamedNode { value: 'http://www.w3.org/2001/XMLSchema#date' },
language: ''
},
max: Literal {
value: '2017-12-31',
datatype: NamedNode { value: 'http://www.w3.org/2001/XMLSchema#date' },
language: ''
}
}
*/
console.log(prettyPrint(timeMinMax));
})();
110 changes: 110 additions & 0 deletions examples/component-values.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// run this example with: $ ts-node examples/component-values.ts
import { inspect } from "util";
import { DataCubeEntryPoint } from "../src/entrypoint";

function prettyPrint(obj) {
return inspect(obj, false, 10000, true);
}
function printTitle(str) {
return `\n\n---- ${str} ----\n`;
}

(async () => {
// instantiate an RDF Data Cube
const entryPoint = new DataCubeEntryPoint(
"https://trifid-lindas.test.cluster.ldbar.ch/query",
{ languages: ["de"] },
);
const dataCubes = await entryPoint.dataCubes();
const datacube = dataCubes[0];

const dimensions = await datacube.dimensions();

const sizeClasses = dimensions[1];
console.log(prettyPrint(sizeClasses));

const values = await datacube.componentValues(sizeClasses);
console.log(prettyPrint(values));
/*
[
{
label: Literal {
value: 'Grössenklasse - Total',
datatype: NamedNode { value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString' },
language: 'de'
},
value: NamedNode { value: 'http://example.org/anzahl-forstbetriebe/property/1/0' }
},
{
label: Literal {
value: '< 50 ha',
datatype: NamedNode { value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString' },
language: 'de'
},
value: NamedNode { value: 'http://example.org/anzahl-forstbetriebe/property/1/1' }
},
{
label: Literal {
value: '50 - 100 ha',
datatype: NamedNode { value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString' },
language: 'de'
},
value: NamedNode { value: 'http://example.org/anzahl-forstbetriebe/property/1/2' }
},
{
label: Literal {
value: '101 - 200 ha',
datatype: NamedNode { value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString' },
language: 'de'
},
value: NamedNode { value: 'http://example.org/anzahl-forstbetriebe/property/1/3' }
},
{
label: Literal {
value: '201 - 500 ha',
datatype: NamedNode { value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString' },
language: 'de'
},
value: NamedNode { value: 'http://example.org/anzahl-forstbetriebe/property/1/4' }
},
{
label: Literal {
value: '501 - 1000 ha',
datatype: NamedNode { value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString' },
language: 'de'
},
value: NamedNode { value: 'http://example.org/anzahl-forstbetriebe/property/1/5' }
},
{
label: Literal {
value: '1001 - 5000 ha',
datatype: NamedNode { value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString' },
language: 'de'
},
value: NamedNode { value: 'http://example.org/anzahl-forstbetriebe/property/1/6' }
},
{
label: Literal {
value: '> 5000 ha',
datatype: NamedNode { value: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString' },
language: 'de'
},
value: NamedNode { value: 'http://example.org/anzahl-forstbetriebe/property/1/7' }
}
]
*/
console.log(prettyPrint(values
.map(((row) => `"${row.label.value}"${row.label.language ? `@${row.label.language}` : ""}`))));
/*
[
'"Grössenklasse - Total"@de',
'"< 50 ha"@de',
'"50 - 100 ha"@de',
'"101 - 200 ha"@de',
'"201 - 500 ha"@de',
'"501 - 1000 ha"@de',
'"1001 - 5000 ha"@de',
'"> 5000 ha"@de'
]
*/
})();
138 changes: 130 additions & 8 deletions src/datacube.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { namedNode, variable } from "@rdfjs/data-model";
import { NamedNode, Term } from "rdf-js";
import namespace from "@rdfjs/namespace";
import { Literal, NamedNode, Term } from "rdf-js";
import { Generator as SparqlGenerator } from "sparqljs";
import { Attribute, Component, Dimension, Measure } from "./components";
import { EntryPointOptions } from "./entrypoint";
Expand Down Expand Up @@ -56,6 +57,8 @@ export interface DataCubeOptions extends EntryPointOptions {
graphIri: NamedNode;
}

const cube = namespace("http://purl.org/linked-data/cube#");

/**
* @class DataCube
*/
Expand Down Expand Up @@ -178,6 +181,125 @@ export class DataCube {
return new Query(this, opts);
}

public async componentValues(component: Component): Promise<Array<{label: Literal, value: NamedNode}>> {
if (!component || !component.componentType) {
throw new Error(`datacube#componentValues expects valid component, got ${component} instead`);
}
const binding = variable("value");
const labelBinding = variable("label");
const observation = variable("observation");

const query: SelectQuery = {
prefixes,
queryType: "SELECT",
variables: [binding, labelBinding],
distinct: true,
from: { default: [namedNode(this.graphIri)], named: [] },
where: [
{
type: "bgp",
triples: [
{
subject: observation,
predicate: namedNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
object: cube("Observation"),
},
{
subject: observation,
predicate: component.iri,
object: binding,
},
{
subject: observation,
predicate: cube("dataSet"),
object: namedNode(this.iri),
},
],
},
...generateLangOptionals(binding, labelBinding, this.languages),
generateLangCoalesce(labelBinding, this.languages),
],
type: "query",
};

const generator = new SparqlGenerator({ allPrefixes: true });
const sparql = generator.stringify(query);
return await this.fetcher.select(sparql);
}

public async componentMinMax(component: Component): Promise<{min: Literal, max: Literal}|null> {
if (!component || !component.componentType) {
throw new Error(`datacube#componentMinMax expects valid component, got ${component} instead`);
}
const binding = variable("value");
const observation = variable("observation");

const query: SelectQuery = {
prefixes,
queryType: "SELECT",
variables: [
{
expression: {
expression: binding,
type: "aggregate",
aggregation: "min",
distinct: false,
},
variable: variable("min"),
},
{
expression: {
expression: binding,
type: "aggregate",
aggregation: "max",
distinct: false,
},
variable: variable("max"),
},
],
from: { default: [namedNode(this.graphIri)], named: [] },
where: [
{
type: "bgp",
triples: [
{
subject: observation,
predicate: namedNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
object: cube("Observation"),
},
{
subject: observation,
predicate: component.iri,
object: binding,
},
{
subject: observation,
predicate: cube("dataSet"),
object: namedNode(this.iri),
},
],
},
{
type: "filter",
expression: {
type: "operation",
operator: "isliteral",
args: [binding],
},
},
],
type: "query",
};

const generator = new SparqlGenerator({ allPrefixes: true });
const sparql = generator.stringify(query);
const results = await this.fetcher.select(sparql);
if (results.length) {
return results[0];
}
return null;
}

private async components() {
if (this.componentsLoaded) {
return;
Expand All @@ -194,24 +316,24 @@ export class DataCube {
variable("kind"),
labelBinding,
],
from: { default: [ namedNode(this.graphIri) ], named: [] },
from: { default: [namedNode(this.graphIri)], named: [] },
where: [
{
type: "bgp",
triples: [
{
subject: namedNode(this.iri),
predicate: namedNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
object: namedNode("http://purl.org/linked-data/cube#DataSet"),
object: cube("DataSet"),
},
{
subject: namedNode(this.iri),
predicate: {
type: "path",
pathType: "/",
items: [
namedNode("http://purl.org/linked-data/cube#structure"),
namedNode("http://purl.org/linked-data/cube#component"),
cube("structure"),
cube("component"),
],
},
object: variable("componentSpec"),
Expand All @@ -231,9 +353,9 @@ export class DataCube {
args: [
variable("kind"),
[
namedNode("http://purl.org/linked-data/cube#attribute"),
namedNode("http://purl.org/linked-data/cube#dimension"),
namedNode("http://purl.org/linked-data/cube#measure"),
cube("attribute"),
cube("dimension"),
cube("measure"),
],
],
},
Expand Down

0 comments on commit cefd4e5

Please sign in to comment.