Issue 46: Parse Construct Statement#64
Conversation
| Elements: []Element{ | ||
| NewTokenType(lexer.ItemLBracket), | ||
| NewSymbol("CLAUSES"), | ||
| NewTokenType(lexer.ItemRBracket), |
There was a problem hiding this comment.
There is part missing in this construct. It should support only 3 bindings per entry.
https://www.w3.org/TR/rdf-sparql-query/#tempatesWithBNodes
Which includes the special notation for blank nodes. The current implementation would allow an arbitrary amount that may lead to impossible to construct triples that then we would have to do extra work on the semantic to validate their number, instead of only the type.
Also we should propose a version of how are we going to deal with blank nodes. The one above is pretty simple, but does not help with the reification case. That one is usually expressed with the ; construct something along the lines
construct {
?s ?p ?o ;
"some_pred" ?k .
} ...
That would insert ?s ?p ?o triples, then reify it, and insert blank "some_pred" ?k triple also.
As you can see there two things going here, the first one to create blank nodes as needed, the second to deal with reification.
Yes, the ";" is something that also needs to be revamped later, together with filters in the where clauses; there reason I mention it here is because in the where clause are ways to work around the reification ; syntax, but not here, since otherwise we would have to write something along the lines of
construct {
?s ?p ?o .
_:v "_subject" ?s.
_:v "_predicate" ?p.
_:v "_object" ?o.
_:v "some_pred" ?k .
} ...
Which as you can see is a bit more tedious, and prone to error if you mistype the reification predicates.
Also about the blank node syntax we can keep with _:v where v is a id of that blank node so you can introduce multiple ones, eg _:v1, _:v2 ...
|
The latest commit handles triples and blank nodes. The reification ; syntax will be implemented in a different commit. |
xllora
left a comment
There was a problem hiding this comment.
Thanks @palimarrao . I left a few comments. This looks pretty close to what we want 😄
| }, | ||
| { | ||
| Elements: []Element{ | ||
| NewTokenType(lexer.ItemPredicateBound), |
There was a problem hiding this comment.
Predicate bounds can present a number of predicates. I am not sure we want this here. I think we should only support predicate and binding. For instance, if we go with
construct{
?s ?p@[,some_ts] ?o
}
Does it mean we have to filter further the binded predicates of ?p. This seems a bit redundant since it can be done by construing the where clause further or by adding a having clause. For that reason, I would suggest dropping it.
There was a problem hiding this comment.
Got it. I have removed the support for binded predicates.
| }, | ||
| { | ||
| Elements: []Element{ | ||
| NewTokenType(lexer.ItemPredicateBound), |
There was a problem hiding this comment.
Same comment here about the predicate bound.
| `delete data from ?world {/room<000> "named"@[] "Hallway"^^type:text. | ||
| /room<000> "connects_to"@[] /room<001>};`, | ||
| // Test Construct clause. | ||
| `construct {?s "foo"@[,] ?o} into ?a from ?b where {?s "foo"@[,] ?o} having ?s = ?o;`, |
There was a problem hiding this comment.
This is exactly the point I was making above. If you want to create triples for each of the foo predicates with the right timestamp, you could write it like this instead
CONSTRUCT {?s ?p ?s}
INTO ?a
FROM ?b
WHERE {
?s "foo"@[,] as ?p ?s
} ;
Also see how you can also avoid the having by properly playing with the binding, but that is beside the point here, since we should definitely have test that cover the having clause 😄
There was a problem hiding this comment.
I have updated this test case.
| } | ||
|
|
||
| func TestSemanticStatementGraphClausesLenghtCorrectness(t *testing.T) { | ||
| func TestSemanticStatementGraphClausesLengthCorrectness(t *testing.T) { |
| return nil | ||
| } | ||
| for { | ||
| if r := l.next(); !unicode.IsLetter(r) && !unicode.IsDigit(r) && r != rune('_') || r == eof { |
There was a problem hiding this comment.
Do we want to force the first rune to be a letter? right now this _:_ or _:1 would be valid blank node IDs?
There was a problem hiding this comment.
That's a good idea. The BNode label name should begin with a letter.
| return lexLiteral | ||
| } | ||
|
|
||
| // lexPredicate lexes a predicate of out of the input. |
| } | ||
|
|
||
| // lexPredicate lexes a literal of out of the input. | ||
| // lexLiteral lexes a literal out of the input. |
| {Type: ItemBlankNode, Text: "_:v1"}, | ||
| {Type: ItemBlankNode, Text: "_:foo_bar"}, | ||
| {Type: ItemEOF}}}, | ||
| {"_v1", |
There was a problem hiding this comment.
See my comment about if we should start with a letter always the ID of the blank node.
|
Thanks for the detailed review @xllora ! I have addressed your comments. |
| /room<000> "connects_to"@[] /room<001>};`, | ||
| // Test Construct clause. | ||
| `construct {?s "foo"@[] ?o} into ?a from ?b where {?s "foo"@[,] ?o} having ?s = ?o;`, | ||
| `construct {?s "foo"@[] ?o} into ?a from ?b where {?s "foo"@[,] ?o};`, |
There was a problem hiding this comment.
Could you use a different predicate other than "foo" to avoid confusing. Above it adds a foo that is immutable as opposed to the temporal ones you are querying.
On another note we may want to provide some way to allow folks to construct temporal predicates. Immutable predicates are easy, as you shown in the above examples. But for temporal ones, we would need something along the lines of:
TEMPORAL_PREDICATE("bar"^^type:string, ?ts)
TEMPORAL_PREDICATE("bar"^^type:string, @1234)
TEMPORAL_PREDICATE("bar"^^type:string, "2017....")
What do you thing? No need to do it in this round, but maybe we should file an issue for later.
There was a problem hiding this comment.
Done! For temporal predicates, can we use the same syntax as is used in the INSERT statement?
construct {?s "some_pred"@[2006-01-02T15:04:05.999999999Z07:00] ?o } into ?a from ?b where {?s "foo"@[,] ?o};
Or is the reason that we might need to construct temporal predicates from predicates returned by the WHERE clause, but with a different time anchor?
| // Test Construct clause. | ||
| `construct {?s "foo"@[] ?o} into ?a from ?b where {?s "foo"@[,] ?o} having ?s = ?o;`, | ||
| `construct {?s "foo"@[] ?o} into ?a from ?b where {?s "foo"@[,] ?o};`, | ||
| `construct {?s ?p ?o} into ?a from ?b where {?s "foo"@[,] ?o} having ?s = ?o;`, |
There was a problem hiding this comment.
Nit pick, since it will mater later, ?p is not defined and hence this statement is not going to be semantically valid. Other statements have a similar issue :)
|
Thanks for the review @xllora ! |
Also fixed some typos that I found.