forked from SolidOS/solid-panes
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathqueryByExample.js
More file actions
297 lines (273 loc) · 8.6 KB
/
queryByExample.js
File metadata and controls
297 lines (273 loc) · 8.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
/* istanbul ignore file */
// The query-by-example functionality in the tabulator
// was the ability to expore a bit of the web in outline mode,
// select a ceratain set of fields in the tree,
// then pres "find all" which would then generte a SPARQL query
// to find all other places which had the same pattern.
// Fields could be optional by pressing th ewhite optoional button
import { store } from 'solid-logic-jss'
import * as UI from 'solid-ui-jss'
import * as $rdf from 'rdflib'
const optionalSubqueriesIndex = []
function predParentOf (node) {
let n = node
while (true) {
if (n.getAttribute('predTR')) {
return n
} else if (n.previousSibling && n.previousSibling.nodeName === 'TR') {
n = n.previousSibling
} else {
console.log('Could not find predParent')
return node
}
}
}
export function makeQueryRow (q, tr, constraint) {
// predtr = predParentOf(tr)
// var nodes = tr.childNodes
// var n = tr.childNodes.length
const inverse = tr.AJAR_inverse
// var hasVar = 0
let parentVar, level, pat
function makeRDFStatement (freeVar, parent) {
if (inverse) {
return new $rdf.Statement(freeVar, st.predicate, parent)
} else {
return new $rdf.Statement(parent, st.predicate, freeVar)
}
}
let optionalSubqueryIndex = null
for (level = tr.parentNode; level; level = level.parentNode) {
if (typeof level.AJAR_statement !== 'undefined') {
// level.AJAR_statement
level.setAttribute('bla', level.AJAR_statement) // @@? -timbl
// UI.log.debug("Parent TR statement="+level.AJAR_statement + ", var=" + level.AJAR_variable)
/* for(let c=0;c<level.parentNode.childNodes.length;c++) //This makes sure the same variable is used for a subject
if(level.parentNode.childNodes[c].AJAR_variable)
level.AJAR_variable = level.parentNode.childNodes[c].AJAR_variable; */
if (!level.AJAR_variable) {
makeQueryRow(q, level)
}
parentVar = level.AJAR_variable
const predLevel = predParentOf(level)
if (predLevel.getAttribute('optionalSubqueriesIndex')) {
optionalSubqueryIndex = predLevel.getAttribute(
'optionalSubqueriesIndex'
)
pat = optionalSubqueriesIndex[optionalSubqueryIndex]
}
break
}
}
if (!pat) {
pat = q.pat
}
const predtr = predParentOf(tr)
// /////OPTIONAL KLUDGE///////////
const opt = predtr.getAttribute('optional')
if (!opt) {
if (optionalSubqueryIndex) {
predtr.setAttribute('optionalSubqueriesIndex', optionalSubqueryIndex)
} else {
predtr.removeAttribute('optionalSubqueriesIndex')
}
}
if (opt) {
const optForm = store.formula()
optionalSubqueriesIndex.push(optForm)
predtr.setAttribute(
'optionalSubqueriesIndex',
optionalSubqueriesIndex.length - 1
)
pat.optional.push(optForm)
pat = optForm
}
// //////////////////////////////
const st = tr.AJAR_statement
const constraintVar = tr.AJAR_inverse ? st.subject : st.object // this is only used for constraints
let hasParent = true
if (constraintVar.isBlank && constraint) {
window.alert(
'You cannot constrain a query with a blank node. No constraint will be added.'
)
}
if (!parentVar) {
hasParent = false
parentVar = inverse ? st.object : st.subject // if there is no parents, uses the sub/obj
}
// UI.log.debug('Initial variable: '+tr.AJAR_variable)
const v = tr.AJAR_variable
? tr.AJAR_variable
: store.variable(UI.utils.newVariableName())
q.vars.push(v)
v.label = hasParent ? parentVar.label : UI.utils.label(parentVar)
v.label += ' ' + UI.utils.predicateLabelForXML(st.predicate, inverse)
const pattern = makeRDFStatement(v, parentVar)
// alert(pattern)
v.label = v.label.slice(0, 1).toUpperCase() + v.label.slice(1) // init cap
// See ../rdf/sparql.js
// This should only work on literals but doesn't.
function ConstraintEqualTo (value) {
this.describe = function (varstr) {
return varstr + ' = ' + value.toNT()
}
this.test = function (term) {
return value.sameTerm(term)
}
return this
}
if (constraint) {
// binds the constrained variable to its selected value
pat.constraints[v] = new ConstraintEqualTo(constraintVar)
}
UI.log.info('Pattern: ' + pattern)
pattern.tr = tr
tr.AJAR_pattern = pattern // Cross-link UI and query line
tr.AJAR_variable = v
// UI.log.debug('Final variable: '+tr.AJAR_variable)
UI.log.debug('Query pattern: ' + pattern)
pat.statements.push(pattern)
return v
} // makeQueryRow
function saveQuery (selection, qs) {
// var qs = outline.qs // @@
const q = new $rdf.Query()
const n = selection.length
let i, sel, st, tr
for (i = 0; i < n; i++) {
sel = selection[i]
tr = sel.parentNode
st = tr.AJAR_statement
UI.log.debug('Statement ' + st)
if (sel.getAttribute('class').indexOf('pred') >= 0) {
UI.log.info(' We have a predicate')
makeQueryRow(q, tr)
}
if (sel.getAttribute('class').indexOf('obj') >= 0) {
UI.log.info(' We have an object')
makeQueryRow(q, tr, true)
}
}
qs.addQuery(q)
function resetOutliner (pat) {
const n = pat.statements.length
let pattern, tr
for (let i = 0; i < n; i++) {
pattern = pat.statements[i]
tr = pattern.tr
// UI.log.debug('tr: ' + tr.AJAR_statement);
if (typeof tr !== 'undefined') {
tr.AJAR_pattern = null // TODO: is this == to whats in current version?
tr.AJAR_variable = null
}
}
for (const x in pat.optional) {
resetOutliner(pat.optional[x])
}
}
resetOutliner(q.pat)
// NextVariable=0;
return q
} // saveQuery
// When the user asks for all list of all matching parts of the data
//
export function viewAndSaveQuery (outline, selection) {
const qs = outline.qs
UI.log.info('outline.doucment is now ' + outline.document.location)
const q = saveQuery(selection, qs)
/*
if (tabulator.isExtension) {
// tabulator.drawInBestView(q)
} else
*/
for (let i = 0; i < qs.listeners.length; i++) {
qs.listeners[i].getActiveView().view.drawQuery(q)
qs.listeners[i].updateQueryControls(qs.listeners[i].getActiveView())
}
}
/**
* The QuerySource object stores a set of listeners and a set of queries.
* It keeps the listeners aware of those queries that the source currently
* contains, and it is then up to the listeners to decide what to do with
* those queries in terms of displays.
* Not used 2010-08 -- TimBL
* @class QuerySource
* @author jambo
*/
export function QuerySource () {
/**
* stores all of the queries currently held by this source,
* indexed by ID number.
*/
this.queries = []
/**
* stores the listeners for a query object.
* @see TabbedContainer
*/
this.listeners = []
/**
* add a Query object to the query source--It will be given an ID number
* and a name, if it doesn't already have one. This subsequently adds the
* query to all of the listeners the QuerySource knows about.
*/
this.addQuery = function (q) {
let i
if (q.name === null || q.name === '') {
q.name = 'Query #' + (this.queries.length + 1)
}
q.id = this.queries.length
this.queries.push(q)
for (i = 0; i < this.listeners.length; i++) {
if (this.listeners[i] !== null) {
this.listeners[i].addQuery(q)
}
}
}
/**
* Remove a Query object from the source. Tells all listeners to also
* remove the query.
*/
this.removeQuery = function (q) {
let i
for (i = 0; i < this.listeners.length; i++) {
if (this.listeners[i] !== null) {
this.listeners[i].removeQuery(q)
}
}
if (this.queries[q.id] !== null) {
delete this.queries[q.id]
}
}
/**
* adds a "Listener" to this QuerySource - that is, an object
* which is capable of both adding and removing queries.
* Currently, only the TabbedContainer class is added.
* also puts all current queries into the listener to be used.
*/
this.addListener = function (listener) {
let i
this.listeners.push(listener)
for (i = 0; i < this.queries.length; i++) {
if (this.queries[i] !== null) {
listener.addQuery(this.queries[i])
}
}
}
/**
* removes listener from the array of listeners, if it exists! Also takes
* all of the queries from this source out of the listener.
*/
this.removeListener = function (listener) {
let i
for (i = 0; i < this.queries.length; i++) {
if (this.queries[i] !== null) {
listener.removeQuery(this.queries[i])
}
}
for (i = 0; i < this.listeners.length; i++) {
if (this.listeners[i] === listener) {
delete this.listeners[i]
}
}
}
}