Skip to content

Commit

Permalink
Let formula, store/indexedFormula implement a proper datafactory
Browse files Browse the repository at this point in the history
The current implementation contains some methods which are like the spec
DataFactory interface but have small distinctions. E.g. `namedNode` is
called `sym`, `literal` accepts three rather than two arguments. This
commit applies the canonical methods of the rdfjs tf DataFactory
interface to the store. End-users can also overwrite the used factory
via a constructor argument.
  • Loading branch information
Fletcher91 committed Oct 15, 2019
1 parent 30a5bf7 commit 33bacf9
Show file tree
Hide file tree
Showing 11 changed files with 151 additions and 84 deletions.
57 changes: 57 additions & 0 deletions src/data-factory-internal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import BlankNode from './blank-node'
import DefaultGraph from './default-graph'
import Literal from './literal'
import NamedNode from './named-node'
import Statement from './statement'
import Variable from './variable'

function blankNode (value) {
return new BlankNode(value)
}

function defaultGraph () {
return new DefaultGraph()
}

function literal (value, languageOrDatatype) {
if (typeof value !== "string" && !languageOrDatatype) {
return Literal.fromValue(value)
}

const strValue = typeof value === 'string' ? value : '' + value
if (typeof languageOrDatatype === 'string') {
if (languageOrDatatype.indexOf(':') === -1) {
return new Literal(strValue, languageOrDatatype)
} else {
return new Literal(strValue, null, namedNode(languageOrDatatype))
}
} else {
return new Literal(strValue, null, languageOrDatatype)
}
}
function namedNode (value) {
return new NamedNode(value)
}
function quad (subject, predicate, object, graph) {
graph = graph || new DefaultGraph()
return new Statement(subject, predicate, object, graph)
}
function variable (name) {
return new Variable(name)
}

/** Only contains the factory methods as defined in the spec */
export default {
blankNode,
defaultGraph,
literal,
namedNode,
quad,
variable,
supports: {
COLLECTIONS: false,
DEFAULT_GRAPH_TYPE: true,
EQUALS_METHOD: true,
VARIABLE_TYPE: true,
}
}
64 changes: 23 additions & 41 deletions src/data-factory.js
Original file line number Diff line number Diff line change
@@ -1,71 +1,53 @@
'use strict'
import BlankNode from './blank-node'
import Collection from './collection'
import DefaultGraph from './default-graph'
import CanonicalDataFactory from './data-factory-internal'
import Fetcher from './fetcher'
import IndexedFormula from './store'
import Literal from './literal'
import NamedNode from './named-node'
import Statement from './statement'
import Variable from './variable'
import IndexedFormula from './store'

/**
* Data factory which also supports Collections
*
* Necessary for preventing circular dependencies.
*/
const ExtendedTermFactory = {
...CanonicalDataFactory,
collection,
supports: {
COLLECTIONS: true,
DEFAULT_GRAPH_TYPE: true,
EQUALS_METHOD: true,
VARIABLE_TYPE: true,
}
}

/** Full RDFLib.js Data Factory */
const DataFactory = {
blankNode,
defaultGraph,
...ExtendedTermFactory,
fetcher,
graph,
lit,
literal,
namedNode,
quad,
st,
triple,
variable,
}
export default DataFactory

