-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
schema: split schema package into multiple files
- Loading branch information
Showing
8 changed files
with
1,341 additions
and
1,269 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,289 @@ | ||
package schema_test | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/cayleygraph/cayley/graph" | ||
"github.com/cayleygraph/cayley/graph/iterator" | ||
"github.com/cayleygraph/cayley/graph/memstore" | ||
"github.com/cayleygraph/cayley/quad" | ||
"github.com/cayleygraph/cayley/schema" | ||
) | ||
|
||
func TestLoadIteratorTo(t *testing.T) { | ||
sch := schema.NewConfig() | ||
for i, c := range testFillValueCases { | ||
t.Run(c.name, func(t *testing.T) { | ||
qs := memstore.New(c.quads...) | ||
out := reflect.New(reflect.TypeOf(c.expect)) | ||
var it graph.Iterator | ||
if c.from != nil { | ||
fixed := iterator.NewFixed() | ||
for _, id := range c.from { | ||
fixed.Add(qs.ValueOf(id)) | ||
} | ||
it = fixed | ||
} | ||
depth := c.depth | ||
if depth == 0 { | ||
depth = -1 | ||
} | ||
if err := sch.LoadIteratorToDepth(nil, qs, out, depth, it); err != nil { | ||
t.Errorf("case %d failed: %v", i+1, err) | ||
return | ||
} | ||
got := out.Elem().Interface() | ||
if s, ok := got.(interface { | ||
Sort() | ||
}); ok { | ||
s.Sort() | ||
} | ||
if s, ok := c.expect.(interface { | ||
Sort() | ||
}); ok { | ||
s.Sort() | ||
} | ||
if !reflect.DeepEqual(got, c.expect) { | ||
t.Errorf("case %d failed: objects are different\n%#v\n%#v", | ||
i+1, out.Elem().Interface(), c.expect, | ||
) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
var testFillValueCases = []struct { | ||
name string | ||
expect interface{} | ||
quads []quad.Quad | ||
depth int | ||
from []quad.Value | ||
}{ | ||
{ | ||
name: "complex object", | ||
expect: struct { | ||
rdfType struct{} `quad:"rdf:type > some:Type"` | ||
ID quad.IRI `quad:"@id"` | ||
Name string `quad:"name"` | ||
Values []string `quad:"values"` | ||
Items []item `quad:"items"` | ||
Sub *item `quad:"sub"` | ||
Val int `quad:"val"` | ||
}{ | ||
ID: "1234", | ||
Name: "some item", | ||
Values: []string{"val1", "val2"}, | ||
Items: []item{ | ||
{ID: "sub1", Name: "Sub 1"}, | ||
{ID: "sub2", Name: "Sub 2"}, | ||
}, | ||
Sub: &item{ID: "sub3", Name: "Sub 3"}, | ||
Val: 123, | ||
}, | ||
quads: []quad.Quad{ | ||
{iri("1234"), typeIRI, iri("some:Type"), nil}, | ||
{iri("1234"), iri("name"), quad.String("some item"), nil}, | ||
{iri("1234"), iri("values"), quad.String("val1"), nil}, | ||
{iri("1234"), iri("values"), quad.String("val2"), nil}, | ||
{iri("sub1"), typeIRI, iri("some:item"), nil}, | ||
{iri("sub1"), iri("name"), quad.String("Sub 1"), nil}, | ||
{iri("1234"), iri("items"), iri("sub1"), nil}, | ||
{iri("sub2"), typeIRI, iri("some:item"), nil}, | ||
{iri("sub2"), iri("name"), quad.String("Sub 2"), nil}, | ||
{iri("1234"), iri("items"), iri("sub2"), nil}, | ||
{iri("sub3"), typeIRI, iri("some:item"), nil}, | ||
{iri("sub3"), iri("name"), quad.String("Sub 3"), nil}, | ||
{iri("1234"), iri("sub"), iri("sub3"), nil}, | ||
{iri("1234"), iri("val"), quad.Int(123), nil}, | ||
}, | ||
}, | ||
{ | ||
name: "complex object (id value)", | ||
expect: struct { | ||
rdfType struct{} `quad:"rdf:type > some:Type"` | ||
ID quad.Value `quad:"@id"` | ||
Name string `quad:"name"` | ||
Values []string `quad:"values"` | ||
Items []item `quad:"items"` | ||
}{ | ||
ID: quad.BNode("1234"), | ||
Name: "some item", | ||
Values: []string{"val1", "val2"}, | ||
Items: []item{ | ||
{ID: "sub1", Name: "Sub 1"}, | ||
{ID: "sub2", Name: "Sub 2"}, | ||
}, | ||
}, | ||
quads: []quad.Quad{ | ||
{quad.BNode("1234"), typeIRI, iri("some:Type"), nil}, | ||
{quad.BNode("1234"), iri("name"), quad.String("some item"), nil}, | ||
{quad.BNode("1234"), iri("values"), quad.String("val1"), nil}, | ||
{quad.BNode("1234"), iri("values"), quad.String("val2"), nil}, | ||
{iri("sub1"), typeIRI, iri("some:item"), nil}, | ||
{iri("sub1"), iri("name"), quad.String("Sub 1"), nil}, | ||
{quad.BNode("1234"), iri("items"), iri("sub1"), nil}, | ||
{iri("sub2"), typeIRI, iri("some:item"), nil}, | ||
{iri("sub2"), iri("name"), quad.String("Sub 2"), nil}, | ||
{quad.BNode("1234"), iri("items"), iri("sub2"), nil}, | ||
}, | ||
}, | ||
{ | ||
name: "embedded object", | ||
expect: struct { | ||
rdfType struct{} `quad:"rdf:type > some:Type"` | ||
item2 | ||
ID quad.IRI `quad:"@id"` | ||
Values []string `quad:"values"` | ||
}{ | ||
item2: item2{Name: "Sub 1", Spec: "special"}, | ||
ID: "1234", | ||
Values: []string{"val1", "val2"}, | ||
}, | ||
quads: []quad.Quad{ | ||
{iri("1234"), typeIRI, iri("some:Type"), nil}, | ||
{iri("1234"), iri("name"), quad.String("Sub 1"), nil}, | ||
{iri("1234"), iri("spec"), quad.String("special"), nil}, | ||
{iri("1234"), iri("values"), quad.String("val1"), nil}, | ||
{iri("1234"), iri("values"), quad.String("val2"), nil}, | ||
}, | ||
}, | ||
{ | ||
name: "type shorthand", | ||
expect: struct { | ||
rdfType struct{} `quad:"@type > some:Type"` | ||
item2 | ||
ID quad.IRI `quad:"@id"` | ||
Values []string `quad:"values"` | ||
}{ | ||
item2: item2{Name: "Sub 1", Spec: "special"}, | ||
ID: "1234", | ||
Values: []string{"val1", "val2"}, | ||
}, | ||
quads: []quad.Quad{ | ||
{iri("1234"), typeIRI, iri("some:Type"), nil}, | ||
{iri("1234"), iri("name"), quad.String("Sub 1"), nil}, | ||
{iri("1234"), iri("spec"), quad.String("special"), nil}, | ||
{iri("1234"), iri("values"), quad.String("val1"), nil}, | ||
{iri("1234"), iri("values"), quad.String("val2"), nil}, | ||
}, | ||
}, | ||
{ | ||
name: "tree", | ||
expect: treeItem{ | ||
ID: iri("n1"), | ||
Name: "Node 1", | ||
Children: []treeItem{ | ||
{ | ||
ID: iri("n2"), | ||
Name: "Node 2", | ||
}, | ||
{ | ||
ID: iri("n3"), | ||
Name: "Node 3", | ||
Children: []treeItem{ | ||
{ | ||
ID: iri("n4"), | ||
Name: "Node 4", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
quads: treeQuads, | ||
from: []quad.Value{iri("n1")}, | ||
}, | ||
{ | ||
name: "tree with depth limit 1", | ||
expect: treeItem{ | ||
ID: iri("n1"), | ||
Name: "Node 1", | ||
Children: []treeItem{ | ||
{ | ||
ID: iri("n2"), | ||
Name: "Node 2", | ||
}, | ||
{ | ||
ID: iri("n3"), | ||
Name: "Node 3", | ||
Children: []treeItem{ | ||
{ | ||
ID: iri("n4"), | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
depth: 1, | ||
quads: treeQuads, | ||
from: []quad.Value{iri("n1")}, | ||
}, | ||
{ | ||
name: "tree with depth limit 2", | ||
expect: treeItemOpt{ | ||
ID: iri("n1"), | ||
Name: "Node 1", | ||
Children: []treeItemOpt{ | ||
{ | ||
ID: iri("n2"), | ||
Name: "Node 2", | ||
}, | ||
{ | ||
ID: iri("n3"), | ||
Name: "Node 3", | ||
Children: []treeItemOpt{ | ||
{ | ||
ID: iri("n4"), | ||
Name: "Node 4", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
depth: 2, | ||
quads: treeQuads, | ||
from: []quad.Value{iri("n1")}, | ||
}, | ||
{ | ||
name: "tree with required children", | ||
expect: treeItemReq{ | ||
ID: iri("n1"), | ||
Name: "Node 1", | ||
Children: []treeItemReq{ | ||
{ | ||
ID: iri("n3"), | ||
Name: "Node 3", | ||
// TODO(dennwc): a strange behavior: this field is required, but it's empty for current object, | ||
// because all it's children are missing the same field. Leaving this as-is for now because | ||
// it's weird to set Children field as required in a tree. | ||
Children: nil, | ||
}, | ||
}, | ||
}, | ||
quads: treeQuads, | ||
from: []quad.Value{iri("n1")}, | ||
}, | ||
{ | ||
name: "simple object", | ||
expect: subObject{ | ||
genObject: genObject{ | ||
ID: "1234", | ||
Name: "Obj", | ||
}, | ||
Num: 3, | ||
}, | ||
quads: []quad.Quad{ | ||
{iri("1234"), iri("name"), quad.String("Obj"), nil}, | ||
{iri("1234"), iri("num"), quad.Int(3), nil}, | ||
}, | ||
}, | ||
{ | ||
name: "coords", | ||
expect: Coords{Lat: 12.3, Lng: 34.5}, | ||
quads: []quad.Quad{ | ||
{iri("c1"), typeIRI, iri("ex:Coords"), nil}, | ||
{iri("c1"), iri("ex:lat"), quad.Float(12.3), nil}, | ||
{iri("c1"), iri("ex:lng"), quad.Float(34.5), nil}, | ||
}, | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package schema | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"reflect" | ||
|
||
"github.com/cayleygraph/cayley/graph" | ||
"github.com/cayleygraph/cayley/quad" | ||
"github.com/cayleygraph/cayley/voc" | ||
) | ||
|
||
type namespace struct { | ||
_ struct{} `quad:"@type > cayley:namespace"` | ||
Full quad.IRI `quad:"@id"` | ||
Prefix quad.IRI `quad:"cayley:prefix"` | ||
} | ||
|
||
// WriteNamespaces will writes namespaces list into graph. | ||
func (c *Config) WriteNamespaces(w quad.Writer, n *voc.Namespaces) error { | ||
rules, err := c.rulesFor(reflect.TypeOf(namespace{})) | ||
if err != nil { | ||
return fmt.Errorf("can't load rules: %v", err) | ||
} | ||
wr := c.newWriter(w) | ||
for _, ns := range n.List() { | ||
obj := namespace{ | ||
Full: quad.IRI(ns.Full), | ||
Prefix: quad.IRI(ns.Prefix), | ||
} | ||
rv := reflect.ValueOf(obj) | ||
if err = wr.writeValueAs(obj.Full, rv, "", rules); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// LoadNamespaces will load namespaces stored in graph to a specified list. | ||
// If destination list is empty, global namespace registry will be used. | ||
func (c *Config) LoadNamespaces(ctx context.Context, qs graph.QuadStore, dest *voc.Namespaces) error { | ||
var list []namespace | ||
if err := c.LoadTo(ctx, qs, &list); err != nil { | ||
return err | ||
} | ||
register := dest.Register | ||
if dest == nil { | ||
register = voc.Register | ||
} | ||
for _, ns := range list { | ||
register(voc.Namespace{ | ||
Prefix: string(ns.Prefix), | ||
Full: string(ns.Full), | ||
}) | ||
} | ||
return nil | ||
} |
Oops, something went wrong.