schema/edge: add annotation support for edges (#651)

This commit is contained in:
Ariel Mashraki
2020-08-01 15:38:47 +03:00
committed by GitHub
parent e9b406ca65
commit 05dfd6b78b
11 changed files with 136 additions and 71 deletions

View File

@@ -63,11 +63,11 @@ type (
func NewGraph(c *Config, schemas ...*load.Schema) (g *Graph, err error) {
defer catch(&err)
g = &Graph{c, make([]*Type, 0, len(schemas)), schemas}
for _, schema := range schemas {
g.addNode(schema)
for i := range schemas {
g.addNode(schemas[i])
}
for _, schema := range schemas {
g.addEdges(schema)
for i := range schemas {
g.addEdges(schemas[i])
}
for _, t := range g.Nodes {
check(resolve(t), "resolve %q relations", t.Name)
@@ -75,8 +75,8 @@ func NewGraph(c *Config, schemas ...*load.Schema) (g *Graph, err error) {
for _, t := range g.Nodes {
check(t.resolveFKs(), "set %q foreign-keys", t.Name)
}
for _, schema := range schemas {
g.addIndexes(schema)
for i := range schemas {
g.addIndexes(schemas[i])
}
return
}
@@ -144,26 +144,28 @@ func (g *Graph) addEdges(schema *load.Schema) {
// Assoc only.
case !e.Inverse:
t.Edges = append(t.Edges, &Edge{
def: e,
Type: typ,
Name: e.Name,
Owner: t,
Unique: e.Unique,
Optional: !e.Required,
StructTag: e.Tag,
def: e,
Type: typ,
Name: e.Name,
Owner: t,
Unique: e.Unique,
Optional: !e.Required,
StructTag: e.Tag,
Annotations: e.Annotations,
})
// Inverse only.
case e.Inverse && e.Ref == nil:
expect(e.RefName != "", "missing reference name for inverse edge: %s.%s", t.Name, e.Name)
t.Edges = append(t.Edges, &Edge{
def: e,
Type: typ,
Name: e.Name,
Owner: typ,
Inverse: e.RefName,
Unique: e.Unique,
Optional: !e.Required,
StructTag: e.Tag,
def: e,
Type: typ,
Name: e.Name,
Owner: typ,
Inverse: e.RefName,
Unique: e.Unique,
Optional: !e.Required,
StructTag: e.Tag,
Annotations: e.Annotations,
})
// Inverse and assoc.
case e.Inverse:
@@ -171,22 +173,24 @@ func (g *Graph) addEdges(schema *load.Schema) {
expect(e.RefName == "", "reference name is derived from the assoc name: %s.%s <-> %s.%s", t.Name, ref.Name, t.Name, e.Name)
expect(ref.Type == t.Name, "assoc-inverse edge allowed only as o2o relation of the same type")
t.Edges = append(t.Edges, &Edge{
def: e,
Type: typ,
Name: e.Name,
Owner: t,
Inverse: ref.Name,
Unique: e.Unique,
Optional: !e.Required,
StructTag: e.Tag,
def: e,
Type: typ,
Name: e.Name,
Owner: t,
Inverse: ref.Name,
Unique: e.Unique,
Optional: !e.Required,
StructTag: e.Tag,
Annotations: e.Annotations,
}, &Edge{
def: e,
Type: typ,
Owner: t,
Name: ref.Name,
Unique: ref.Unique,
Optional: !ref.Required,
StructTag: ref.Tag,
def: e,
Type: typ,
Owner: t,
Name: ref.Name,
Unique: ref.Unique,
Optional: !ref.Required,
StructTag: ref.Tag,
Annotations: e.Annotations,
})
default:
panic(graphError{"edge must be either an assoc or inverse edge"})

View File

@@ -77,8 +77,8 @@ type (
// UserDefined indicates that this field was defined by the loaded schema.
// Unlike default id field, which is defined by the generator.
UserDefined bool
// Annotations that were defined in the field schema.
// The mapping is from the Annotation.Name() to the decoded object.
// Annotations that were defined for the field in the schema.
// The mapping is from the Annotation.Name() to a JSON decoded object.
Annotations map[string]interface{}
}
@@ -110,6 +110,9 @@ type (
// edge.To("spouse", User.Type).Unique() // one 2 one.
//
Bidi bool
// Annotations that were defined for the edge in the schema.
// The mapping is from the Annotation.Name() to a JSON decoded object.
Annotations map[string]interface{}
}
// Relation holds the relational database information for edges.

View File

@@ -10,4 +10,5 @@ package ent
type CardExtension struct {
Number string
Name string
Spec int
}

View File

@@ -50,6 +50,9 @@ func (Card) Edges() []ent.Edge {
Ref("card").
Unique(),
edge.From("spec", Spec.Type).
Ref("card"),
Ref("card").
Annotations(&template.Extension{
Type: "int",
}),
}
}

View File

@@ -11,6 +11,7 @@ in the LICENSE file in the root directory of this source tree.
{{ range $n := $.Nodes }}
{{ $hasExt := false }}
{{ range $f := $n.Fields }}{{ if $f.Annotations.Extension }}{{ $hasExt = true }}{{ end }}{{ end }}
{{ range $e := $n.Edges }}{{ if $e.Annotations.Extension }}{{ $hasExt = true }}{{ end }}{{ end }}
{{/* If one or fields contain the "Extension" annotation */}}
{{ if $hasExt }}
// {{ $n.Name }}Extension is a type for holding the extension information defined in the schema.
@@ -20,6 +21,11 @@ in the LICENSE file in the root directory of this source tree.
{{ $f.StructField }} {{ $ant.Type }}
{{- end }}
{{- end }}
{{- range $e := $n.Edges }}
{{- with $ant := $e.Annotations.Extension }}
{{ $e.StructField }} {{ $ant.Type }}
{{- end }}
{{- end }}
}
{{ end }}
{{ end }}

View File

@@ -10,4 +10,5 @@ package ent
type CardExtension struct {
Number string
Name string
Spec int
}

File diff suppressed because one or more lines are too long

View File

@@ -57,15 +57,16 @@ type Field struct {
// Edge represents an ent.Edge that was loaded from a complied user package.
type Edge struct {
Name string `json:"name,omitempty"`
Type string `json:"type,omitempty"`
Tag string `json:"tag,omitempty"`
RefName string `json:"ref_name,omitempty"`
Ref *Edge `json:"ref,omitempty"`
Unique bool `json:"unique,omitempty"`
Inverse bool `json:"inverse,omitempty"`
Required bool `json:"required,omitempty"`
StorageKey *edge.StorageKey `json:"storage_key,omitempty"`
Name string `json:"name,omitempty"`
Type string `json:"type,omitempty"`
Tag string `json:"tag,omitempty"`
RefName string `json:"ref_name,omitempty"`
Ref *Edge `json:"ref,omitempty"`
Unique bool `json:"unique,omitempty"`
Inverse bool `json:"inverse,omitempty"`
Required bool `json:"required,omitempty"`
StorageKey *edge.StorageKey `json:"storage_key,omitempty"`
Annotations map[string]interface{} `json:"annotations,omitempty"`
}
// Index represents an ent.Index that was loaded from a complied user package.
@@ -79,14 +80,18 @@ type Index struct {
// NewEdge creates an loaded edge from edge descriptor.
func NewEdge(ed *edge.Descriptor) *Edge {
ne := &Edge{
Tag: ed.Tag,
Type: ed.Type,
Name: ed.Name,
Unique: ed.Unique,
Inverse: ed.Inverse,
Required: ed.Required,
RefName: ed.RefName,
StorageKey: ed.StorageKey,
Tag: ed.Tag,
Type: ed.Type,
Name: ed.Name,
Unique: ed.Unique,
Inverse: ed.Inverse,
Required: ed.Required,
RefName: ed.RefName,
StorageKey: ed.StorageKey,
Annotations: make(map[string]interface{}),
}
for _, at := range ed.Annotations {
ne.Annotations[at.Name()] = at
}
if ref := ed.Ref; ref != nil {
ne.Ref = NewEdge(ref)

View File

@@ -60,7 +60,8 @@ func (User) Fields() []ent.Field {
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("groups", Group.Type),
edge.To("groups", Group.Type).
Annotations(&OrderConfig{FieldName: "name"}),
edge.To("parent", User.Type).
Unique().
StorageKey(edge.Column("user_parent_id")).
@@ -139,6 +140,10 @@ func TestMarshalSchema(t *testing.T) {
require.Equal(t, "groups", schema.Edges[0].Name)
require.Equal(t, "Group", schema.Edges[0].Type)
require.False(t, schema.Edges[0].Inverse)
require.NotEmpty(t, schema.Edges[0].Annotations)
ant = schema.Edges[0].Annotations["order_config"].(map[string]interface{})
require.Equal(t, ant["FieldName"], "name")
require.Equal(t, "children", schema.Edges[1].Name)
require.Equal(t, "user_parent_id", schema.Edges[1].StorageKey.Columns[0])
require.Equal(t, "User", schema.Edges[1].Type)