From 0c664e990c060aa639233a432f010fd3ea83444b Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Thu, 30 Apr 2020 13:30:38 +0200 Subject: [PATCH 1/3] Adding rdflib data types to Store Once I started using the newest version with the new types in SolidOS I realized that the Store methods were not working properly, as they return RDF/JS data types, and SolidOS relies heavily on rdflib data types. I think the changes should conform to RDF/JS data types, but have some doubts about some of the code I changed, especially IndexedFormula#canon (which, as I understand it, must cast RDF/JS data types to rdflib data types). I hope this works, as it makes most of the codebase in SolidOS work (there are still _some_ inconsistencies, but I'll create separate issues/PRs for these) --- src/formula.ts | 50 +++++++++++++----------------------- src/store.ts | 69 ++++++++++++++++++++++++++++++++++---------------- 2 files changed, 65 insertions(+), 54 deletions(-) diff --git a/src/formula.ts b/src/formula.ts index e24769e62..7870ca2d1 100644 --- a/src/formula.ts +++ b/src/formula.ts @@ -19,7 +19,6 @@ import { } from './factories/factory-types' import { appliedFactoryMethods, arrayToStatements } from './utils' import { - BlankNode, RdfJsDataFactory, Quad_Graph, Quad_Object, @@ -27,9 +26,10 @@ import { Quad, Quad_Subject, Term, - NamedNode, } from './tf-types' import Fetcher from './fetcher' +import BlankNode from './blank-node' +import NamedNode from './named-node' export interface FormulaOpts { dataCallback?: (q: Quad) => void @@ -57,9 +57,6 @@ export default class Formula extends Node { classOrder = ClassOrder.Graph - /** The additional constraints */ - constraints: ReadonlyArray; - /** * The accompanying fetcher instance. * @@ -67,8 +64,6 @@ export default class Formula extends Node { */ fetcher?: Fetcher - initBindings: ReadonlyArray - isVar = 0 /** @@ -77,14 +72,9 @@ export default class Formula extends Node { */ ns = Namespace - optional: ReadonlyArray - /** The factory used to generate statements and terms */ rdfFactory: any - /** The stored statements */ - statements: Quad[]; - /** * Initializes this formula * @constructor @@ -96,17 +86,13 @@ export default class Formula extends Node { * @param opts.rdfFactory - The rdf factory that should be used by the store */ constructor ( - statements?: Quad[], - constraints?: ReadonlyArray, - initBindings?: ReadonlyArray, - optional?: ReadonlyArray, + public statements: Array = [], + public constraints: ReadonlyArray = [], + public initBindings: ReadonlyArray = [], + public optional: ReadonlyArray = [], opts: FormulaOpts = {} ) { super('') - this.statements = statements || [] - this.constraints = constraints || [] - this.initBindings = initBindings || [] - this.optional = optional || [] this.rdfFactory = (opts && opts.rdfFactory) || CanonicalDataFactory // Enable default factory methods on this while preserving factory context. @@ -122,11 +108,11 @@ export default class Formula extends Node { * @param graph - the last part of the statement */ add ( - subject: Quad_Subject | Quad | Quad[] | Statement | Statement[], + subject: Quad_Subject | Quad | Quad[], predicate?: Quad_Predicate, object?: Term | string, graph?: Quad_Graph - ): Quad | null | this | number { + ): Statement | null | this | number { if (arguments.length === 1) { (subject as Quad[]).forEach(st => this.add(st.subject, st.predicate, st.object, st.graph)) } @@ -137,7 +123,7 @@ export default class Formula extends Node { * @param {Statement} statement - An existing constructed statement to add */ addStatement (statement: Quad): number { - return this.statements.push(statement) + return this.add(statement) as number } /** @@ -175,7 +161,7 @@ export default class Formula extends Node { p?: Quad_Predicate | null, o?: Quad_Object | null, g?: Quad_Graph | null - ): Term | null { + ): Node | null { const st = this.anyStatementMatching(s, p, o, g) if (st == null) { return null @@ -232,7 +218,7 @@ export default class Formula extends Node { p?: Quad_Predicate | null, o?: Quad_Object | null, g?: Quad_Graph | null - ): Quad | undefined { + ): Statement | undefined { let x = this.statementsMatching(s, p, o, g, true) if (!x || x.length === 0) { return undefined @@ -267,7 +253,7 @@ export default class Formula extends Node { o?: Quad_Object | null, g?: Quad_Graph | null, justOne?: boolean - ): Quad[] { + ): Statement[] { const sts = this.statements.filter(st => (!s || s.equals(st.subject)) && (!p || p.equals(st.predicate)) && @@ -346,8 +332,8 @@ export default class Formula extends Node { p?: Quad_Predicate | null, o?: Quad_Object | null, g?: Quad_Graph | null - ): Term[] { - const results: Term[] = [] + ): Node[] { + const results: Node[] = [] let sts = this.statementsMatching(s, p, o, g, false) if (s == null) { for (let i = 0, len = sts.length; i < len; i++) { @@ -363,7 +349,7 @@ export default class Formula extends Node { } } else if (g == null) { for (let q = 0, len3 = sts.length; q < len3; q++) { - results.push(sts[q].graph) + results.push(new NamedNode(sts[q].graph.value)) } } @@ -570,12 +556,12 @@ export default class Formula extends Node { subject: Quad_Subject, doc: Quad_Graph, excludePredicateURIs?: ReadonlyArray - ): Quad[] { + ): Statement[] { excludePredicateURIs = excludePredicateURIs || [] let todo = [subject] let done: { [k: string]: boolean } = {} let doneArcs: { [k: string]: boolean } = {} - let result: Quad[] = [] + let result: Statement[] = [] let self = this let follow = function (x) { let queue = function (x) { @@ -798,7 +784,7 @@ export default class Formula extends Node { p?: Quad_Predicate | null, o?: Quad_Object | null, g?: Quad_Graph | null - ): Term | null | undefined { + ): Node | null | undefined { let x = this.any(s, p, o, g) if (x == null) { log.error('No value found for the() {' + s + ' ' + p + ' ' + o + '}.') diff --git a/src/store.ts b/src/store.ts index bba6542d6..c9507f70e 100644 --- a/src/store.ts +++ b/src/store.ts @@ -35,22 +35,28 @@ import Variable from './variable' import { Query, indexedFormulaQuery } from './query' import UpdateManager from './update-manager' import { - Bindings, + Bindings, BlankNodeTermType, CollectionTermType, DefaultGraphTermType, EmptyTermType, GraphTermType, LiteralTermType, NamedNodeTermType, VariableTermType } from './types' import Statement from './statement' import { Indexable } from './factories/factory-types' import NamedNode from './named-node' import Fetcher from './fetcher' import { - BlankNode, Quad_Graph, + Literal as TFLiteral, NamedNode as TFNamedNode, Quad_Object, Quad_Predicate, Quad, Quad_Subject, - Term + Term, } from './tf-types' +import { namedNode } from './index' +import BlankNode from './blank-node' +import DefaultGraph from './default-graph' +import Empty from './empty' +import Literal from './literal' +import Collection from './collection' const owlNamespaceURI = 'http://www.w3.org/2002/07/owl#' @@ -136,24 +142,24 @@ export default class IndexedFormula extends Formula { // IN future - allow pass /** Reverse mapping to redirection: aliases for this */ aliases: any[] /** Redirections we got from HTTP */ - HTTPRedirects: Quad[] + HTTPRedirects: Statement[] /** Array of statements with this X as subject */ - subjectIndex: Quad[] + subjectIndex: Statement[] /** Array of statements with this X as predicate */ - predicateIndex: Quad[] + predicateIndex: Statement[] /** Array of statements with this X as object */ - objectIndex: Quad[] + objectIndex: Statement[] /** Array of statements with X as provenance */ - whyIndex: Quad[] + whyIndex: Statement[] index: [ - Quad[], - Quad[], - Quad[], - Quad[] + Statement[], + Statement[], + Statement[], + Statement[] ] features: FeaturesType static handleRDFType: Function - _universalVariables?: TFNamedNode[] + _universalVariables?: NamedNode[] _existentialVariables?: BlankNode[] /** Function to remove quads from the store arrays with */ @@ -299,7 +305,7 @@ export default class IndexedFormula extends Formula { // IN future - allow pass var query = new Query('patch') query.pat = patch.where query.pat.statements.map(function (st) { - st.graph = target + st.graph = namedNode(target.value) }) //@ts-ignore TODO: add sync property to Query when converting Query to typescript query.sync = true @@ -395,7 +401,7 @@ export default class IndexedFormula extends Formula { // IN future - allow pass pred?: Quad_Predicate, obj?: Term | string, why?: Quad_Graph - ): Quad | null | this | number { + ): Statement | null | this | number { var i: number if (arguments.length === 1) { if (subj instanceof Array) { @@ -410,7 +416,7 @@ export default class IndexedFormula extends Formula { // IN future - allow pass return this } var actions: Function[] - var st: Quad + var st: Statement if (!why) { // system generated why = this.fetcher ? this.fetcher.appNode : this.rdfFactory.defaultGraph() @@ -489,13 +495,32 @@ export default class IndexedFormula extends Formula { // IN future - allow pass * Returns the symbol with canonical URI as smushed * @param term - An RDF node */ - canon(term: Term): Term { + canon(term: Term): Node { if (!term) { return term } var y = this.redirections[this.id(term)] if (!y) { - return term + switch (term.termType) { + case BlankNodeTermType: + return new BlankNode(term.value) + case CollectionTermType: + return term as Collection // non-RDF/JS type, should just need to cast + case DefaultGraphTermType: + return new DefaultGraph() + case EmptyTermType: // non-RDF/JS type, should just need to cast + return term as Empty + case GraphTermType: // non-RDF/JS type, should just need to cast + return term as IndexedFormula + case LiteralTermType: + return new Literal(term.value, (term as TFLiteral).language, (term as TFLiteral).datatype) + case NamedNodeTermType: + return new NamedNode(term.value) + case VariableTermType: + return new Variable(term.value) + default: + throw new Error(`Term Type not recognized for canonization: ${term.termType}`) + } } return y } @@ -1038,7 +1063,7 @@ export default class IndexedFormula extends Formula { // IN future - allow pass obj?: Quad_Object | null, why?: Quad_Graph | null, justOne?: boolean - ): Quad[] { + ): Statement[] { // log.debug("Matching {"+subj+" "+pred+" "+obj+"}") var pat = [ subj, pred, obj, why ] var pattern: Term[] = [] @@ -1089,12 +1114,12 @@ export default class IndexedFormula extends Formula { // IN future - allow pass } // Ok, we have picked the shortest index but now we have to filter it var pBest = given[iBest] - var possibles: Quad[] = this.index[pBest][hash[pBest]] + var possibles: Statement[] = this.index[pBest][hash[pBest]] var check = given.slice(0, iBest).concat(given.slice(iBest + 1)) // remove iBest - var results: Quad[] = [] + var results: Statement[] = [] var parts = [ 'subject', 'predicate', 'object', 'why' ] for (var j = 0; j < possibles.length; j++) { - var st: Quad | null = possibles[j] + var st: Statement | null = possibles[j] for (i = 0; i < check.length; i++) { // for each position to be checked p = check[i] From 6d6284f2a18a98b8fad38a3ad812650f074507d2 Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Thu, 30 Apr 2020 20:23:23 +0200 Subject: [PATCH 2/3] Not ideal solution, but works --- src/store.ts | 51 ++++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/src/store.ts b/src/store.ts index c9507f70e..49d6e6544 100644 --- a/src/store.ts +++ b/src/store.ts @@ -495,34 +495,35 @@ export default class IndexedFormula extends Formula { // IN future - allow pass * Returns the symbol with canonical URI as smushed * @param term - An RDF node */ - canon(term: Term): Node { + canon(term?: Term): Node { if (!term) { - return term + // @@ TODO Should improve this to return proper value - doing this to keep it backward compatible + return term as unknown as Node } - var y = this.redirections[this.id(term)] - if (!y) { - switch (term.termType) { - case BlankNodeTermType: - return new BlankNode(term.value) - case CollectionTermType: - return term as Collection // non-RDF/JS type, should just need to cast - case DefaultGraphTermType: - return new DefaultGraph() - case EmptyTermType: // non-RDF/JS type, should just need to cast - return term as Empty - case GraphTermType: // non-RDF/JS type, should just need to cast - return term as IndexedFormula - case LiteralTermType: - return new Literal(term.value, (term as TFLiteral).language, (term as TFLiteral).datatype) - case NamedNodeTermType: - return new NamedNode(term.value) - case VariableTermType: - return new Variable(term.value) - default: - throw new Error(`Term Type not recognized for canonization: ${term.termType}`) - } + const y = this.redirections[this.id(term)] + if (y) { + return y + } + switch (term.termType) { + case BlankNodeTermType: + return new BlankNode(term.value) + case CollectionTermType: + return term as Collection // non-RDF/JS type, should just need to cast + case DefaultGraphTermType: + return new DefaultGraph() + case EmptyTermType: // non-RDF/JS type, should just need to cast + return term as Empty + case GraphTermType: // non-RDF/JS type, should just need to cast + return term as IndexedFormula + case LiteralTermType: + return new Literal(term.value, (term as TFLiteral).language, (term as TFLiteral).datatype) + case NamedNodeTermType: + return new NamedNode(term.value) + case VariableTermType: + return new Variable(term.value) + default: + throw new Error(`Term Type not recognized for canonization: ${term.termType}`) } - return y } From 062cc104da7b6abeac928be68b453e54b2d0c61a Mon Sep 17 00:00:00 2001 From: Arne Hassel Date: Thu, 30 Apr 2020 20:24:45 +0200 Subject: [PATCH 3/3] Extended types for addStatement, as per Rubens suggestion --- src/formula.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/formula.ts b/src/formula.ts index 7870ca2d1..c7867ef8a 100644 --- a/src/formula.ts +++ b/src/formula.ts @@ -122,8 +122,8 @@ export default class Formula extends Node { /** Add a statment object * @param {Statement} statement - An existing constructed statement to add */ - addStatement (statement: Quad): number { - return this.add(statement) as number + addStatement (statement: Quad): Statement | null | this | number { + return this.add(statement) } /**