Skip to content

Commit

Permalink
Merge pull request #74 from palimarrao/differentiate_graphs
Browse files Browse the repository at this point in the history
Added input and output graph lists.
  • Loading branch information
xllora authored Jun 15, 2017
2 parents 5d847b0 + 011227f commit 9b7b7f6
Show file tree
Hide file tree
Showing 8 changed files with 273 additions and 49 deletions.
54 changes: 49 additions & 5 deletions bql/grammar/grammar.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func BQL() *Grammar {
NewTokenType(lexer.ItemQuery),
NewSymbol("VARS"),
NewTokenType(lexer.ItemFrom),
NewSymbol("GRAPHS"),
NewSymbol("INPUT_GRAPHS"),
NewSymbol("WHERE"),
NewSymbol("GROUP_BY"),
NewSymbol("ORDER_BY"),
Expand All @@ -49,7 +49,7 @@ func BQL() *Grammar {
NewTokenType(lexer.ItemInsert),
NewTokenType(lexer.ItemData),
NewTokenType(lexer.ItemInto),
NewSymbol("GRAPHS"),
NewSymbol("OUTPUT_GRAPHS"),
NewTokenType(lexer.ItemLBracket),
NewTokenType(lexer.ItemNode),
NewTokenType(lexer.ItemPredicate),
Expand All @@ -64,7 +64,7 @@ func BQL() *Grammar {
NewTokenType(lexer.ItemDelete),
NewTokenType(lexer.ItemData),
NewTokenType(lexer.ItemFrom),
NewSymbol("GRAPHS"),
NewSymbol("INPUT_GRAPHS"),
NewTokenType(lexer.ItemLBracket),
NewTokenType(lexer.ItemNode),
NewTokenType(lexer.ItemPredicate),
Expand Down Expand Up @@ -93,9 +93,9 @@ func BQL() *Grammar {
NewTokenType(lexer.ItemConstruct),
NewSymbol("CONSTRUCT_FACTS"),
NewTokenType(lexer.ItemInto),
NewSymbol("GRAPHS"),
NewSymbol("OUTPUT_GRAPHS"),
NewTokenType(lexer.ItemFrom),
NewSymbol("GRAPHS"),
NewSymbol("INPUT_GRAPHS"),
NewSymbol("WHERE"),
NewSymbol("HAVING"),
NewTokenType(lexer.ItemSemicolon),
Expand Down Expand Up @@ -194,6 +194,42 @@ func BQL() *Grammar {
},
{},
},
"INPUT_GRAPHS": []*Clause{
{
Elements: []Element{
NewTokenType(lexer.ItemBinding),
NewSymbol("MORE_INPUT_GRAPHS"),
},
},
},
"MORE_INPUT_GRAPHS": []*Clause{
{
Elements: []Element{
NewTokenType(lexer.ItemComma),
NewTokenType(lexer.ItemBinding),
NewSymbol("MORE_INPUT_GRAPHS"),
},
},
{},
},
"OUTPUT_GRAPHS": []*Clause{
{
Elements: []Element{
NewTokenType(lexer.ItemBinding),
NewSymbol("MORE_OUTPUT_GRAPHS"),
},
},
},
"MORE_OUTPUT_GRAPHS": []*Clause{
{
Elements: []Element{
NewTokenType(lexer.ItemComma),
NewTokenType(lexer.ItemBinding),
NewSymbol("MORE_OUTPUT_GRAPHS"),
},
},
{},
},
"WHERE": []*Clause{
{
Elements: []Element{
Expand Down Expand Up @@ -919,6 +955,14 @@ func SemanticBQL() *Grammar {
graphSymbols := []semantic.Symbol{"GRAPHS", "MORE_GRAPHS"}
setElementHook(semanticBQL, graphSymbols, semantic.GraphAccumulatorHook(), nil)

// Add graph binding collection to INPUT_GRAPHS and MORE_INPUT_GRAPHS clauses.
inputGraphSymbols := []semantic.Symbol{"INPUT_GRAPHS", "MORE_INPUT_GRAPHS"}
setElementHook(semanticBQL, inputGraphSymbols, semantic.InputGraphAccumulatorHook(), nil)

// Add graph binding collection to OUTPUT_GRAPHS and MORE_OUTPUT_GRAPHS clauses.
outputGraphSymbols := []semantic.Symbol{"OUTPUT_GRAPHS", "MORE_OUTPUT_GRAPHS"}
setElementHook(semanticBQL, outputGraphSymbols, semantic.OutputGraphAccumulatorHook(), nil)

// Insert and Delete semantic hooks addition.
insertSymbols := []semantic.Symbol{
"INSERT_OBJECT", "INSERT_DATA", "DELETE_OBJECT", "DELETE_DATA",
Expand Down
73 changes: 49 additions & 24 deletions bql/grammar/grammar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package grammar

import (
"reflect"
"testing"

"github.com/google/badwolf/bql/semantic"
Expand Down Expand Up @@ -255,36 +256,54 @@ func TestRejectByParse(t *testing.T) {
}
}

func TestAcceptOpsByParseAndSemantic(t *testing.T) {
func TestAcceptGraphOpsByParseAndSemantic(t *testing.T) {
var empty []string
table := []struct {
query string
graphs int
triples int
query string
graphs []string
inputGraphs []string
outputGraphs []string
triples int
}{
// Insert data.
{`insert data into ?a {/_<foo> "bar"@[1975-01-01T00:01:01.999999999Z] /_<foo>};`, 1, 1},
{`insert data into ?a {/_<foo> "bar"@[] "bar"@[1975-01-01T00:01:01.999999999Z]};`, 1, 1},
{`insert data into ?a {/_<foo> "bar"@[] "yeah"^^type:text};`, 1, 1},
// Insert into multiple graphs.
{`insert data into ?a,?b,?c {/_<foo> "bar"@[] /_<foo>};`, 3, 1},
// Create graphs. All graphs are regular graphs.
{`create graph ?foo1, ?bar1;`, []string{"?foo1", "?bar1"}, empty, empty, 0},
// Drop graphs. All graphs are regular graphs.
{`drop graph ?foo2, ?bar2;`, []string{"?foo2", "?bar2"}, empty, empty, 0},

// Insert data. All graphs are output graphs.
{`insert data into ?a {/_<foo> "bar"@[1975-01-01T00:01:01.999999999Z] /_<foo>};`, empty, empty, []string{"?a"}, 1},
{`insert data into ?a {/_<foo> "bar"@[] "bar"@[1975-01-01T00:01:01.999999999Z]};`, empty, empty, []string{"?a"}, 1},
{`insert data into ?a {/_<foo> "bar"@[] "yeah"^^type:text};`, empty, empty, []string{"?a"}, 1},
// Insert into multiple output graphs.
{`insert data into ?a,?b,?c {/_<foo> "bar"@[] /_<foo>};`, empty, empty, []string{"?a", "?b", "?c"}, 1},
// Insert multiple data.
{`insert data into ?a {/_<foo> "bar"@[] /_<foo> .
/_<foo> "bar"@[] "bar"@[1975-01-01T00:01:01.999999999Z] .
/_<foo> "bar"@[] "yeah"^^type:text};`, 1, 3},
// Delete data.
{`delete data from ?a {/_<foo> "bar"@[] /_<foo>};`, 1, 1},
{`delete data from ?a {/_<foo> "bar"@[] "bar"@[1975-01-01T00:01:01.999999999Z]};`, 1, 1},
{`delete data from ?a {/_<foo> "bar"@[] "yeah"^^type:text};`, 1, 1},
// Delete from multiple graphs.
{`delete data from ?a,?b,?c {/_<foo> "bar"@[1975-01-01T00:01:01.999999999Z] /_<foo>};`, 3, 1},
/_<foo> "bar"@[] "yeah"^^type:text};`, empty, empty, []string{"?a"}, 3},

// Delete data. All graphs are input graphs.
{`delete data from ?a {/_<foo> "bar"@[] /_<foo>};`, empty, []string{"?a"}, empty, 1},
{`delete data from ?a {/_<foo> "bar"@[] "bar"@[1975-01-01T00:01:01.999999999Z]};`, empty, []string{"?a"}, empty, 1},
{`delete data from ?a {/_<foo> "bar"@[] "yeah"^^type:text};`, empty, []string{"?a"}, empty, 1},
// Delete from multiple input graphs.
{`delete data from ?a,?b,?c {/_<foo> "bar"@[1975-01-01T00:01:01.999999999Z] /_<foo>};`, empty, []string{"?a", "?b", "?c"}, empty, 1},
// Delete multiple data.
{`delete data from ?a {/_<foo> "bar"@[] /_<foo> .
/_<foo> "bar"@[] "bar"@[1975-01-01T00:01:01.999999999Z] .
/_<foo> "bar"@[] "yeah"^^type:text};`, 1, 3},
// Create graphs.
{`create graph ?foo;`, 1, 0},
// Drop graphs.
{`drop graph ?foo, ?bar;`, 2, 0},
/_<foo> "bar"@[] "yeah"^^type:text};`, empty, []string{"?a"}, empty, 3},

// Construct data. Graphs can be input or output graphs.
{`construct {?s "predicate_1"@[] ?o1;
"predicate_2"@[] ?o2} into ?a from ?b where {?s "old_predicate_1"@[,] ?o1.
?s "old_predicate_2"@[,] ?o2.
?s "old_predicate_3"@[,] ?o3};`,
empty, []string{"?b"}, []string{"?a"}, 0},
// construct data into multiple output graphs from multple input graphs.
{`construct {?s "predicate_1"@[] ?o1;
"predicate_2"@[] ?o2} into ?a, ?b from ?c, ?d where {?s "old_predicate_1"@[,] ?o1.
?s "old_predicate_2"@[,] ?o2.
?s "old_predicate_3"@[,] ?o3};`,
empty, []string{"?c", "?d"}, []string{"?a", "?b"}, 0},
}
p, err := NewParser(SemanticBQL())
if err != nil {
Expand All @@ -295,8 +314,14 @@ func TestAcceptOpsByParseAndSemantic(t *testing.T) {
if err := p.Parse(NewLLk(entry.query, 1), st); err != nil {
t.Errorf("Parser.consume: Failed to accept entry %q with error %v", entry, err)
}
if got, want := len(st.GraphNames()), entry.graphs; got != want {
t.Errorf("Parser.consume: Failed to collect right number of graphs for case %v; got %d, want %d", entry, got, want)
if got, want := st.GraphNames(), entry.graphs; !reflect.DeepEqual(got, want) {
t.Errorf("Parser.consume: Failed to collect the right graphs for case %v; got %d, want %d", entry, got, want)
}
if got, want := st.InputGraphNames(), entry.inputGraphs; !reflect.DeepEqual(got, want) {
t.Errorf("Parser.consume: Failed to collect the right input graphs for case %v; got %d, want %d", entry, got, want)
}
if got, want := st.OutputGraphNames(), entry.outputGraphs; !reflect.DeepEqual(got, want) {
t.Errorf("Parser.consume: Failed to collect the right output graphs for case %v; got %d, want %d", entry, got, want)
}
if got, want := len(st.Data()), entry.triples; got != want {
t.Errorf("Parser.consume: Failed to collect right number of triples for case %v; got %d, want %d", entry, got, want)
Expand Down
14 changes: 7 additions & 7 deletions bql/planner/planner.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ func update(ctx context.Context, stm *semantic.Statement, store storage.Store, f
errs = append(errs, err.Error())
}

for _, graphBinding := range stm.GraphNames() {
for _, graphBinding := range stm.OutputGraphNames() {
wg.Add(1)
go func(graph string) {
defer wg.Done()
Expand Down Expand Up @@ -191,7 +191,7 @@ func (p *insertPlan) Execute(ctx context.Context) (*table.Table, error) {
// String returns a readable description of the execution plan.
func (p *insertPlan) String() string {
b := bytes.NewBufferString("INSERT plan:\n\n")
for _, g := range p.stm.Graphs() {
for _, g := range p.stm.OutputGraphs() {
b.WriteString(fmt.Sprintf("store(%q).Graph(%q).AddTriples(_, data)\n", p.store.Name(nil), g))
}
b.WriteString("where data:\n")
Expand Down Expand Up @@ -228,7 +228,7 @@ func (p *deletePlan) Execute(ctx context.Context) (*table.Table, error) {
// String returns a readable description of the execution plan.
func (p *deletePlan) String() string {
b := bytes.NewBufferString("DELETE plan:\n\n")
for _, g := range p.stm.Graphs() {
for _, g := range p.stm.InputGraphs() {
b.WriteString(fmt.Sprintf("store(%q).Graph(%q).RemoveTriples(_, data)\n", p.store.Name(nil), g))
}
b.WriteString("where data:\n")
Expand Down Expand Up @@ -270,7 +270,7 @@ func newQueryPlan(ctx context.Context, store storage.Store, stm *semantic.Statem
stm: stm,
store: store,
bndgs: bs,
grfsNames: stm.GraphNames(),
grfsNames: stm.InputGraphNames(),
cls: stm.SortedGraphPatternClauses(),
tbl: t,
chanSize: chanSize,
Expand Down Expand Up @@ -524,7 +524,7 @@ func (p *queryPlan) filterOnExistence(ctx context.Context, cls *semantic.GraphCl
return fmt.Errorf("failed to fully specify clause %v for row %+v", cls, r)
}
exist := false
for _, g := range p.stm.Graphs() {
for _, g := range p.stm.InputGraphs() {
t, err := triple.New(sbj, prd, obj)
if err != nil {
return err
Expand Down Expand Up @@ -708,12 +708,12 @@ func (p *queryPlan) limit() {
func (p *queryPlan) Execute(ctx context.Context) (*table.Table, error) {
// Fetch and catch graph instances.
trace(p.tracer, func() []string {
return []string{fmt.Sprintf("Caching graph instances for graphs %v", p.stm.GraphNames())}
return []string{fmt.Sprintf("Caching graph instances for graphs %v", p.stm.InputGraphNames())}
})
if err := p.stm.Init(ctx, p.store); err != nil {
return nil, err
}
p.grfs = p.stm.Graphs()
p.grfs = p.stm.InputGraphs()
// Retrieve the data.
lo := p.stm.GlobalLookupOptions()
trace(p.tracer, func() []string {
Expand Down
18 changes: 9 additions & 9 deletions bql/planner/planner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -501,14 +501,14 @@ func TestPlannerQuery(t *testing.T) {
}
tbl, err := plnr.Execute(ctx)
if err != nil {
t.Errorf("planner.Excecute failed for query %q with error %v", entry.q, err)
t.Errorf("planner.Execute failed for query %q with error %v", entry.q, err)
continue
}
if got, want := len(tbl.Bindings()), entry.nbs; got != want {
t.Errorf("tbl.Bindings returned the wrong number of bindings for %q; got %d, want %d", entry.q, got, want)
}
if got, want := len(tbl.Rows()), entry.nrws; got != want {
t.Errorf("planner.Excecute failed to return the expected number of rows for query %q; got %d want %d\nGot:\n%v\n", entry.q, got, want, tbl)
t.Errorf("planner.Execute failed to return the expected number of rows for query %q; got %d want %d\nGot:\n%v\n", entry.q, got, want, tbl)
}
}
}
Expand Down Expand Up @@ -552,13 +552,13 @@ func TestTreeTraversalToRoot(t *testing.T) {
}
tbl, err := plnr.Execute(ctx)
if err != nil {
t.Errorf("planner.Excecute failed for query %q with error %v", traversalQuery, err)
t.Errorf("planner.Execute failed for query %q with error %v", traversalQuery, err)
}
if got, want := len(tbl.Bindings()), 1; got != want {
t.Errorf("tbl.Bindings returned the wrong number of bindings for %q; got %d, want %d", traversalQuery, got, want)
}
if got, want := len(tbl.Rows()), 1; got != want {
t.Errorf("planner.Excecute failed to return the expected number of rows for query %q; got %d want %d\nGot:\n%v\n", traversalQuery, got, want, tbl)
t.Errorf("planner.Execute failed to return the expected number of rows for query %q; got %d want %d\nGot:\n%v\n", traversalQuery, got, want, tbl)
}
}

Expand Down Expand Up @@ -599,13 +599,13 @@ func TestChaining(t *testing.T) {
}
tbl, err := plnr.Execute(ctx)
if err != nil {
t.Errorf("planner.Excecute failed for query %q with error %v", traversalQuery, err)
t.Errorf("planner.Execute failed for query %q with error %v", traversalQuery, err)
}
if got, want := len(tbl.Bindings()), 1; got != want {
t.Errorf("tbl.Bindings returned the wrong number of bindings for %q; got %d, want %d", traversalQuery, got, want)
}
if got, want := len(tbl.Rows()), 1; got != want {
t.Errorf("planner.Excecute failed to return the expected number of rows for query %q; got %d want %d\nGot:\n%v\n", traversalQuery, got, want, tbl)
t.Errorf("planner.Execute failed to return the expected number of rows for query %q; got %d want %d\nGot:\n%v\n", traversalQuery, got, want, tbl)
}
}

Expand Down Expand Up @@ -657,13 +657,13 @@ func TestReificationResolutionIssue70(t *testing.T) {
}
tbl, err := plnr.Execute(ctx)
if err != nil {
t.Fatalf("planner.Excecute failed for query %q with error %v", query, err)
t.Fatalf("planner.Execute failed for query %q with error %v", query, err)
}
if got, want := len(tbl.Bindings()), 2; got != want {
t.Errorf("tbl.Bindings returned the wrong number of bindings for %q; got %d, want %d", query, got, want)
}
if got, want := len(tbl.Rows()), 1; got != want {
t.Errorf("planner.Excecute failed to return the expected number of rows for query %q; got %d want %d\nGot:\n%v\n", query, got, want, tbl)
t.Errorf("planner.Execute failed to return the expected number of rows for query %q; got %d want %d\nGot:\n%v\n", query, got, want, tbl)
}
}

Expand All @@ -688,7 +688,7 @@ func benchmarkQuery(query string, b *testing.B) {
}
_, err = plnr.Execute(ctx)
if err != nil {
b.Errorf("planner.Excecute failed for query %q with error %v", query, err)
b.Errorf("planner.Execute failed for query %q with error %v", query, err)
}
}
}
Expand Down
Loading

0 comments on commit 9b7b7f6

Please sign in to comment.