function blankNode (value) {
return new BlankNode(value)
}
function collection (elements) {
return new Collection(elements)
}
function defaultGraph () {
return new DefaultGraph()
}
function fetcher (store, options) {
return new Fetcher(store, options)
}
function graph () {
return new IndexedFormula()
function graph (features = undefined, opts = undefined) {
return new IndexedFormula(features, opts || { rdfFactory: ExtendedTermFactory })
}
function lit (val, lang, dt) {
return new Literal('' + val, lang, dt)
}
function literal (value, languageOrDatatype) {
if (typeof languageOrDatatype === 'string') {
if (languageOrDatatype.indexOf(':') === -1) {
return new Literal(value, languageOrDatatype)
} else {
return new Literal(value, null, namedNode(languageOrDatatype))
}
} else {
return new Literal(value, null, languageOrDatatype)
}
}
function namedNode (value) {
return new NamedNode(value)
}
function quad (subject, predicate, object, graph) {
graph = graph || new DefaultGraph()
return new Statement(subject, predicate, object, graph)
}
function st (subject, predicate, object, graph) {
return new Statement(subject, predicate, object, graph)
}
function triple (subject, predicate, object) {
return quad(subject, predicate, object)
}
function variable (name) {
return new Variable(name)
return CanonicalDataFactory.quad(subject, predicate, object)
}
24 changes: 14 additions & 10 deletions src/formula.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import BlankNode from './blank-node'
import ClassOrder from './class-order'
import Collection from './collection'
import Literal from './literal'
import CanonicalDataFactory from './data-factory-internal'
import log from './log'
import NamedNode from './named-node'
import Namespace from './namespace'
Expand All @@ -20,14 +20,21 @@ export default class Formula extends Node {
* @param constraints - initial array of constraints
* @param initBindings - initial bindings used in Query
* @param optional - optional
* @param opts
* @param {DataFactory} opts.rdfFactory - The rdf factory that should be used by the store
*/
constructor (statements, constraints, initBindings, optional) {
constructor (statements, constraints, initBindings, optional, opts = {}) {
super()
this.termType = Formula.termType
this.statements = statements || []
this.constraints = constraints || []
this.initBindings = initBindings || []
this.optional = optional || []

this.rdfFactory = (opts && opts.rdfFactory) || CanonicalDataFactory
for(const factoryMethod of Object.keys(this.rdfFactory)) {
this[factoryMethod] = this.rdfFactory[factoryMethod]
}
}
/** Add a statement from its parts
* @param {Node} subject - the first part of the statemnt
Expand All @@ -36,7 +43,7 @@ export default class Formula extends Node {
* @param {Node} graph - the last part of the statemnt
*/
add (subject, predicate, object, graph) {
return this.statements.push(new Statement(subject, predicate, object, graph))
return this.statements.push(this.rdfFactory.quad(subject, predicate, object, graph))
}
/** Add a statment object
* @param {Statement} statement - an existing constructed statement to add
Expand All @@ -45,7 +52,7 @@ export default class Formula extends Node {
return this.statements.push(st)
}
bnode (id) {
return new BlankNode(id)
return this.rdfFactory.blankNode(id)
}

addAll (statements) {
Expand Down Expand Up @@ -443,9 +450,9 @@ export default class Formula extends Node {
str = str.replace(/\\"/g, '"')
str = str.replace(/\\n/g, '\n')
str = str.replace(/\\\\/g, '\\')
return this.literal(str, lang, dt)
return this.literal(str, lang || dt)
case '_':
return new BlankNode(str.slice(2))
return this.rdfFactory.blankNode(str.slice(2))
case '?':
return new Variable(str.slice(1))
}
Expand Down Expand Up @@ -485,9 +492,6 @@ export default class Formula extends Node {
})
return collection
}
literal (val, lang, dt) {
return new Literal('' + val, lang, dt)
}
/**
* transform a collection of NTriple URIs into their URI strings
* @param t some iterable colletion of NTriple URI strings
Expand Down Expand Up @@ -547,7 +551,7 @@ export default class Formula extends Node {
if (name) {
throw new Error('This feature (kb.sym with 2 args) is removed. Do not assume prefix mappings.')
}
return new NamedNode(uri)
return this.rdfFactory.namedNode(uri)
}
the (s, p, o, g) {
var x = this.any(s, p, o, g)
Expand Down
2 changes: 1 addition & 1 deletion src/literal.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import ClassOrder from './class-order'
import NamedNode from './named-node'
import Node from './node-internal'
import XSD from './xsd'
import XSD from './xsd-internal'

export default class Literal extends Node {
constructor (value, language, datatype) {
Expand Down
12 changes: 6 additions & 6 deletions src/n3parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -1316,9 +1316,9 @@ __SinkParser.prototype.nodeOrLiteral = function(str, i, res) {
var val = m[0];
j = i + val.length;
if ((val.indexOf("T") >= 0)) {
res.push(this._store.literal(val, undefined, this._store.sym(DATETIME_DATATYPE)));
res.push(this._store.literal(val, this._store.sym(DATETIME_DATATYPE)));
} else {
res.push(this._store.literal(val, undefined, this._store.sym(DATE_DATATYPE)));
res.push(this._store.literal(val, this._store.sym(DATE_DATATYPE)));
}

} else {
Expand All @@ -1330,13 +1330,13 @@ __SinkParser.prototype.nodeOrLiteral = function(str, i, res) {
j = ( i + number_syntax.lastIndex ) ;
var val = str.slice( i, j);
if ((val.indexOf("e") >= 0)) {
res.push(this._store.literal(parseFloat(val), undefined, this._store.sym(FLOAT_DATATYPE)));
res.push(this._store.literal(parseFloat(val), this._store.sym(FLOAT_DATATYPE)));
}
else if ((str.slice( i, j).indexOf(".") >= 0)) {
res.push(this._store.literal(parseFloat(val), undefined, this._store.sym(DECIMAL_DATATYPE)));
res.push(this._store.literal(parseFloat(val), this._store.sym(DECIMAL_DATATYPE)));
}
else {
res.push(this._store.literal(parseInt(val), undefined, this._store.sym(INTEGER_DATATYPE)));
res.push(this._store.literal(parseInt(val), this._store.sym(INTEGER_DATATYPE)));
}
};
return j; // Where we have got up to
Expand Down Expand Up @@ -1371,7 +1371,7 @@ __SinkParser.prototype.nodeOrLiteral = function(str, i, res) {
var j = this.uri_ref2(str, ( j + 2 ) , res2);
var dt = res2[0];
}
res.push(this._store.literal(s, lang, dt));
res.push(this._store.literal(s, lang || dt));
return j;
}
else {
Expand Down
2 changes: 1 addition & 1 deletion src/rdfxmlparser.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export default function RDFParser(store) {
this.addSymbol(this.ARC, uri)
}, /** Add a literal to this frame */'addLiteral': function (value) {
if (this.parent.datatype) {
this.node = this.store.literal(value, '', this.store.sym(this.parent.datatype))
this.node = this.store.literal(value, this.store.sym(this.parent.datatype))
} else {
this.node = this.store.literal(value, this.lang)
}
Expand Down
16 changes: 10 additions & 6 deletions src/serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import NamedNode from './named-node'
import BlankNode from './blank-node'
import * as Uri from './uri'
import * as Util from './util'
import XSD from './xsd'
import CanonicalDataFactory from './data-factory-internal'
import { createXSD } from './xsd'

export default (function () {
var __Serializer = function (store) {
Expand All @@ -28,6 +29,8 @@ export default (function () {
this.incoming = null // Array not calculated yet
this.formulas = [] // remebering original formulae from hashes
this.store = store
this.rdfFactory = store.rdfFactory || CanonicalDataFactory
this.xsd = createXSD(this.rdfFactory)
}

__Serializer.prototype.setBase = function (base) { this.base = base; return this }
Expand Down Expand Up @@ -209,14 +212,15 @@ export default (function () {
var rdfns = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
var self = this
var kb = this.store
var factory = this.rdfFactory
var termToNT = function (x) {
if (x.termType !== 'Collection') {
return self.atomicTermToN3(x)
}
var list = x.elements
var rest = kb.sym(rdfns + 'nill')
for (var i = list.length - 1; i >= 0; i--) {
var bnode = new BlankNode()
var bnode = factory.blankNode()
str += termToNT(bnode) + ' ' + termToNT(kb.sym(rdfns + 'first')) + ' ' + termToNT(list[i]) + '.\n'
str += termToNT(bnode) + ' ' + termToNT(kb.sym(rdfns + 'rest')) + ' ' + termToNT(rest) + '.\n'
rest = bnode
Expand Down Expand Up @@ -480,7 +484,7 @@ export default (function () {
var str = this.stringToN3(expr.value)
if (expr.language) {
str += '@' + expr.language
} else if (!expr.datatype.equals(XSD.string)) {
} else if (!expr.datatype.equals(this.xsd.string)) {
str += '^^' + this.atomicTermToN3(expr.datatype, stats)
}
return str
Expand Down Expand Up @@ -804,7 +808,7 @@ export default (function () {
if (number === intNumber.toString()) {
// was numeric; don't need to worry about ordering since we've already
// sorted the statements
pred = new NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#li')
pred = this.rdfFactory.namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#li')
}
}

Expand All @@ -826,7 +830,7 @@ export default (function () {
break
case 'Literal':
results = results.concat(['<' + t +
(st.object.datatype.equals(XSD.string)
(st.object.datatype.equals(this.xsd.string)
? ''
: ' rdf:datatype="' + escapeForXML(st.object.datatype.uri) + '"') +
(st.object.language ? ' xml:lang="' + st.object.language + '"' : '') +
Expand Down Expand Up @@ -892,7 +896,7 @@ export default (function () {
break
case 'Literal':
results = results.concat(['<' + qname(st.predicate) +
(st.object.datatype.equals(XSD.string) ? '' : ' rdf:datatype="' + escapeForXML(st.object.datatype.value) + '"') +
(st.object.datatype.equals(this.xsd.string) ? '' : ' rdf:datatype="' + escapeForXML(st.object.datatype.value) + '"') +
(st.object.language ? ' xml:lang="' + st.object.language + '"' : '') +
'>' + escapeForXML(st.object.value) +
'</' + qname(st.predicate) + '>'])
Expand Down
3 changes: 1 addition & 2 deletions src/sparql-to-query.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ export default function SPARQLToQuery (SPARQL, testMode, kb) {
// alert(end2)
res[1] = kb.literal(
str.slice(ind + 1, ind + 1 + end),
'',
kb.sym(removeBrackets(
str.slice(ind + 4 + end, ind + 2 + end + end2))
)
Expand All @@ -129,7 +128,7 @@ export default function SPARQLToQuery (SPARQL, testMode, kb) {
parseLiterals(str.slice(end + ind + 2 + end2))
)
} else {
res[1] = kb.literal(str.slice(ind + 1, ind + 1 + end), '', null)
res[1] = kb.literal(str.slice(ind + 1, ind + 1 + end))
log.info('Literal found: ' + res[1])
res = res.concat(parseLiterals(str.slice(end + ind + 2))) // finds any other literals
}
Expand Down
Loading

0 comments on commit 33bacf9

Please sign in to comment.