@@ -109,8 +109,15 @@ function WOQLQuery(query){
109
109
* Takes an array of variables, an optional array of column names
110
110
*/
111
111
WOQLQuery . prototype . get = function ( arr1 , arr2 , target ) {
112
- var map = this . buildAsClauses ( arr1 , arr2 ) ;
112
+ if ( arr1 . json ) {
113
+ var map = arr1 . json ( ) ;
114
+ target = arr2 ;
115
+ }
116
+ else {
117
+ var map = this . buildAsClauses ( arr1 , arr2 ) ;
118
+ }
113
119
if ( target ) {
120
+ if ( target . json ) target = target . json ( ) ;
114
121
this . cursor [ 'get' ] = [ map , target ] ;
115
122
}
116
123
else {
@@ -122,18 +129,18 @@ WOQLQuery.prototype.get = function(arr1, arr2, target){
122
129
123
130
WOQLQuery . prototype . buildAsClauses = function ( vars , cols ) {
124
131
var clauses = [ ] ;
125
- if ( vars ) {
132
+ if ( vars && typeof vars == "object" && vars . length ) {
126
133
for ( var i = 0 ; i < vars . length ; i ++ ) {
127
134
var v = vars [ i ] ;
128
- if ( cols ) {
135
+ if ( cols && typeof cols == "object" && cols . length ) {
129
136
var c = cols [ i ] ;
130
137
if ( typeof c == "string" ) {
131
138
c = { "@value" : c } ;
132
139
}
133
140
clauses . push ( { as : [ c , v ] } ) ;
134
141
}
135
142
else {
136
- clauses . push ( { as : [ v ] } ) ;
143
+ v . as ? clauses . push ( v ) : clauses . push ( { as : [ v ] } ) ;
137
144
}
138
145
}
139
146
}
@@ -549,9 +556,15 @@ WOQLQuery.prototype.deleteProperty = function(p, graph){
549
556
* Language elements that cannot be invoked from the top level and therefore are not exposed in the WOQL api
550
557
*/
551
558
WOQLQuery . prototype . as = function ( a , b ) {
559
+ if ( ! a || ! b ) return ;
560
+ if ( ! this . asArray ) {
561
+ this . asArray = true ;
562
+ this . query = [ ] ;
563
+ }
552
564
b = ( b . indexOf ( ":" ) == - 1 ? "v:" + b : b ) ;
553
- this . cursor [ 'as' ] = [ { "@value" : a } , b ] ;
554
- return this . lastUpdate ( ) ;
565
+ var val = ( typeof a == "object" ? a : { "@value" : a } ) ;
566
+ this . query . push ( { as : [ val , b ] } ) ;
567
+ return this ;
555
568
}
556
569
557
570
/**
@@ -1086,52 +1099,67 @@ WOQLQuery.prototype.prettyPrint = function(indent, show_context, q, fluent){
1086
1099
q = ( q ? q : this . query ) ;
1087
1100
var str = "" ;
1088
1101
const newlining_operators = [ "get" , "from" , "into" ] ;
1089
- const non_chaining_operators = [ "and" , "or" ] ;
1090
1102
for ( var operator in q ) {
1091
1103
//ignore context in pretty print
1092
1104
if ( operator == "@context" ) {
1093
1105
if ( show_context ) {
1094
1106
var c = this . getContext ( ) ;
1095
- if ( c ) str += "@context: " + JSON . stringify ( c ) ;
1107
+ if ( c ) str += "@context: " + JSON . stringify ( c ) + "\n" ;
1096
1108
}
1097
1109
continue ;
1098
1110
}
1099
- if ( operator == "true" ) {
1100
- str += "true" ;
1101
- continue ;
1102
- }
1103
- if ( operator == "false" ) {
1104
- str += "false" ;
1105
- continue ;
1106
- }
1107
- if ( fluent ) {
1108
- str += "." + operator ;
1109
- }
1110
- else {
1111
- var inline = indent - this . indent ;
1112
- if ( inline ) {
1113
- str += "\n" + nspaces ( inline ) ;
1114
- }
1115
- str += "WOQL." + operator ;
1116
- }
1111
+ //statement starts differently depending on indent and whether it is fluent style or regular function style
1112
+ str += this . getWOQLPrelude ( operator , fluent , indent - this . indent ) ;
1117
1113
var val = q [ operator ] ;
1118
- if ( typeof val [ val . length - 1 ] == "object" && typeof val [ val . length - 1 ] [ '@value' ] == "undefined" && typeof val [ val . length - 1 ] [ '@type' ] == "undefined" && typeof val [ val . length - 1 ] [ 'value' ] == "undefined" && non_chaining_operators . indexOf ( operator ) == - 1 ) {
1114
+ if ( this . chainable ( operator , val [ val . length - 1 ] ) ) {
1115
+ //all arguments up until the last are regular function arguments
1119
1116
str += this . uncleanArguments ( operator , val . slice ( 0 , val . length - 1 ) , indent , show_context ) ;
1120
1117
if ( newlining_operators . indexOf ( operator ) !== - 1 ) {
1118
+ //some fluent function calls demand a linebreak..
1121
1119
str += "\n" + nspaces ( indent - this . indent ) ;
1122
1120
}
1121
+ //recursive call to query included in tail
1123
1122
str += this . prettyPrint ( indent , show_context , val [ val . length - 1 ] , true ) ;
1124
1123
}
1125
1124
else {
1125
+ //non chainable operators all live inside the function call parameters
1126
1126
str += this . uncleanArguments ( operator , val , indent , show_context ) ;
1127
1127
}
1128
1128
}
1129
+ //remove any trailing dots in the chain (only exist in incompletely specified queries)
1129
1130
if ( str . substring ( str . length - 1 ) == "." ) {
1130
1131
str = str . substring ( 0 , str . length - 1 ) ;
1131
1132
}
1132
1133
return str ;
1133
1134
}
1134
1135
1136
+ /**
1137
+ * Gets the starting characters for a WOQL query - varies depending on how the query is invoked and how indented it is
1138
+ */
1139
+ WOQLQuery . prototype . getWOQLPrelude = function ( operator , fluent , inline ) {
1140
+ if ( operator === "true" || operator === "false" ) {
1141
+ return operator ;
1142
+ }
1143
+ if ( fluent ) {
1144
+ return "." + operator ;
1145
+ }
1146
+ return ( inline ? "\n" + nspaces ( inline ) : "" ) + "WOQL." + operator ;
1147
+ }
1148
+
1149
+ /**
1150
+ * Determines whether a given operator can have a chained query as its last argument
1151
+ */
1152
+ WOQLQuery . prototype . chainable = function ( operator , lastArg ) {
1153
+ const non_chaining_operators = [ "and" , "or" ] ;
1154
+ if ( typeof lastArg == "object" && typeof lastArg [ '@value' ] == "undefined" && typeof lastArg [ '@type' ] == "undefined" && typeof lastArg [ 'value' ] == "undefined" && non_chaining_operators . indexOf ( operator ) == - 1 ) {
1155
+ return true ;
1156
+ }
1157
+ return false ;
1158
+ }
1159
+
1160
+ /**
1161
+ * Transforms arguments to WOQL functions from the internal (clean) version, to the WOQL.js human-friendly version
1162
+ */
1135
1163
WOQLQuery . prototype . uncleanArguments = function ( operator , args , indent , show_context ) {
1136
1164
str = '(' ;
1137
1165
const args_take_newlines = [ "and" , "or" ] ;
@@ -1143,8 +1171,29 @@ WOQLQuery.prototype.uncleanArguments = function(operator, args, indent, show_con
1143
1171
if ( this . argIsSubQuery ( operator , args [ i ] , i ) ) {
1144
1172
str += this . prettyPrint ( indent + this . indent , show_context , args [ i ] , false ) ;
1145
1173
}
1174
+ else if ( operator == "get" && i == 0 ) { // weird one, needs special casing
1175
+ str += "\n" + nspaces ( indent - this . indent ) + "WOQL" ;
1176
+ for ( var j = 0 ; j < args [ 0 ] . length ; j ++ ) {
1177
+ var myas = ( args [ 0 ] [ j ] . as ? args [ 0 ] [ j ] . as : args [ 0 ] [ j ] ) ;
1178
+ var lhs = myas [ 0 ] ;
1179
+ var rhs = myas [ 1 ] ;
1180
+ if ( typeof lhs == "object" && lhs [ '@value' ] ) {
1181
+ lhs = lhs [ '@value' ] ;
1182
+ }
1183
+ if ( typeof lhs == "object" ) {
1184
+ lhs = JSON . stringify ( lhs ) ;
1185
+ }
1186
+ else {
1187
+ lhs = '"' + lhs + '"'
1188
+ }
1189
+ str += '.as(' + lhs ;
1190
+ if ( rhs ) str += ', "' + rhs + '"' ;
1191
+ str += ")" ;
1192
+ str += "\n" + nspaces ( indent ) ;
1193
+ }
1194
+ }
1146
1195
else {
1147
- str += this . uncleanArgument ( operator , args [ i ] , i ) ;
1196
+ str += this . uncleanArgument ( operator , args [ i ] , i , args ) ;
1148
1197
}
1149
1198
if ( i < args . length - 1 ) str += ',' ;
1150
1199
}
@@ -1156,7 +1205,13 @@ WOQLQuery.prototype.uncleanArguments = function(operator, args, indent, show_con
1156
1205
return str ;
1157
1206
}
1158
1207
1159
- WOQLQuery . prototype . uncleanArgument = function ( operator , val , index ) {
1208
+
1209
+ /**
1210
+ * Passed as arguments: 1) the operator (and, triple, not, opt, etc)
1211
+ * 2) the value of the argument
1212
+ * 3) the index (position) of the argument.
1213
+ */
1214
+ WOQLQuery . prototype . uncleanArgument = function ( operator , val , index , allArgs ) {
1160
1215
//numeric values go out untouched...
1161
1216
const numeric_operators = [ "limit" , "start" , "eval" , "plus" , "minus" , "times" , "divide" , "exp" ] ;
1162
1217
if ( operator == "isa" ) {
@@ -1165,35 +1220,9 @@ WOQLQuery.prototype.uncleanArgument = function(operator, val, index){
1165
1220
else if ( operator == "sub" ) {
1166
1221
val = this . unclean ( val , 'class' ) ;
1167
1222
}
1168
- else if ( operator == "get" && index == 0 ) {
1169
- var lhs = [ ] ;
1170
- var rhs = [ ] ;
1171
- for ( var i = 0 ; i < val . length ; i ++ ) {
1172
- var entry = val [ i ] . as ;
1173
- if ( entry . length == 2 ) {
1174
- var colname = entry [ 0 ] [ '@value' ] ;
1175
- if ( colname ) lhs . push ( colname ) ;
1176
- var varname = entry [ 1 ] ;
1177
- if ( varname . indexOf ( ":" ) == - 1 ) varname = "v:" + varname ;
1178
- rhs . push ( varname ) ;
1179
- }
1180
- else {
1181
- var varname = entry [ 0 ] ;
1182
- if ( varname . indexOf ( ":" ) == - 1 ) varname = "v:" + varname ;
1183
- rhs . push ( varname ) ;
1184
- }
1185
- }
1186
- if ( lhs . length ) {
1187
- val = nspaces ( this . index ) + JSON . stringify ( rhs ) + ",\n" + nspaces ( this . index ) + JSON . stringify ( lhs ) ;
1188
- }
1189
- else {
1190
- val = JSON . stringify ( rhs ) ;
1191
- }
1192
- return val ;
1193
- }
1194
1223
else if ( [ "select" ] . indexOf ( operator ) != - 1 ) {
1195
1224
if ( val . substring ( 0 , 2 ) == "v:" ) val = val . substring ( 2 ) ;
1196
- }
1225
+ }
1197
1226
else if ( [ "quad" , "add_quad" , "delete_quad" , "add_triple" , "delete_triple" , "triple" ] . indexOf ( operator ) != - 1 ) {
1198
1227
switch ( index ) {
1199
1228
case 0 : val = this . unclean ( val , "subject" ) ; break ;
@@ -1224,6 +1253,8 @@ WOQLQuery.prototype.uncleanArgument = function(operator, val, index){
1224
1253
return '"' + val + '"' ;
1225
1254
}
1226
1255
1256
+
1257
+
1227
1258
WOQLQuery . prototype . uncleanObjectArgument = function ( operator , val , index ) {
1228
1259
if ( val [ '@value' ] && ( val [ '@language' ] || ( val [ '@type' ] && val [ '@type' ] == "xsd:string" ) ) ) return '"' + val [ '@value' ] + '"' ;
1229
1260
if ( val [ '@value' ] && ( val [ '@type' ] && val [ '@type' ] == "xsd:integer" ) ) return val [ '@value' ] ;
@@ -1259,12 +1290,13 @@ WOQLQuery.prototype.unclean = function(s, part){
1259
1290
if ( s . indexOf ( ":" ) == - 1 ) return s ;
1260
1291
if ( s . substring ( 0 , 4 ) == "http" ) return s ;
1261
1292
var suff = s . split ( ":" ) [ 1 ] ;
1262
- if ( this . vocab && this . vocab [ suff ] ) {
1293
+ if ( this . vocab && this . vocab [ suff ] && this . vocab [ suff ] == s ) {
1263
1294
return suff ;
1264
1295
}
1265
1296
if ( ! part ) return s ;
1266
1297
if ( part == "subject" && ( s . split ( ":" ) [ 0 ] == "doc" ) ) return suff ;
1267
1298
if ( part == "class" && ( s . split ( ":" ) [ 0 ] == "scm" ) ) return suff ;
1299
+ if ( part == "predicate" && ( s . split ( ":" ) [ 0 ] == "scm" ) ) return suff ;
1268
1300
if ( part == "type" && ( s . split ( ":" ) [ 0 ] == "scm" ) ) return suff ;
1269
1301
if ( part == "graph" && ( s . split ( ":" ) [ 0 ] == "db" ) ) return suff ;
1270
1302
return s ;
@@ -1281,7 +1313,6 @@ WOQLQuery.prototype.getShortcut = function(operator, args, indent, show_context)
1281
1313
1282
1314
1283
1315
1284
-
1285
1316
function nspaces ( n ) {
1286
1317
let spaces = "" ;
1287
1318
for ( var i = 0 ; i < n ; i ++ ) {
@@ -1351,23 +1382,35 @@ function TripleBuilder(type, cursor, s){
1351
1382
1352
1383
TripleBuilder . prototype . label = function ( l , lang ) {
1353
1384
lang = ( lang ? lang : "en" ) ;
1354
- var x = this . addPO ( 'rdfs:label' , { "@value" : l , "@language" : lang } ) ;
1385
+ if ( l . substring ( 0 , 2 ) == "v:" ) {
1386
+ var d = { "value" : l , "@language" : lang }
1387
+ }
1388
+ else {
1389
+ var d = { "@value" : l , "@language" : lang }
1390
+ }
1391
+ var x = this . addPO ( 'rdfs:label' , d ) ;
1355
1392
return x ;
1356
1393
}
1357
1394
1358
1395
TripleBuilder . prototype . comment = function ( c , lang ) {
1359
1396
lang = ( lang ? lang : "en" ) ;
1360
- return this . addPO ( 'rdfs:comment' , { "@value" : c , "@language" : lang } ) ;
1397
+ if ( c . substring ( 0 , 2 ) == "v:" ) {
1398
+ var d = { "value" : l , "@language" : lang }
1399
+ }
1400
+ else {
1401
+ var d = { "@value" : l , "@language" : lang }
1402
+ }
1403
+ return this . addPO ( 'rdfs:comment' , d ) ;
1361
1404
}
1362
1405
1363
1406
TripleBuilder . prototype . addPO = function ( p , o , g ) {
1364
1407
if ( this . type ) {
1365
1408
var ttype = ( this . type == "isa" || this . type == "sub" ? "triple" : this . type ) ;
1366
1409
}
1367
1410
else var ttype = "triple" ;
1368
- var evstr = ttype + "('" + this . subject + "', '" + p + "', " ;
1411
+ var evstr = ttype + '("' + this . subject + '", "' + p + '", ' ;
1369
1412
if ( typeof o == "string" ) {
1370
- evstr += "'" + o + "'" ;
1413
+ evstr += "'" + o + "'" ;
1371
1414
}
1372
1415
else if ( typeof o == "object" ) {
1373
1416
evstr += JSON . stringify ( o ) ;
@@ -1377,7 +1420,7 @@ TripleBuilder.prototype.addPO = function(p, o, g){
1377
1420
}
1378
1421
if ( ttype . substring ( ttype . length - 4 ) == "quad" || this . g ) {
1379
1422
var g = ( g ? g : ( this . g ? this . g : "db:schema" ) ) ;
1380
- evstr += ", '" + g + "'" ;
1423
+ evstr += ', "' + g + '"' ;
1381
1424
}
1382
1425
evstr += ")" ;
1383
1426
try {
0 commit comments