Example #1
0
func TestDataAccessTripleToRowObjectBindingsDroping(t *testing.T) {
	n, p, _ := testNodeTemporalPredicateLiteral(t)
	ts, err := p.TimeAnchor()
	if err != nil {
		t.Fatal(err)
	}
	testTable := []struct {
		t   string
		cls *semantic.GraphClause
		bc  *table.Cell
		ac  *table.Cell
		tc  *table.Cell
		ic  *table.Cell
		tsc *table.Cell
		atc *table.Cell
	}{
		{
			t: n.String() + "\t" + p.String() + "\t" + n.String(),
			cls: &semantic.GraphClause{
				OBinding:   "?o",
				OAlias:     "?alias",
				OTypeAlias: "?o",
				OIDAlias:   "?id",
			},
			bc: &table.Cell{N: n},
			ac: &table.Cell{N: n},
			tc: &table.Cell{S: table.CellString(n.Type().String())},
			ic: &table.Cell{S: table.CellString(n.ID().String())},
		},
		{
			t: n.String() + "\t" + p.String() + "\t" + p.String(),
			cls: &semantic.GraphClause{
				OBinding:       "?o",
				OAlias:         "?alias",
				OIDAlias:       "?id",
				OAnchorBinding: "?ts",
				OAnchorAlias:   "?o",
			},
			bc:  &table.Cell{P: p},
			ac:  &table.Cell{P: p},
			ic:  &table.Cell{S: table.CellString(string(p.ID()))},
			tsc: &table.Cell{T: ts},
			atc: &table.Cell{T: ts},
		},
	}
	for _, entry := range testTable {
		tpl, err := triple.Parse(entry.t, literal.DefaultBuilder())
		if err != nil {
			t.Errorf("triple.Parse failed to parse valid triple %q with error %v", entry.t, err)
		}
		r, err := tripleToRow(tpl, entry.cls)
		if err != nil {
			t.Errorf("tripleToRow for triple %q and clasuse %v, failed with error %v", tpl, entry.cls, err)
		}
		if r != nil {
			t.Errorf("tripleToRow for triple %q and clasuse %v, failed to drop triple and returned %v", tpl, entry.cls, r)
		}
	}
}
Example #2
0
func TestDataAccessTripleToRowSubjectBindings(t *testing.T) {
	n, p, _ := testNodePredicateLiteral(t)
	testTable := []struct {
		t   string
		cls *semantic.GraphClause
		sc  *table.Cell
		ac  *table.Cell
		tc  *table.Cell
		ic  *table.Cell
	}{
		{
			t: n.String() + "\t" + p.String() + "\t" + n.String(),
			cls: &semantic.GraphClause{
				SBinding:   "?s",
				SAlias:     "?alias",
				STypeAlias: "?type",
				SIDAlias:   "?id",
			},
			sc: &table.Cell{N: n},
			ac: &table.Cell{N: n},
			tc: &table.Cell{S: table.CellString(n.Type().String())},
			ic: &table.Cell{S: table.CellString(n.ID().String())},
		},
	}
	for _, entry := range testTable {
		tpl, err := triple.Parse(entry.t, literal.DefaultBuilder())
		if err != nil {
			t.Errorf("triple.Parse failed to parse valid triple %q with error %v", entry.t, err)
		}
		r, err := tripleToRow(tpl, entry.cls)
		if err != nil {
			t.Errorf("tripleToRow for triple %q and clasuse %v, failed with error %v", tpl, entry.cls, err)
		}
		if got, want := r["?s"], entry.sc; !reflect.DeepEqual(got, want) {
			t.Errorf("tripleToRow failed to return right value for binding \"?s\"; got %q, want %q", got, want)
		}
		if got, want := r["?alias"], entry.ac; !reflect.DeepEqual(got, want) {
			t.Errorf("tripleToRow failed to return right value for binding alias \"?alias\"; got %q, want %q", got, want)
		}
		if got, want := r["?type"], entry.tc; !reflect.DeepEqual(got, want) {
			t.Errorf("tripleToRow failed to return right value for binding \"?type\"; got %q, want %q", got, want)
		}
		if got, want := r["?id"], entry.ic; !reflect.DeepEqual(got, want) {
			t.Errorf("tripleToRow failed to return right value for binding \"?ud\"; got %q, want %q", got, want)
		}
	}
}
Example #3
0
func TestDataAccessTripleToRowPredicateBindings(t *testing.T) {
	n, p, _ := testNodeTemporalPredicateLiteral(t)
	ts, err := p.TimeAnchor()
	if err != nil {
		t.Fatal(err)
	}
	testTable := []struct {
		t   string
		cls *semantic.GraphClause
		bc  *table.Cell
		ac  *table.Cell
		ic  *table.Cell
		tc  *table.Cell
		atc *table.Cell
	}{
		{
			t: n.String() + "\t" + p.String() + "\t" + n.String(),
			cls: &semantic.GraphClause{
				PBinding:       "?p",
				PAlias:         "?alias",
				PIDAlias:       "?id",
				PAnchorBinding: "?ts",
				PAnchorAlias:   "?tsa",
			},
			bc:  &table.Cell{P: p},
			ac:  &table.Cell{P: p},
			ic:  &table.Cell{S: table.CellString(string(p.ID()))},
			tc:  &table.Cell{T: ts},
			atc: &table.Cell{T: ts},
		},
	}
	for _, entry := range testTable {
		tpl, err := triple.Parse(entry.t, literal.DefaultBuilder())
		if err != nil {
			t.Errorf("triple.Parse failed to parse valid triple %q with error %v", entry.t, err)
		}
		r, err := tripleToRow(tpl, entry.cls)
		if err != nil {
			t.Errorf("tripleToRow for triple %q and clasuse %v, failed with error %v", tpl, entry.cls, err)
		}
		if got, want := r["?p"], entry.bc; !reflect.DeepEqual(got, want) {
			t.Errorf("tripleToRow failed to return right value for binding \"?p\"; got %q, want %q", got, want)
		}
		if got, want := r["?alias"], entry.ac; !reflect.DeepEqual(got, want) {
			t.Errorf("tripleToRow failed to return right value for binding alias \"?alias\"; got %q, want %q", got, want)
		}
		if got, want := r["?id"], entry.ic; !reflect.DeepEqual(got, want) {
			t.Errorf("tripleToRow failed to return right value for binding \"?id\"; got %q, want %q", got, want)
		}
		if got, want := r["?ts"], entry.tc; !reflect.DeepEqual(got, want) {
			t.Errorf("tripleToRow failed to return right value for binding \"?ts\"; got %q, want %q", got, want)
		}
		if got, want := r["?tsa"], entry.tc; !reflect.DeepEqual(got, want) {
			t.Errorf("tripleToRow failed to return right value for binding \"?tsa\"; got %q, want %q", got, want)
		}
	}
}
Example #4
0
// inferCell builds a Cell out of the provided string.
func inferCell(s string) *table.Cell {
	if n, err := node.Parse(s); err == nil {
		return &table.Cell{N: n}
	}
	if p, err := predicate.Parse(s); err == nil {
		return &table.Cell{P: p}
	}
	if l, err := literal.DefaultBuilder().Parse(s); err == nil {
		return &table.Cell{L: l}
	}
	t, err := time.Parse(time.RFC3339Nano, s)
	if err == nil {
		return &table.Cell{T: &t}
	}
	return &table.Cell{S: table.CellString(s)}
}
Example #5
0
func TestEvaluationNode(t *testing.T) {
	testTable := []struct {
		eval Evaluator
		r    table.Row
		want bool
		err  bool
	}{
		{
			eval: &evaluationNode{EQ, "?foo", "?wrong_binding"},
			r: table.Row{
				"?foo": &table.Cell{S: table.CellString("foo")},
				"?bar": &table.Cell{S: table.CellString("foo")},
			},
			want: false,
			err:  true,
		},
		{
			eval: &evaluationNode{EQ, "?foo", "?bar"},
			r: table.Row{
				"?foo": &table.Cell{S: table.CellString("foo")},
				"?bar": &table.Cell{S: table.CellString("bar")},
			},
			want: false,
			err:  false,
		},
		{
			eval: &evaluationNode{EQ, "", "?bar"},
			r: table.Row{
				"?foo": &table.Cell{S: table.CellString("foo")},
				"?bar": &table.Cell{S: table.CellString("bar")},
			},
			want: false,
			err:  true,
		},
		{
			eval: &evaluationNode{EQ, "?foo", ""},
			r: table.Row{
				"?foo": &table.Cell{S: table.CellString("foo")},
				"?bar": &table.Cell{S: table.CellString("bar")},
			},
			want: false,
			err:  true,
		},
		{
			eval: &evaluationNode{EQ, "?foo", "?bar"},
			r: table.Row{
				"?foo": &table.Cell{S: table.CellString("foo")},
				"?bar": &table.Cell{S: table.CellString("foo")},
			},
			want: true,
			err:  false,
		},
		{
			eval: &evaluationNode{LT, "?foo", "?bar"},
			r: table.Row{
				"?foo": &table.Cell{S: table.CellString("foo")},
				"?bar": &table.Cell{S: table.CellString("bar")},
			},
			want: false,
			err:  false,
		},
		{
			eval: &evaluationNode{GT, "?foo", "?bar"},
			r: table.Row{
				"?foo": &table.Cell{S: table.CellString("foo")},
				"?bar": &table.Cell{S: table.CellString("bar")},
			},
			want: true,
			err:  false,
		},
	}
	for _, entry := range testTable {
		got, err := entry.eval.Evaluate(entry.r)
		if !entry.err && err != nil {
			t.Errorf("failed to evaluate op %q for %v on row %v with error %v", entry.eval.(*evaluationNode).op, entry.eval, entry.r, err)
		}
		if want := entry.want; got != want {
			t.Errorf("failed to evaluate op %q for %v on row %v; got %v, want %v", entry.eval.(*evaluationNode).op, entry.eval, entry.r, got, want)
		}
	}
}
Example #6
0
func TestNewEvaluator(t *testing.T) {
	testTable := []struct {
		id   string
		in   []ConsumedElement
		r    table.Row
		err  bool
		want bool
	}{
		{
			id: "?foo = ?bar",
			in: []ConsumedElement{
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemBinding,
					Text: "?foo",
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemEQ,
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemBinding,
					Text: "?bar",
				}),
			},
			r: table.Row{
				"?foo": &table.Cell{S: table.CellString("VALUE")},
				"?bar": &table.Cell{S: table.CellString("VALUE")},
			},
			err:  false,
			want: true,
		},
		{
			id: "?foo < ?bar",
			in: []ConsumedElement{
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemBinding,
					Text: "?foo",
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemLT,
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemBinding,
					Text: "?bar",
				}),
			},
			r: table.Row{
				"?foo": &table.Cell{S: table.CellString("foo")},
				"?bar": &table.Cell{S: table.CellString("bar")},
			},
			err:  false,
			want: false,
		},
		{
			id: "?foo > ?bar",
			in: []ConsumedElement{
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemBinding,
					Text: "?foo",
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemGT,
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemBinding,
					Text: "?bar",
				}),
			},
			r: table.Row{
				"?foo": &table.Cell{S: table.CellString("foo")},
				"?bar": &table.Cell{S: table.CellString("bar")},
			},
			err:  false,
			want: true,
		},
		{
			id: "not(?foo = ?bar)",
			in: []ConsumedElement{
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemNot,
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemLPar,
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemBinding,
					Text: "?foo",
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemEQ,
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemBinding,
					Text: "?bar",
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemRPar,
				}),
			},
			r: table.Row{
				"?foo": &table.Cell{S: table.CellString("VALUE")},
				"?bar": &table.Cell{S: table.CellString("VALUE")},
			},
			err:  false,
			want: false,
		},
		{
			id: "(?foo < ?bar) or (?foo > ?bar)",
			in: []ConsumedElement{
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemLPar,
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemBinding,
					Text: "?foo",
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemLT,
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemBinding,
					Text: "?bar",
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemRPar,
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemOr,
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemLPar,
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemBinding,
					Text: "?foo",
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemGT,
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemBinding,
					Text: "?bar",
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemRPar,
				}),
			},
			r: table.Row{
				"?foo": &table.Cell{S: table.CellString("foo")},
				"?bar": &table.Cell{S: table.CellString("bar")},
			},
			err:  false,
			want: true,
		},
		{
			id: "(?foo < ?bar) and (?foo > ?bar)",
			in: []ConsumedElement{
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemLPar,
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemBinding,
					Text: "?foo",
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemLT,
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemBinding,
					Text: "?bar",
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemRPar,
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemAnd,
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemLPar,
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemBinding,
					Text: "?foo",
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemGT,
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemBinding,
					Text: "?bar",
				}),
				NewConsumedToken(&lexer.Token{
					Type: lexer.ItemRPar,
				}),
			},
			r: table.Row{
				"?foo": &table.Cell{S: table.CellString("foo")},
				"?bar": &table.Cell{S: table.CellString("bar")},
			},
			err:  false,
			want: false,
		},
	}
	for _, entry := range testTable {
		eval, err := NewEvaluator(entry.in)
		if !entry.err && err != nil {
			t.Fatalf("test %q should have never failed to process %v with error %v", entry.id, entry.in, err)
		}
		got, err := eval.Evaluate(entry.r)
		if err != nil {
			t.Errorf("test %q the created evaluator failed to evaluate row %v with error %v", entry.id, entry.r, err)
		}
		if want := entry.want; got != want {
			t.Errorf("test %q failed to evaluate the proper value; got %v, want %v", entry.id, got, want)
		}
	}
}
Example #7
0
func TestHavingExpressionBuilder(t *testing.T) {
	f := havingExpressionBuilder()
	testTable := []struct {
		id   string
		s    *Statement
		r    table.Row
		want bool
	}{
		{
			id:   "empty statement",
			s:    &Statement{},
			want: true,
		},
		{
			id: "(?foo < ?bar) or (?foo > ?bar)",
			s: &Statement{
				havingExpression: []ConsumedElement{
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemLPar,
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemBinding,
						Text: "?foo",
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemLT,
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemBinding,
						Text: "?bar",
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemRPar,
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemOr,
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemLPar,
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemBinding,
						Text: "?foo",
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemGT,
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemBinding,
						Text: "?bar",
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemRPar,
					}),
				},
			},
			r: table.Row{
				"?foo": &table.Cell{S: table.CellString("foo")},
				"?bar": &table.Cell{S: table.CellString("bar")},
			},
			want: true,
		},
		{
			id: "not((?foo < ?bar) or (?foo > ?bar))",
			s: &Statement{
				havingExpression: []ConsumedElement{
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemNot,
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemLPar,
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemLPar,
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemBinding,
						Text: "?foo",
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemLT,
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemBinding,
						Text: "?bar",
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemRPar,
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemOr,
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemLPar,
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemBinding,
						Text: "?foo",
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemGT,
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemBinding,
						Text: "?bar",
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemRPar,
					}),
					NewConsumedToken(&lexer.Token{
						Type: lexer.ItemRPar,
					}),
				},
			},
			r: table.Row{
				"?foo": &table.Cell{S: table.CellString("foo")},
				"?bar": &table.Cell{S: table.CellString("bar")},
			},
			want: false,
		},
	}
	for _, entry := range testTable {
		if _, err := f(entry.s, Symbol("FOO")); err != nil {
			t.Errorf("semantic.havingExpressionBuilder faile to build statement %#v for case %q with error %v", entry.s, entry.id, err)
		}
		got, err := entry.s.havingExpressionEvaluator.Evaluate(entry.r)
		if err != nil {
			t.Errorf("expression evaluator should have not fail with errorf %v for case %q", err, entry.id)
		}
		if want := entry.want; got != want {
			t.Errorf("expression evaluator returned the wrong value for case %q; got %v, want %v", entry.id, got, want)
		}
	}
}
Example #8
0
// tripleToRow converts a triple into a row using the binndings specidfied
// on the graph clause.
func tripleToRow(t *triple.Triple, cls *semantic.GraphClause) (table.Row, error) {
	r, s, p, o := make(table.Row), t.Subject(), t.Predicate(), t.Object()

	// Enforce binding validity inside te clause.
	bnd := make(map[string]*table.Cell)
	validBinding := func(k string, v *table.Cell) bool {
		c, ok := bnd[k]
		bnd[k] = v
		if !ok {
			return true
		}
		if reflect.DeepEqual(c, v) {
			return true
		}
		return false
	}

	// Subject related bindings.
	if cls.SBinding != "" {
		c := &table.Cell{N: s}
		r[cls.SBinding] = c
		if !validBinding(cls.SBinding, c) {
			return nil, nil
		}
	}
	if cls.SAlias != "" {
		c := &table.Cell{N: s}
		r[cls.SAlias] = c
		if !validBinding(cls.SAlias, c) {
			return nil, nil
		}
	}
	if cls.STypeAlias != "" {
		c := &table.Cell{S: table.CellString(s.Type().String())}
		r[cls.STypeAlias] = c
		if !validBinding(cls.STypeAlias, c) {
			return nil, nil
		}
	}
	if cls.SIDAlias != "" {
		c := &table.Cell{S: table.CellString(s.ID().String())}
		r[cls.SIDAlias] = c
		if !validBinding(cls.SIDAlias, c) {
			return nil, nil
		}
	}

	// Predicate related bindings.
	if cls.PBinding != "" {
		c := &table.Cell{P: p}
		r[cls.PBinding] = c
		if !validBinding(cls.PBinding, c) {
			return nil, nil
		}
	}
	if cls.PAlias != "" {
		c := &table.Cell{P: p}
		r[cls.PAlias] = c
		if !validBinding(cls.PAlias, c) {
			return nil, nil
		}
	}
	if cls.PIDAlias != "" {
		c := &table.Cell{S: table.CellString(string(p.ID()))}
		r[cls.PIDAlias] = c
		if !validBinding(cls.PIDAlias, c) {
			return nil, nil
		}
	}
	if cls.PAnchorBinding != "" {
		if p.Type() != predicate.Temporal {
			return nil, fmt.Errorf("cannot retrieve the time anchor value for non temporal predicate %q in binding %q", p, cls.PAnchorBinding)
		}
		t, err := p.TimeAnchor()
		if err != nil {
			return nil, fmt.Errorf("failed to retrieve the time anchor value for predicate %q in binding %q with error %v", p, cls.PAnchorBinding, err)
		}
		c := &table.Cell{T: t}
		r[cls.PAnchorBinding] = c
		if !validBinding(cls.PAnchorBinding, c) {
			return nil, nil
		}
	}

	if cls.PAnchorAlias != "" {
		if p.Type() != predicate.Temporal {
			return nil, fmt.Errorf("cannot retrieve the time anchor value for non temporal predicate %q in binding %q", p, cls.PAnchorAlias)
		}
		t, err := p.TimeAnchor()
		if err != nil {
			return nil, fmt.Errorf("failed to retrieve the time anchor value for predicate %q in binding %q with error %v", p, cls.PAnchorAlias, err)
		}
		c := &table.Cell{T: t}
		r[cls.PAnchorAlias] = c
		if !validBinding(cls.PAnchorAlias, c) {
			return nil, nil
		}
	}

	// Object related bindings.
	if cls.OBinding != "" {
		// Extract the object type.
		c, err := objectToCell(o)
		if err != nil {
			return nil, err
		}
		r[cls.OBinding] = c
		if !validBinding(cls.OBinding, c) {
			return nil, nil
		}
	}
	if cls.OAlias != "" {
		// Extract the object type.
		c, err := objectToCell(o)
		if err != nil {
			return nil, err
		}
		r[cls.OAlias] = c
		if !validBinding(cls.OAlias, c) {
			return nil, nil
		}
	}
	if cls.OTypeAlias != "" {
		n, err := o.Node()
		if err != nil {
			return nil, err
		}
		c := &table.Cell{S: table.CellString(n.Type().String())}
		r[cls.OTypeAlias] = c
		if !validBinding(cls.OTypeAlias, c) {
			return nil, nil
		}
	}
	if cls.OIDAlias != "" {
		n, err := o.Node()
		if err == nil {
			r[cls.OIDAlias] = &table.Cell{S: table.CellString(n.ID().String())}
		} else {
			p, err := o.Predicate()
			if err != nil {
				return nil, err
			}
			c := &table.Cell{S: table.CellString(string(p.ID()))}
			r[cls.OIDAlias] = c
			if !validBinding(cls.OIDAlias, c) {
				return nil, nil
			}
		}
	}
	if cls.OAnchorBinding != "" {
		p, err := o.Predicate()
		if err != nil {
			return nil, err
		}
		ts, err := p.TimeAnchor()
		if err != nil {
			return nil, err
		}
		c := &table.Cell{T: ts}
		r[cls.OAnchorBinding] = c
		if !validBinding(cls.OAnchorBinding, c) {
			return nil, nil
		}
	}
	if cls.OAnchorAlias != "" {
		p, err := o.Predicate()
		if err != nil {
			return nil, err
		}
		ts, err := p.TimeAnchor()
		if err != nil {
			return nil, err
		}
		c := &table.Cell{T: ts}
		r[cls.OAnchorAlias] = c
		if !validBinding(cls.OAnchorAlias, c) {
			return nil, nil
		}
	}

	return r, nil
}