-
Notifications
You must be signed in to change notification settings - Fork 66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue 46: Parse Construct Statement #64
Conversation
bql/grammar/grammar.go
Outdated
Elements: []Element{ | ||
NewTokenType(lexer.ItemLBracket), | ||
NewSymbol("CLAUSES"), | ||
NewTokenType(lexer.ItemRBracket), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @palimarrao . I left a few comments. This looks pretty close to what we want 😄
bql/grammar/grammar.go
Outdated
}, | ||
{ | ||
Elements: []Element{ | ||
NewTokenType(lexer.ItemPredicateBound), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. I have removed the support for binded predicates.
bql/grammar/grammar.go
Outdated
}, | ||
{ | ||
Elements: []Element{ | ||
NewTokenType(lexer.ItemPredicateBound), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment here about the predicate bound.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
bql/grammar/grammar_test.go
Outdated
@@ -113,6 +113,16 @@ func TestAcceptByParse(t *testing.T) { | |||
/room<000> "connects_to"@[] /room<001>};`, | |||
`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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have updated this test case.
@@ -344,7 +365,7 @@ func TestRejectByParseAndSemantic(t *testing.T) { | |||
} | |||
} | |||
|
|||
func TestSemanticStatementGraphClausesLenghtCorrectness(t *testing.T) { | |||
func TestSemanticStatementGraphClausesLengthCorrectness(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thx for the typo fixing 😄
bql/lexer/lexer.go
Outdated
return nil | ||
} | ||
for { | ||
if r := l.next(); !unicode.IsLetter(r) && !unicode.IsDigit(r) && r != rune('_') || r == eof { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good idea. The BNode label name should begin with a letter.
@@ -618,7 +647,7 @@ func lexPredicateOrLiteral(l *lexer) stateFn { | |||
return lexLiteral | |||
} | |||
|
|||
// lexPredicate lexes a predicate of out of the input. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thx 😄
@@ -669,7 +698,7 @@ func lexPredicate(l *lexer) stateFn { | |||
return lexSpace | |||
} | |||
|
|||
// lexPredicate lexes a literal of out of the input. | |||
// lexLiteral lexes a literal out of the input. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yay! 😸
{Type: ItemBlankNode, Text: "_:v1"}, | ||
{Type: ItemBlankNode, Text: "_:foo_bar"}, | ||
{Type: ItemEOF}}}, | ||
{"_v1", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
bql/grammar/grammar_test.go
Outdated
@@ -113,6 +113,16 @@ func TestAcceptByParse(t *testing.T) { | |||
/room<000> "connects_to"@[] /room<001>};`, | |||
`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;`, | |||
`construct {?s "foo"@[] ?o} into ?a from ?b where {?s "foo"@[,] ?o};`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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?
bql/grammar/grammar_test.go
Outdated
// 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Thanks for the review @xllora ! |
Also fixed some typos that I found.