func TestDataAccessObjeToCell(t *testing.T) { n, p, l := testNodePredicateLiteral(t) testTable := []struct { o *triple.Object c *table.Cell }{ { o: triple.NewNodeObject(n), c: &table.Cell{N: n}, }, { o: triple.NewPredicateObject(p), c: &table.Cell{P: p}, }, { o: triple.NewLiteralObject(l), c: &table.Cell{L: l}, }, } for _, entry := range testTable { c, err := objectToCell(entry.o) if err != nil { t.Errorf("objecToCell for object %q failed with error %v", entry.o, err) } if got, want := c, entry.c; !reflect.DeepEqual(got, want) { t.Errorf("objectToCell failed to properly convert the object into a cell; got %#v, want %#v", got, want) } } }
// cellToObject returns an object for the given cell. func cellToObject(c *table.Cell) (*triple.Object, error) { if c == nil { return nil, errors.New("cannot create an object out of and empty cell") } if c.N != nil { return triple.NewNodeObject(c.N), nil } if c.P != nil { return triple.NewPredicateObject(c.P), nil } if c.L != nil { return triple.NewLiteralObject(c.L), nil } if c.S != "" { l, err := literal.DefaultBuilder().Parse(fmt.Sprintf(`"%s"^^type:string`, c.S)) if err != nil { return nil, err } return triple.NewLiteralObject(l), nil } return nil, fmt.Errorf("invalid cell %v", c) }
// whereObjectClause returns an element hook that updates the object // modifiers on the working graph clause. func whereObjectClause() ElementHook { var ( f ElementHook lastNopToken *lexer.Token ) f = func(st *Statement, ce ConsumedElement) (ElementHook, error) { if ce.IsSymbol() { return f, nil } tkn := ce.Token() c := st.WorkingClause() switch tkn.Type { case lexer.ItemNode, lexer.ItemLiteral: lastNopToken = nil if c.O != nil { return nil, fmt.Errorf("invalid object %s for object on graph clause since already set to %s", tkn.Text, c.O) } obj, err := triple.ParseObject(tkn.Text, literal.DefaultBuilder()) if err != nil { return nil, err } c.O = obj return f, nil case lexer.ItemPredicate: lastNopToken = nil if c.O != nil { return nil, fmt.Errorf("invalid predicate %s for object on graph clause since already set to %s", tkn.Text, c.O) } var ( pred *predicate.Predicate err error ) pred, c.OID, c.OAnchorBinding, err = processPredicate(c, ce, lastNopToken) if err != nil { return nil, err } if pred != nil { c.O = triple.NewPredicateObject(pred) } return f, nil case lexer.ItemPredicateBound: lastNopToken = nil if c.OLowerBound != nil || c.OUpperBound != nil || c.OLowerBoundAlias != "" || c.OUpperBoundAlias != "" { return nil, fmt.Errorf("invalid predicate bound %s on graph clause since already set to %s", tkn.Text, c.O) } oID, oLowerBoundAlias, oUpperBoundAlias, oLowerBound, oUpperBound, err := processPredicateBound(c, ce, lastNopToken) if err != nil { return nil, err } c.OID, c.OLowerBoundAlias, c.OUpperBoundAlias, c.OLowerBound, c.OUpperBound = oID, oLowerBoundAlias, oUpperBoundAlias, oLowerBound, oUpperBound return f, nil case lexer.ItemBinding: if lastNopToken == nil { if c.OBinding != "" { return nil, fmt.Errorf("object binding %q is already set to %q", tkn.Text, c.SBinding) } c.OBinding = tkn.Text return f, nil } defer func() { lastNopToken = nil }() switch lastNopToken.Type { case lexer.ItemAs: if c.OAlias != "" { return nil, fmt.Errorf("AS alias binding for predicate has already being assined on %v", st) } c.OAlias = tkn.Text case lexer.ItemType: if c.OTypeAlias != "" { return nil, fmt.Errorf("TYPE alias binding for predicate has already being assined on %v", st) } c.OTypeAlias = tkn.Text case lexer.ItemID: if c.OIDAlias != "" { return nil, fmt.Errorf("ID alias binding for predicate has already being assined on %v", st) } c.OIDAlias = tkn.Text case lexer.ItemAt: if c.OAnchorAlias != "" { return nil, fmt.Errorf("AT alias binding for predicate has already being assined on %v", st) } c.OAnchorAlias = tkn.Text default: return nil, fmt.Errorf("binding %q found after invalid token %s", tkn.Text, lastNopToken) } return f, nil } lastNopToken = tkn return f, nil } return f }
func TestWhereObjectClauseHook(t *testing.T) { st := &Statement{} f := whereObjectClause() st.ResetWorkingGraphClause() node, err := node.Parse("/_<foo>") if err != nil { t.Fatalf("node.Parse failed with error %v", err) } n := triple.NewNodeObject(node) pred, err := predicate.Parse(`"foo"@[2015-07-19T13:12:04.669618843-07:00]`) if err != nil { t.Fatalf("predicate.Parse failed with error %v", err) } p := triple.NewPredicateObject(pred) tlb, err := time.Parse(time.RFC3339Nano, `2015-07-19T13:12:04.669618843-07:00`) if err != nil { t.Fatalf("time.Parse failed to parse valid lower time bound with error %v", err) } tub, err := time.Parse(time.RFC3339Nano, `2016-07-19T13:12:04.669618843-07:00`) if err != nil { t.Fatalf("time.Parse failed to parse valid upper time bound with error %v", err) } l, err := triple.ParseObject(`"1"^^type:int64`, literal.DefaultBuilder()) if err != nil { t.Fatalf("literal.Parse should have never fail to pars %s with error %v", `"1"^^type:int64`, err) } runTabulatedClauseHookTest(t, "semantic.whereObjectClause", f, []testClauseTable{ { valid: true, id: "node_example", ces: []ConsumedElement{ NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemNode, Text: "/_<foo>", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemAs, Text: "as", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar", }), NewConsumedToken(&lexer.Token{ Type: lexer.ItemType, Text: "type", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar2", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemID, Text: "id", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar3", }), NewConsumedSymbol("FOO"), }, want: &GraphClause{ O: n, OAlias: "?bar", OTypeAlias: "?bar2", OIDAlias: "?bar3", }, }, { valid: true, id: "binding_example", ces: []ConsumedElement{ NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?foo", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemAs, Text: "as", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar", }), NewConsumedToken(&lexer.Token{ Type: lexer.ItemType, Text: "type", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar2", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemID, Text: "id", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar3", }), NewConsumedSymbol("FOO"), }, want: &GraphClause{ OBinding: "?foo", OAlias: "?bar", OTypeAlias: "?bar2", OIDAlias: "?bar3", }, }, { valid: true, id: "valid predicate", ces: []ConsumedElement{ NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemPredicate, Text: `"foo"@[2015-07-19T13:12:04.669618843-07:00]`, }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemAs, Text: "as", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar", }), NewConsumedToken(&lexer.Token{ Type: lexer.ItemID, Text: "id", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar2", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemAt, Text: "at", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar3", }), NewConsumedSymbol("FOO"), }, want: &GraphClause{ O: p, OAlias: "?bar", OIDAlias: "?bar2", OAnchorAlias: "?bar3", OTemporal: true, }, }, { valid: true, id: "valid predicate with binding", ces: []ConsumedElement{ NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemPredicate, Text: `"foo"@[?foo]`, }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemAs, Text: "as", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar", }), NewConsumedToken(&lexer.Token{ Type: lexer.ItemID, Text: "id", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar2", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemAt, Text: "at", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar3", }), NewConsumedSymbol("FOO"), }, want: &GraphClause{ OID: "foo", OAnchorBinding: "?foo", OAlias: "?bar", OIDAlias: "?bar2", OAnchorAlias: "?bar3", OTemporal: true, }, }, { valid: true, id: "valid bound with bindings", ces: []ConsumedElement{ NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemPredicateBound, Text: `"foo"@[?fooLower,?fooUpper]`, }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemAs, Text: "as", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar", }), NewConsumedToken(&lexer.Token{ Type: lexer.ItemID, Text: "id", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar2", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemAt, Text: "at", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar3", }), NewConsumedSymbol("FOO"), }, want: &GraphClause{ OID: "foo", OLowerBoundAlias: "?fooLower", OUpperBoundAlias: "?fooUpper", OAlias: "?bar", OIDAlias: "?bar2", OAnchorAlias: "?bar3", OTemporal: true, }, }, { valid: true, id: "valid bound with dates", ces: []ConsumedElement{ NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemPredicateBound, Text: `"foo"@[2015-07-19T13:12:04.669618843-07:00,2016-07-19T13:12:04.669618843-07:00]`, }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemAs, Text: "as", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar", }), NewConsumedToken(&lexer.Token{ Type: lexer.ItemID, Text: "id", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar2", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemAt, Text: "at", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar3", }), NewConsumedSymbol("FOO"), }, want: &GraphClause{ OID: "foo", OLowerBound: &tlb, OUpperBound: &tub, OAlias: "?bar", OIDAlias: "?bar2", OAnchorAlias: "?bar3", OTemporal: true, }, }, { valid: false, id: "invalid bound with dates", ces: []ConsumedElement{ NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemPredicateBound, Text: `"foo"@[2016-07-19T13:12:04.669618843-07:00,2015-07-19T13:12:04.669618843-07:00]`, }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemAs, Text: "as", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar", }), NewConsumedToken(&lexer.Token{ Type: lexer.ItemID, Text: "id", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar2", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemAt, Text: "at", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar3", }), NewConsumedSymbol("FOO"), }, want: &GraphClause{}, }, { valid: true, id: "literal with alias", ces: []ConsumedElement{ NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemLiteral, Text: `"1"^^type:int64`, }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemAs, Text: "as", }), NewConsumedSymbol("FOO"), NewConsumedToken(&lexer.Token{ Type: lexer.ItemBinding, Text: "?bar", }), NewConsumedSymbol("FOO"), }, want: &GraphClause{ O: l, OAlias: "?bar"}, }, }) }