snapshot of https://github.com/ent/ent.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
Atlas CI Public / lint (push) Failing after 13s
Atlas CI Public / sync (push) Has been skipped

This commit is contained in:
upstream-mirror
2026-09-15 22:12:36 +05:00
commit 4b3ad0b611
2680 changed files with 719472 additions and 0 deletions

View File

@@ -0,0 +1,67 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.Graph */}}
{{ define "dialect/sql/order/signature" -}}
// OrderFunc applies an ordering on the sql selector.
// Deprecated: Use Asc/Desc functions or the package builders instead.
type OrderFunc func(*sql.Selector)
var (
initCheck sync.Once
columnCheck sql.ColumnCheck
)
// checkColumn checks if the column exists in the given table.
func checkColumn(t, c string) error {
initCheck.Do(func() {
columnCheck = sql.NewColumnCheck(map[string]func(string) bool{
{{- range $n := $.Nodes }}
{{ $n.Package }}.Table: {{ $n.Package }}.ValidColumn,
{{- end }}
})
})
return columnCheck(t, c)
}
{{- end }}
{{ define "dialect/sql/order/func" -}}
{{- $f := $.Scope.Func -}}
func(s *sql.Selector) {
for _, f := range fields {
if err := checkColumn(s.TableName(), f); err != nil {
s.AddError(&ValidationError{Name: f, err: fmt.Errorf("{{ base $.Config.Package }}: %w", err)})
}
s.OrderBy(sql.{{ $f }}(s.C(f)))
}
}
{{- end }}
{{/* custom signature for group-by function */}}
{{ define "dialect/sql/group/signature" -}}
type AggregateFunc func(*sql.Selector) string
{{- end }}
{{ define "dialect/sql/group/as" -}}
func(s *sql.Selector) string {
return sql.As(fn(s), end)
}
{{- end }}
{{ define "dialect/sql/group/func" -}}
{{- $fn := $.Scope.Func -}}
{{- $withField := $.Scope.WithField -}}
func(s *sql.Selector) string {
{{- if $withField }}
if err := checkColumn(s.TableName(), field); err != nil {
s.AddError(&ValidationError{Name: field, err: fmt.Errorf("{{ base $.Config.Package }}: %w", err)})
return ""
}
{{- end }}
return sql.{{ if eq $fn "Mean" }}Avg{{ else }}{{ $fn }}{{ end }}({{ if $withField }}s.C(field){{ else }}"*"{{ end }})
}
{{- end }}

View File

@@ -0,0 +1,492 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.Type */}}
{{ define "dialect/sql/create" }}
{{ $builder := pascal $.Scope.Builder }}
{{ $receiver := $.Scope.Receiver }}
{{ $mutation := print $receiver ".mutation" }}
{{ $pkg := base $.Config.Package }}
func ({{ $receiver }} *{{ $builder }}) sqlSave(ctx context.Context) (*{{ $.Name }}, error) {
if err := {{ $receiver }}.check(); err != nil {
return nil, err
}
_node, _spec {{ if $.HasValueScanner }}, err {{ end }} := {{ $receiver }}.createSpec()
{{- if $.HasValueScanner }}
if err != nil {
return nil, err
}
{{- end }}
{{- if $.HasBlobFields }}
_blobs := ent.NewBlobs({{ $mutation }}.blobOpeners.{{ $.Name }})
{{- range $f := $.BlobFields }}
{{- if not $f.IsBlobLazy }}
if value, ok := {{ $mutation }}.{{ $f.MutationGet }}(); ok {
{{- if $f.HasValueScanner }}
_blobDV, err := {{ $f.ValueFunc }}(value)
if err != nil {
return nil, fmt.Errorf("{{ $pkg }}: encoding {{ $f.Name }}: %w", err)
}
var _blobData []byte
switch v := _blobDV.(type) {
case []byte:
_blobData = v
case string:
_blobData = []byte(v)
default:
return nil, fmt.Errorf("{{ $pkg }}: encoding {{ $f.Name }}: expected []byte or string, got %T", _blobDV)
}
_blobs.Set({{ $.Package }}.{{ $f.Constant }}, _blobData,
{{ if $f.HasBlobKey }}{{ $.Package }}.{{ $f.BlobKeyName }}{{ else }}defaultBlobKey{{ end }},
func(k string) {
_node.{{ $f.BlobKeyColumn }} = &k
_spec.SetField("{{ $f.BlobKeyColumn }}", field.TypeString, k)
},
)
{{- else if $f.IsBlobGoString }}
_blobs.Set({{ $.Package }}.{{ $f.Constant }}, []byte(value),
{{ if $f.HasBlobKey }}{{ $.Package }}.{{ $f.BlobKeyName }}{{ else }}defaultBlobKey{{ end }},
func(k string) {
_node.{{ $f.BlobKeyColumn }} = &k
_spec.SetField("{{ $f.BlobKeyColumn }}", field.TypeString, k)
},
)
{{- else }}
_blobs.Set({{ $.Package }}.{{ $f.Constant }}, value,
{{ if $f.HasBlobKey }}{{ $.Package }}.{{ $f.BlobKeyName }}{{ else }}defaultBlobKey{{ end }},
func(k string) {
_node.{{ $f.BlobKeyColumn }} = &k
_spec.SetField("{{ $f.BlobKeyColumn }}", field.TypeString, k)
},
)
{{- end }}
_node.{{ $f.StructField }} = value
}
{{- else }}
if r, ok := {{ $mutation }}.{{ $f.StructField }}(); ok {
_blobData, err := io.ReadAll(r)
if err != nil {
return nil, fmt.Errorf("{{ $pkg }}: reading {{ $f.Name }}: %w", err)
}
_blobs.Set({{ $.Package }}.{{ $f.Constant }}, _blobData,
{{ if $f.HasBlobKey }}{{ $.Package }}.{{ $f.BlobKeyName }}{{ else }}defaultBlobKey{{ end }},
func(k string) {
_node.{{ $f.BlobKeyColumn }} = &k
_spec.SetField("{{ $f.BlobKeyColumn }}", field.TypeString, k)
},
)
}
{{- end }}
{{- end }}
_blobCleanup, err := _blobs.Create(ctx, {{ if $.HasBlobRefCheckedFields }}&sqlgraph.BlobSpec{
Driver: {{ $receiver }}.driver,
Table: {{ $.Package }}.Table,
Columns: map[string]string{
{{- range $f := $.BlobRefCheckedFields }}
{{ $.Package }}.{{ $f.Constant }}: "{{ $f.BlobKeyColumn }}",
{{- end }}
},
CheckRefs: map[string]bool{
{{- range $f := $.BlobRefCheckedFields }}
{{ $.Package }}.{{ $f.Constant }}: true,
{{- end }}
},
}{{ else }}nil{{ end }})
if err != nil {
return nil, err
}
{{- end }}
if err := sqlgraph.CreateNode(ctx, {{ $receiver }}.driver, _spec); err != nil {
if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
{{- if $.HasBlobFields }}
return nil, errors.Join(err, _blobCleanup(ctx))
{{- else }}
return nil, err
{{- end }}
}
{{- if $.HasBlobFields }}
if txd, ok := {{ $receiver }}.driver.(*txDriver); ok {
txd.mu.Lock()
txd.onRollback = append(txd.onRollback, func(next Rollbacker) Rollbacker {
return RollbackFunc(func(ctx context.Context, tx *Tx) error {
err := next.Rollback(ctx, tx)
return errors.Join(err, _blobCleanup(ctx))
})
})
txd.mu.Unlock()
}
{{- end }}
{{- if $.HasCompositeID }}
{{- else if or $.ID.HasValueScanner $.ID.Type.ValueScanner (not $.ID.Type.Numeric) }}
if _spec.ID.Value != nil {
{{- if $.ID.HasValueScanner }}
sv, ok := _spec.ID.Value.(field.ValueScanner)
if !ok {
sv = {{ $.ID.ScanValueFunc }}()
if err := sv.Scan(_spec.ID.Value); err != nil {
return nil, err
}
}
if value, err := {{ $.ID.FromValueFunc }}(sv); err != nil {
return nil, err
} else {
_node.ID = value
}
{{- else }}
{{- /* If the ID type is not a pointer, but implements the ValueScanner interface (e.g. UUID fields). */}}
{{- if and $.ID.Type.ValueScanner (not $.ID.Type.RType.IsPtr) }}
if id, ok := _spec.ID.Value.(*{{ $.ID.Type }}); ok {
_node.ID = *id
{{- else }}
if id, ok := _spec.ID.Value.({{ $.ID.Type }}); ok {
_node.ID = id
{{- end }}
{{- if $.ID.Type.ValueScanner }}
} else if err := _node.ID.Scan(_spec.ID.Value); err != nil {
return nil, err
{{- else }}
} else {
return nil, fmt.Errorf("unexpected {{ $.Name }}.ID type: %T", _spec.ID.Value)
{{- end }}
}
{{- end }}
}
{{- else }}
{{- if $.ID.UserDefined }}
if _spec.ID.Value != _node.ID {
{{- end }}
id := _spec.ID.Value.(int64)
_node.ID = {{ $.ID.Type }}(id)
{{- if $.ID.UserDefined }}
}
{{- end }}
{{- end }}
{{- if $.HasOneFieldID }}
{{ $mutation }}.{{ $.ID.BuilderField }} = &_node.{{ $.ID.StructField }}
{{ $mutation }}.done = true
{{- end }}
return _node, nil
}
func ({{ $receiver }} *{{ $builder }}) createSpec() (*{{ $.Name }}, *sqlgraph.CreateSpec{{ if $.HasValueScanner }}, error{{ end }}) {
var (
_node = &{{ $.Name }}{config: {{ $receiver }}.config}
_spec = sqlgraph.NewCreateSpec({{ $.Package }}.Table, {{ if $.HasOneFieldID }}sqlgraph.NewFieldSpec({{ $.Package }}.{{ $.ID.Constant }}, field.{{ $.ID.Type.ConstName }}){{ else }}nil{{ end }})
)
{{- /* Allow mutating the sqlgraph.CreateSpec by ent extensions or user templates.*/}}
{{- with $tmpls := matchTemplate "dialect/sql/create/spec/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{- if and (not $.HasCompositeID) $.ID.UserDefined }}
if id, ok := {{ $mutation }}.{{ $.ID.MutationGet }}(); ok {
_node.ID = id
{{- if $.ID.HasValueScanner }}
vv, err := {{ $.ID.ValueFunc }}(id)
if err != nil {
return nil, nil, err
}
_spec.ID.Value = vv
{{- else }}
_spec.ID.Value = {{ if and $.ID.Type.ValueScanner (not $.ID.Type.RType.IsPtr) }}&{{ end }}id
{{- end }}
}
{{- end }}
{{- range $f := $.MutationFields }}
{{- if $f.IsBlobNoColumn }}{{ continue }}{{ end }}
if value, ok := {{ $mutation }}.{{ $f.MutationGet }}(); ok {
{{- if $f.HasValueScanner }}
vv, err := {{ $f.ValueFunc }}(value)
if err != nil {
return nil, nil, err
}
_spec.SetField({{ $.Package }}.{{ $f.Constant }}, field.{{ $f.Type.ConstName }}, vv)
{{- else }}
_spec.SetField({{ $.Package }}.{{ $f.Constant }}, field.{{ $f.Type.ConstName }}, value)
{{- end }}
_node.{{ $f.StructField }} = {{ if $f.NillableValue }}&{{ end }}value
}
{{- end }}
{{- range $e := $.EdgesWithID }}
if nodes := {{ $mutation }}.{{ $e.StructField }}IDs(); len(nodes) > 0 {
{{- with extend $ "Edge" $e "Nodes" true "Zero" "nil" }}
{{ template "dialect/sql/defedge" . }}{{/* defined in sql/update.tmpl */}}
{{- end }}
{{- if $e.OwnFK }}
{{- $fk := $e.ForeignKey }}
_node.{{ $fk.StructField }} = {{ if $fk.Field.NillableValue }}&{{ end }}nodes[0]
{{- end }}
_spec.Edges = append(_spec.Edges, edge)
}
{{- end }}
return _node, _spec{{ if $.HasValueScanner }}, nil{{ end }}
}
{{- /* Allow adding methods to the create-builder by ent extensions or user templates.*/}}
{{- with $tmpls := matchTemplate "dialect/sql/create/additional/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{ end }}
{{/* Additional fields for the create builder. */}}
{{ define "dialect/sql/create/fields" }}
{{- with $tmpls := matchTemplate "dialect/sql/create/fields/additional/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{- end }}
{{/* Additional fields for the create_bulk builder. */}}
{{ define "dialect/sql/create_bulk/fields" }}
{{- with $tmpls := matchTemplate "dialect/sql/create_bulk/fields/additional/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{- end }}
{{ define "dialect/sql/create_bulk" }}
{{ $builder := pascal $.Scope.Builder }}
{{ $receiver := $.Scope.Receiver }}
{{ $pkg := base $.Config.Package }}
// Save creates the {{ $.Name }} entities in the database.
func ({{ $receiver }} *{{ $builder }}) Save(ctx context.Context) ([]*{{ $.Name }}, error) {
{{- /* Initialization error was set by MapCreateBulk. */}}
if {{ $receiver }}.err != nil {
return nil, {{ $receiver }}.err
}
specs := make([]*sqlgraph.CreateSpec, len({{ $receiver }}.builders))
nodes := make([]*{{ $.Name }}, len({{ $receiver }}.builders))
mutators := make([]Mutator, len({{ $receiver }}.builders))
{{- if $.HasBlobFields }}
_blobs := ent.NewBlobs({{ $receiver }}.blobOpeners.{{ $.Name }})
{{- end }}
for i := range {{ $receiver }}.builders {
func(i int, root context.Context) {
builder := {{ $receiver }}.builders[i]
{{- if $.HasDefault }}
builder.defaults()
{{- end }}
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
mutation, ok := m.(*{{ $.MutationName }})
if !ok {
return nil, fmt.Errorf("unexpected mutation type %T", m)
}
if err := builder.check(); err != nil {
return nil, err
}
builder.mutation = mutation
var err error
nodes[i], specs[i] {{ if $.HasValueScanner }}, err {{ end }}= builder.createSpec()
{{- if $.HasValueScanner }}
if err != nil {
return nil, err
}
{{- end }}
{{- if $.HasBlobFields }}
{{- range $f := $.BlobFields }}
{{- if not $f.IsBlobLazy }}
if value, ok := mutation.{{ $f.MutationGet }}(); ok {
{{- if $f.HasValueScanner }}
_blobDV, err := {{ $f.ValueFunc }}(value)
if err != nil {
return nil, fmt.Errorf("{{ $pkg }}: encoding {{ $f.Name }}: %w", err)
}
var _blobData []byte
switch v := _blobDV.(type) {
case []byte:
_blobData = v
case string:
_blobData = []byte(v)
default:
return nil, fmt.Errorf("{{ $pkg }}: encoding {{ $f.Name }}: expected []byte or string, got %T", _blobDV)
}
_blobs.Set({{ $.Package }}.{{ $f.Constant }}, _blobData,
{{ if $f.HasBlobKey }}{{ $.Package }}.{{ $f.BlobKeyName }}{{ else }}defaultBlobKey{{ end }},
func(k string) {
nodes[i].{{ $f.BlobKeyColumn }} = &k
specs[i].SetField("{{ $f.BlobKeyColumn }}", field.TypeString, k)
},
)
{{- else if $f.IsBlobGoString }}
_blobs.Set({{ $.Package }}.{{ $f.Constant }}, []byte(value),
{{ if $f.HasBlobKey }}{{ $.Package }}.{{ $f.BlobKeyName }}{{ else }}defaultBlobKey{{ end }},
func(k string) {
nodes[i].{{ $f.BlobKeyColumn }} = &k
specs[i].SetField("{{ $f.BlobKeyColumn }}", field.TypeString, k)
},
)
{{- else }}
_blobs.Set({{ $.Package }}.{{ $f.Constant }}, value,
{{ if $f.HasBlobKey }}{{ $.Package }}.{{ $f.BlobKeyName }}{{ else }}defaultBlobKey{{ end }},
func(k string) {
nodes[i].{{ $f.BlobKeyColumn }} = &k
specs[i].SetField("{{ $f.BlobKeyColumn }}", field.TypeString, k)
},
)
{{- end }}
nodes[i].{{ $f.StructField }} = value
}
{{- else }}
if r, ok := mutation.{{ $f.StructField }}(); ok {
_blobData, err := io.ReadAll(r)
if err != nil {
return nil, fmt.Errorf("{{ $pkg }}: reading {{ $f.Name }}: %w", err)
}
_blobs.Set({{ $.Package }}.{{ $f.Constant }}, _blobData,
{{ if $f.HasBlobKey }}{{ $.Package }}.{{ $f.BlobKeyName }}{{ else }}defaultBlobKey{{ end }},
func(k string) {
nodes[i].{{ $f.BlobKeyColumn }} = &k
specs[i].SetField("{{ $f.BlobKeyColumn }}", field.TypeString, k)
},
)
}
{{- end }}
{{- end }}
{{- end }}
if i < len(mutators)-1 {
_, err = mutators[i+1].Mutate(root, {{ $receiver }}.builders[i+1].mutation)
} else {
{{- if $.HasBlobFields }}
// Write blobs before creating SQL rows so insert failures can clean up written objects.
_blobCleanup, err := _blobs.Create(ctx, {{ if $.HasBlobRefCheckedFields }}&sqlgraph.BlobSpec{
Driver: {{ $receiver }}.driver,
Table: {{ $.Package }}.Table,
Columns: map[string]string{
{{- range $f := $.BlobRefCheckedFields }}
{{ $.Package }}.{{ $f.Constant }}: "{{ $f.BlobKeyColumn }}",
{{- end }}
},
CheckRefs: map[string]bool{
{{- range $f := $.BlobRefCheckedFields }}
{{ $.Package }}.{{ $f.Constant }}: true,
{{- end }}
},
}{{ else }}nil{{ end }})
if err != nil {
return nil, err
}
{{- end }}
spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
{{- /* Allow mutating the sqlgraph.BatchCreateSpec by ent extensions or user templates.*/}}
{{- with $tmpls := matchTemplate "dialect/sql/create_bulk/spec/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
// Invoke the actual operation on the latest mutation in the chain.
if err = sqlgraph.BatchCreate(ctx, {{ $receiver }}.driver, spec); err != nil {
if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
{{- if $.HasBlobFields }}
return nil, errors.Join(err, _blobCleanup(ctx))
{{- end }}
}
{{- if $.HasBlobFields }}
if txd, ok := {{ $receiver }}.driver.(*txDriver); ok {
txd.mu.Lock()
txd.onRollback = append(txd.onRollback, func(next Rollbacker) Rollbacker {
return RollbackFunc(func(ctx context.Context, tx *Tx) error {
err := next.Rollback(ctx, tx)
return errors.Join(err, _blobCleanup(ctx))
})
})
txd.mu.Unlock()
}
{{- end }}
}
if err != nil {
return nil, err
}
{{- if $.HasOneFieldID }}
mutation.{{ $.ID.BuilderField }} = &nodes[i].{{ $.ID.StructField }}
{{- if and (or $.ID.IsString $.ID.IsUUID $.ID.IsBytes $.ID.IsOther) (not $.ID.HasValueScanner) }}
{{- /* Do nothing, because these 4 types must be supplied by the user. */ -}}
{{- else if $.ID.HasValueScanner }}
if specs[i].ID.Value != nil {
sv, ok := specs[i].ID.Value.(field.ValueScanner)
if !ok {
sv = {{ $.ID.ScanValueFunc }}()
if err := sv.Scan(specs[i].ID.Value); err != nil {
return nil, err
}
}
if id, err := {{ $.ID.FromValueFunc }}(sv); err != nil {
return nil, err
} else {
nodes[i].ID = id
}
}
{{- else if or $.ID.Type.ValueScanner }}
if specs[i].ID.Value != nil {
if err := nodes[i].ID.Scan(specs[i].ID.Value); err != nil {
return nil, err
}
}
{{- else }}
if specs[i].ID.Value != nil {{ if $.ID.UserDefined }}&& nodes[i].ID == 0{{ end }} {
id := specs[i].ID.Value.(int64)
nodes[i].ID = {{ $.ID.Type }}(id)
}
{{- end }}
{{- end }}
mutation.done = true
return nodes[i], nil
})
for i := len(builder.hooks) - 1; i >= 0; i-- {
mut = builder.hooks[i](mut)
}
mutators[i] = mut
}(i, ctx)
}
if len(mutators) > 0 {
if _, err := mutators[0].Mutate(ctx, {{ $receiver }}.builders[0].mutation); err != nil {
return nil, err
}
}
return nodes, nil
}
// SaveX is like Save, but panics if an error occurs.
func ({{ $receiver }} *{{ $builder }}) SaveX(ctx context.Context) []*{{ $.Name }} {
v, err := {{ $receiver }}.Save(ctx)
if err != nil {
panic(err)
}
return v
}
// Exec executes the query.
func ({{ $receiver }} *{{ $builder }}) Exec(ctx context.Context) error {
_, err := {{ $receiver }}.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func ({{ $receiver }} *{{ $builder }}) ExecX(ctx context.Context) {
if err := {{ $receiver }}.Exec(ctx); err != nil {
panic(err)
}
}
{{- /* Allow adding methods to the create_bulk builder by ent extensions or user templates.*/}}
{{- with $tmpls := matchTemplate "dialect/sql/create_bulk/additional/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{ end }}

View File

@@ -0,0 +1,181 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.typeScope */}}
{{ define "dialect/sql/decode/one" }}
{{ $receiver := $.Receiver }}
{{ $ctypes := dict }}
{{ if $.HasOneFieldID }}
{{- if not $.ID.HasValueScanner }}
{{ $idscantype := $.ID.NewScanType }}
{{ $ctypes = set $ctypes $idscantype (list $.ID.Constant) }}
{{- end }}
{{ end }}
{{ range $f := $.Fields }}
{{- if $f.HasValueScanner }}
{{- continue }}
{{- end }}
{{- if or $f.IsBlobNoColumn $f.IsBlobLazy }}
{{- continue }}
{{- end }}
{{ $names := list }}
{{ if hasKey $ctypes $f.NewScanType }}
{{ $names = get $ctypes $f.NewScanType }}
{{ end }}
{{ $names = append $names $f.Constant }}
{{ $ctypes = set $ctypes $f.NewScanType $names }}
{{ end }}
// scanValues returns the types for scanning values from sql.Rows.
func (*{{ $.Name }}) scanValues(columns []string) ([]any, error) {
values := make([]any, len(columns))
for i := range columns {
switch columns[i] {
{{- if and $.HasOneFieldID $.ID.HasValueScanner }}
case {{ $.Package }}.{{ $.ID.Constant }}:
values[i] = {{ $.ID.ScanValueFunc }}()
{{- end }}
{{- range $type, $columns := $ctypes }}
case {{ range $i, $c := $columns }}{{ if ne $i 0 }},{{ end }}{{ $.Package }}.{{ $c }}{{ end }}:
values[i] = {{ $type }}
{{- end }}
{{- range $f := $.Fields }}
{{- if $f.IsBlobNoColumn }}{{ continue }}{{ end }}
{{- if $f.HasValueScanner }}
case {{ $.Package }}.{{ $f.Constant }}:
values[i] = {{ $f.ScanValueFunc }}()
{{- end }}
{{- end }}
{{- range $i, $fk := $.UnexportedForeignKeys }}
{{- $f := $fk.Field }}
case {{ $.Package }}.ForeignKeys[{{ $i }}]: // {{ $f.Name }}
values[i] = {{ if not $f.UserDefined }}new(sql.NullInt64){{ else }}{{ $f.NewScanType }}{{ end }}
{{- end }}
{{- range $i, $bk := $.BlobKeys }}
case {{ $.Package }}.BlobKeys[{{ $i }}]: // {{ $bk.Field.Name }}
values[i] = new(sql.NullString)
{{- end }}
default:
{{- /* In case of unknown column that was added by a modifier, predicate, etc., fallback to any. */}}
values[i] = new(sql.UnknownType)
}
}
return values, nil
}
// assignValues assigns the values that were returned from sql.Rows (after scanning)
// to the {{ $.Name }} fields.
func ({{ $receiver }} *{{ $.Name }}) assignValues(columns []string, values []any) error {
if m, n := len(values), len(columns); m < n {
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
}
for i := range columns {
switch columns[i] {
{{- if $.HasOneFieldID }}
case {{ $.Package }}.{{ $.ID.Constant }}:
{{- if or $.ID.IsString $.ID.IsBytes $.ID.HasGoType $.ID.HasValueScanner }}
{{- with extend $ "Idx" "i" "Field" $.ID "Rec" $receiver }}
{{ template "dialect/sql/decode/field" . }}
{{- end }}
{{- else }}
value, ok := values[i].(*sql.NullInt64)
if !ok {
return fmt.Errorf("unexpected type %T for field id", value)
}
{{ $receiver }}.ID = {{ $.ID.Type }}(value.Int64)
{{- end }}
{{- end }}
{{- range $f := $.Fields }}
{{- if or $f.IsBlobNoColumn $f.IsBlobLazy }}
{{- continue }}
{{- end }}
case {{ $.Package }}.{{ $f.Constant }}:
{{- with extend $ "Idx" "i" "Field" $f "Rec" $receiver }}
{{ template "dialect/sql/decode/field" . }}
{{- end }}
{{- end }}
{{- range $i, $fk := $.UnexportedForeignKeys }}
{{- $f := $fk.Field }}
case {{ if $fk.UserDefined }}{{ $.Package }}.{{ $.ID.Constant }}{{ else }}{{ $.Package }}.ForeignKeys[{{ $i }}]{{ end }}:
{{- if or $fk.UserDefined (and $f.UserDefined (or $f.IsString $f.IsBytes $f.HasGoType)) }}
{{- with extend $ "Idx" "i" "Field" $f "Rec" $receiver "StructField" $fk.StructField }}
{{ template "dialect/sql/decode/field" . }}
{{- end }}
{{- else }}
if value, ok := values[i].(*sql.NullInt64); !ok {
return fmt.Errorf("unexpected type %T for edge-field {{ $f.Name}}", value)
} else if value.Valid {
{{ $receiver }}.{{ $fk.StructField }} = new({{ $f.Type }})
{{ if and $f.Nillable (not $f.Type.Nillable) }}*{{ end }}{{ $receiver }}.{{ $fk.StructField }} = {{ $f.Type }}(value.Int64)
}
{{- end }}
{{- end }}
{{- range $i, $bk := $.BlobKeys }}
case {{ $.Package }}.BlobKeys[{{ $i }}]:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field {{ $bk.Field.Name }}", values[i])
} else if value.Valid {
{{ $receiver }}.{{ $bk.StructField }} = &value.String
}
{{- end }}
default:
{{- /* In case of no match, allow getting this value by its name. */}}
{{ $receiver }}.selectValues.Set(columns[i], values[i])
}
}
return nil
}
// {{ $.ValueName }} returns the ent.Value that was dynamically selected and assigned to the {{ $.Name }}.
// This includes values selected through modifiers, order, etc.
func ({{ $receiver }} *{{ $.Name }}) {{ $.ValueName }}(name string) (ent.Value, error) {
return {{ $receiver }}.selectValues.Get(name)
}
{{ end }}
{{ define "dialect/sql/decode/field" }}
{{- $i := $.Scope.Idx -}}
{{- $f := $.Scope.Field -}}
{{- $ret := $.Scope.Rec -}}
{{- $field := $f.StructField }}{{ with $.Scope.StructField }}{{ $field = . }}{{ end -}}
{{- if $f.HasValueScanner -}}
if value, err := {{ $f.FromValueFunc }}(values[{{ $i }}]); err != nil {
return err
} else {
{{ $ret }}.{{ $field }} = value
}
{{- else if $f.IsJSON -}}
if value, ok := values[{{ $i }}].(*{{ $f.ScanType }}); !ok {
return fmt.Errorf("unexpected type %T for field {{ $f.Name }}", values[{{ $i }}])
} else if value != nil && len(*value) > 0 {
if err := json.Unmarshal(*value, &{{ $ret }}.{{ $field }}); err != nil {
return fmt.Errorf("unmarshal field {{ $f.Name }}: %w", err)
}
}
{{- else }}
{{- $scantype := $f.ScanType -}}
if value, ok := values[{{ $i }}].(*{{ $scantype }}); !ok {
return fmt.Errorf("unexpected type %T for field {{ $f.Name }}", values[{{ $i }}])
{{- if hasPrefix $scantype "sql.Null" }}
} else if value.Valid {
{{- if $f.NillableValue }}
{{ $ret }}.{{ $field }} = new({{ $f.Type }})
*{{ $ret }}.{{ $field }} = {{ $f.ScanTypeField "value" }}
{{- else }}
{{ $ret }}.{{ $field }} = {{ $f.ScanTypeField "value" }}
{{- end }}
{{- else }}
} else if value != nil {
{{ $ret }}.{{ $field }} = {{ if and (not $f.Nillable) (not $f.Type.RType.IsPtr) }}*{{ end }}value
{{- end }}
}
{{- end }}
{{- end }}
{{ define "dialect/sql/decode/many" }}
{{ end }}

View File

@@ -0,0 +1,84 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.typeScope */}}
{{ define "dialect/sql/delete" }}
{{ $builder := pascal $.Scope.Builder }}
{{ $receiver := $.Scope.Receiver }}
{{ $mutation := print $receiver ".mutation" }}
func ({{ $receiver}} *{{ $builder }}) sqlExec(ctx context.Context) (int, error) {
_spec := sqlgraph.NewDeleteSpec({{ $.Package }}.Table, {{ if $.HasOneFieldID }}sqlgraph.NewFieldSpec({{ $.Package }}.{{ $.ID.Constant }}, field.{{ $.ID.Type.ConstName }}){{ else }}nil{{ end }})
{{- /* Allow mutating the sqlgraph.DeleteSpec by ent extensions or user templates.*/}}
{{- with $tmpls := matchTemplate "dialect/sql/delete/spec/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
if ps := {{ $mutation }}.Predicates(); len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
{{- if $.HasBlobFields }}
// Collect blob keys before deleting rows so we can remove blobs from storage afterward.
_blobKeys, _blobErr := ent.NewBlobs({{ $mutation }}.blobOpeners.{{ $.Name }}).Delete(ctx, &sqlgraph.BlobSpec{
Driver: {{ $receiver }}.driver,
Predicate: _spec.Predicate,
Table: {{ $.Package }}.Table,
Columns: map[string]string{
{{- range $f := $.BlobFields }}
{{ $.Package }}.{{ $f.Constant }}: "{{ $f.BlobKeyColumn }}",
{{- end }}
},
{{- if $.HasBlobRefCheckedFields }}
CheckRefs: map[string]bool{
{{- range $f := $.BlobRefCheckedFields }}
{{ $.Package }}.{{ $f.Constant }}: true,
{{- end }}
},
{{- end }}
})
if _blobErr != nil {
return 0, _blobErr
}
{{- end }}
affected, err := sqlgraph.DeleteNodes(ctx, {{ $receiver}}.driver, _spec)
if err != nil && sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
{{- if $.HasBlobFields }}
if err == nil {
// Resolve which blobs are unreferenced now that the rows are gone, while the
// transaction is still open, and remove them from storage once it commits.
_blobCleanup, _blobErr := _blobKeys.Cleanup(ctx)
if _blobErr != nil {
return 0, _blobErr
}
if txd, ok := {{ $receiver }}.driver.(*txDriver); ok {
txd.mu.Lock()
txd.onCommit = append(txd.onCommit, func(next Committer) Committer {
return CommitFunc(func(ctx context.Context, tx *Tx) error {
if err := next.Commit(ctx, tx); err != nil {
return err
}
return _blobCleanup(ctx)
})
})
txd.mu.Unlock()
} else {
err = _blobCleanup(ctx)
}
}
{{- end }}
{{ $mutation }}.done = true
return affected, err
}
{{ end }}

View File

@@ -0,0 +1,25 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.typeScope */}}
{{/* Additional fields for the generated model for holding the foreign-keys */}}
{{ define "dialect/sql/model/fields" }}
{{- range $fk := $.UnexportedForeignKeys }}
{{- $f := $fk.Field }}
{{ $fk.StructField }} {{ if $f.Nillable }}*{{ end }}{{ $f.Type }}
{{- end }}
{{- range $bk := $.BlobKeys }}
{{ $bk.StructField }} *string
{{- end }}
selectValues sql.SelectValues
{{- /* Allow adding struct fields by ent extensions or user templates.*/}}
{{- with $tmpls := matchTemplate "dialect/sql/model/fields/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{ end }}

View File

@@ -0,0 +1,177 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.Graph */}}
{{ define "dialect/sql/entql" }}
{{ $pkg := base $.Config.Package }}
{{ template "header" $ }}
import (
"context"
"time"
"{{ $.Config.Package }}/predicate"
{{- range $n := $.Nodes }}
{{ $n.PackageAlias }} "{{ $.Config.Package }}/{{ $n.PackageDir }}"
{{- end }}
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/entql"
"entgo.io/ent/schema/field"
)
// schemaGraph holds a representation of ent/schema at runtime.
var schemaGraph = func() *sqlgraph.Schema {
graph := &sqlgraph.Schema{Nodes: make([]*sqlgraph.Node, {{ len $.Nodes }})}
{{- range $i, $n := $.Nodes }}
graph.Nodes[{{ $i }}] = &sqlgraph.Node{
NodeSpec: sqlgraph.NodeSpec{
Table: {{ $n.Package }}.Table,
Columns: {{ $n.Package }}.Columns,
{{- if $n.HasOneFieldID }}
ID: &sqlgraph.FieldSpec{
Type: field.{{ $n.ID.Type.ConstName }},
Column: {{ $n.Package }}.{{ $n.ID.Constant }},
},
{{- else }}
CompositeID: []*sqlgraph.FieldSpec{
{{- range $id := $n.EdgeSchema.ID }}
{
Type: field.{{ $id.Type.ConstName }},
Column: {{ $n.Package }}.{{ $id.Constant }},
},
{{- end }}
},
{{- end }}
},
Type: "{{ $n.Name }}",
Fields: map[string]*sqlgraph.FieldSpec{
{{- range $f := $n.Fields }}
{{- if not (or $f.IsBlobNoColumn $f.IsBlobLazy) }}
{{ $n.Package }}.{{ $f.Constant }}: {Type: field.{{ $f.Type.ConstName }}, Column: {{ $n.Package }}.{{ $f.Constant }}},
{{- end }}
{{- end }}
},
}
{{- end }}
{{- range $n := $.Nodes }}
{{- range $e := $n.Edges }}
graph.MustAddE(
"{{ $e.Name }}",
&sqlgraph.EdgeSpec{
Rel: sqlgraph.{{ $e.Rel.Type }},
Inverse: {{ $e.IsInverse }},
Table: {{ $n.Package }}.{{ $e.TableConstant }},
Columns: {{ if $e.M2M }}{{ $n.Package }}.{{ $e.PKConstant }}{{ else }}[]string{ {{ $n.Package }}.{{ $e.ColumnConstant }} }{{ end }},
Bidi: {{ $e.Bidi }},
},
"{{ $n.Name }}",
"{{ $e.Type.Name }}",
)
{{- end }}
{{- end }}
return graph
}()
// predicateAdder wraps the addPredicate method.
// All update, update-one and query builders implement this interface.
type predicateAdder interface {
addPredicate(func(s *sql.Selector))
}
{{ range $i, $n := $.Nodes }}
{{ $builder := $n.QueryName }}
{{ $receiver := $n.QueryReceiver }}
{{ $mutation := $n.MutationName }}
{{ $filter := print $n.FilterName }}
// addPredicate implements the predicateAdder interface.
func ({{ $receiver }} *{{ $builder }}) addPredicate(pred func(s *sql.Selector)) {
{{ $receiver }}.predicates = append({{ $receiver }}.predicates, pred)
}
// Filter returns a Filter implementation to apply filters on the {{ $builder }} builder.
func ({{ $receiver }} *{{ $builder }}) Filter() *{{ $filter }} {
return &{{ $filter }}{config: {{ $receiver }}.config, predicateAdder: {{ $receiver}} }
}
{{- if not $n.IsView }}
// addPredicate implements the predicateAdder interface.
func (m *{{ $mutation }}) addPredicate(pred func(s *sql.Selector)) {
m.Where(pred)
}
// Filter returns an entql.Where implementation to apply filters on the {{ $mutation }} builder.
func (m *{{ $mutation }}) Filter() *{{ $filter }} {
return &{{ $filter }}{config: m.config, predicateAdder: m}
}
{{- end }}
// {{ $filter }} provides a generic filtering capability at runtime for {{ $builder }}.
type {{ $filter }} struct {
predicateAdder
config
}
// Where applies the entql predicate on the query filter.
func (f *{{ $filter }}) Where(p entql.P) {
f.addPredicate(func(s *sql.Selector) {
if err := schemaGraph.EvalP(schemaGraph.Nodes[{{ $i }}].Type, p, s); err != nil {
s.AddError(err)
}
})
}
{{- if $n.HasOneFieldID }}
{{ $type := $n.ID.Type.Type.String }}
{{ $iface := print (pascal $type) "P" }}
{{- if $n.ID.IsTime }}{{ $iface = "TimeP" }}
{{- else if or $n.ID.IsBytes $n.ID.IsJSON }}{{ $iface = "BytesP" }}
{{- else if $n.ID.IsUUID }}{{ $iface = "ValueP" }}
{{- end }}
// WhereID applies the entql {{ $type }} predicate on the id field.
func (f *{{ $filter }}) WhereID(p entql.{{ $iface }}) {
f.Where(p.Field({{ $n.Package }}.{{ $n.ID.Constant }}))
}
{{- end }}
{{ range $f := $n.Fields }}
{{- if or $f.IsBlobNoColumn $f.IsBlobLazy }}{{ continue }}{{ end }}
{{ $type := $f.Type.Type.String }}
{{ $iface := print (pascal $type) "P" }}
{{- if $f.IsTime }}{{ $iface = "TimeP" }}
{{- else if or $f.IsBytes $f.IsJSON }}{{ $iface = "BytesP" }}
{{- else if $f.IsUUID }}{{ $iface = "ValueP" }}
{{- end }}
// Where{{ $f.StructField }} applies the entql {{ $type }} predicate on the {{ $f.Name }} field.
func (f *{{ $filter }}) Where{{ $f.StructField }}(p entql.{{ $iface }}) {
f.Where(p.Field({{ $n.Package }}.{{ $f.Constant }}))
}
{{ end }}
{{ range $e := $n.Edges }}
{{ $func := print "WhereHas" $e.StructField }}
// {{ $func }} applies a predicate to check if query has an edge {{ $e.Name }}.
func (f *{{ $filter }}) {{ $func }}() {
f.Where(entql.HasEdge("{{ $e.Name }}"))
}
{{ $func = print "WhereHas" $e.StructField "With" }}
// {{ $func }} applies a predicate to check if query has an edge {{ $e.Name }} with a given conditions (other predicates).
func (f *{{ $filter }}) {{ $func }}(preds ...predicate.{{ $e.Type.Name }}) {
f.Where(entql.HasEdgeWith("{{ $e.Name }}", sqlgraph.WrapFunc(func(s *sql.Selector) {
for _, p := range preds {
p(s)
}
})))
}
{{ end }}
{{ end }}
{{ end }}

View File

@@ -0,0 +1,11 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.Graph */}}
{{/* custom errors and errors handlers for sql dialects */}}
{{ define "dialect/sql/errors" }}
{{ end }}

View File

@@ -0,0 +1,71 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.Graph*/}}
{{- define "import/additional/stdsql" -}}
{{- if $.FeatureEnabled "sql/execquery" }}
stdsql "database/sql"
{{- end }}
{{- end -}}
{{/* Template for adding "ExecContext"/"QueryContext" methods to the config. */}}
{{ define "config/additional/sql/execquery" }}
{{- if $.FeatureEnabled "sql/execquery" }}
// ExecContext allows calling the underlying ExecContext method of the driver if it is supported by it.
// See, database/sql#DB.ExecContext for more information.
func (c *config) ExecContext(ctx context.Context, query string, args ...any) (stdsql.Result, error) {
ex, ok := c.driver.(interface {
ExecContext(context.Context, string, ...any) (stdsql.Result, error)
})
if !ok {
return nil, fmt.Errorf("Driver.ExecContext is not supported")
}
return ex.ExecContext(ctx, query, args...)
}
// QueryContext allows calling the underlying QueryContext method of the driver if it is supported by it.
// See, database/sql#DB.QueryContext for more information.
func (c *config) QueryContext(ctx context.Context, query string, args ...any) (*stdsql.Rows, error) {
q, ok := c.driver.(interface {
QueryContext(context.Context, string, ...any) (*stdsql.Rows, error)
})
if !ok {
return nil, fmt.Errorf("Driver.QueryContext is not supported")
}
return q.QueryContext(ctx, query, args...)
}
{{- end }}
{{ end }}
{{/* Template for adding "ExecContext"/"QueryContext" methods to the client. */}}
{{ define "tx/additional/sql/execquery" }}
{{- if $.FeatureEnabled "sql/execquery" }}
// ExecContext allows calling the underlying ExecContext method of the transaction if it is supported by it.
// See, database/sql#Tx.ExecContext for more information.
func (tx *txDriver) ExecContext(ctx context.Context, query string, args ...any) (stdsql.Result, error) {
ex, ok := tx.tx.(interface {
ExecContext(context.Context, string, ...any) (stdsql.Result, error)
})
if !ok {
return nil, fmt.Errorf("Tx.ExecContext is not supported")
}
return ex.ExecContext(ctx, query, args...)
}
// QueryContext allows calling the underlying QueryContext method of the transaction if it is supported by it.
// See, database/sql#Tx.QueryContext for more information.
func (tx *txDriver) QueryContext(ctx context.Context, query string, args ...any) (*stdsql.Rows, error) {
q, ok := tx.tx.(interface {
QueryContext(context.Context, string, ...any) (*stdsql.Rows, error)
})
if !ok {
return nil, fmt.Errorf("Tx.QueryContext is not supported")
}
return q.QueryContext(ctx, query, args...)
}
{{- end }}
{{ end }}

View File

@@ -0,0 +1,46 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.Type */}}
{{/* Templates used by the "sql/lock" feature-flag to add "SELECT ... FOR UPDATE/SHARE" capabilities. */}}
{{ define "dialect/sql/query/additional/locking" }}
{{ if $.FeatureEnabled "sql/lock" }}
{{ template "helper/sqlock" $ }}
{{ end }}
{{ end }}
{{ define "helper/sqlock" }}
{{ $builder := pascal $.Scope.Builder }}
{{ $receiver := $.Scope.Receiver }}
// ForUpdate locks the selected rows against concurrent updates, and prevent them from being
// updated, deleted or "selected ... for update" by other sessions, until the transaction is
// either committed or rolled-back.
func ({{ $receiver }} *{{ $builder }}) ForUpdate(opts ...sql.LockOption) *{{ $builder }} {
if {{ $receiver }}.driver.Dialect() == dialect.Postgres {
{{ $receiver }}.Unique(false)
}
{{ $receiver }}.modifiers = append({{ $receiver }}.modifiers, func(s *sql.Selector) {
s.ForUpdate(opts...)
})
return {{ $receiver }}
}
// ForShare behaves similarly to ForUpdate, except that it acquires a shared mode lock
// on any rows that are read. Other sessions can read the rows, but cannot modify them
// until your transaction commits.
func ({{ $receiver }} *{{ $builder }}) ForShare(opts ...sql.LockOption) *{{ $builder }} {
if {{ $receiver }}.driver.Dialect() == dialect.Postgres {
{{ $receiver }}.Unique(false)
}
{{ $receiver }}.modifiers = append({{ $receiver }}.modifiers, func(s *sql.Selector) {
s.ForShare(opts...)
})
return {{ $receiver }}
}
{{ end }}

View File

@@ -0,0 +1,40 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.Graph */}}
{{ define "migrate/diff" }}
// Diff compares the state read from a database connection or migration directory with
// the state defined by the Ent schema. Changes will be written to new migration files.
func Diff(ctx context.Context, url string, opts ...schema.MigrateOption) error {
return NamedDiff(ctx, url, "changes", opts...)
}
// NamedDiff compares the state read from a database connection or migration directory with
// the state defined by the Ent schema. Changes will be written to new named migration files.
func NamedDiff(ctx context.Context, url, name string, opts ...schema.MigrateOption) error {
return schema.Diff(ctx, url, name, Tables, opts...)
}
// Diff creates a migration file containing the statements to resolve the diff
// between the Ent schema and the connected database.
func (s *Schema) Diff(ctx context.Context, opts ...schema.MigrateOption) error {
migrate, err := schema.NewMigrate(s.drv, opts...)
if err != nil {
return fmt.Errorf("ent/migrate: %w", err)
}
return migrate.Diff(ctx, Tables...)
}
// NamedDiff creates a named migration file containing the statements to resolve the diff
// between the Ent schema and the connected database.
func (s *Schema) NamedDiff(ctx context.Context, name string, opts ...schema.MigrateOption) error {
migrate, err := schema.NewMigrate(s.drv, opts...)
if err != nil {
return fmt.Errorf("ent/migrate: %w", err)
}
return migrate.NamedDiff(ctx, name, Tables...)
}
{{ end }}

View File

@@ -0,0 +1,92 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.Type */}}
{{/* Templates used by the "sql/modifier" feature-flag to add custom modifiers to the builders. */}}
{{/* Template for adding the "modifiers" field to the query builder. */}}
{{ define "dialect/sql/query/fields/additional/modify" -}}
{{- if or ($.FeatureEnabled "sql/lock") ($.FeatureEnabled "sql/modifier") }}
modifiers []func(*sql.Selector)
{{- end }}
{{- end -}}
{{/* Template for adding the "executing" the list of modifiers on the sql.Selector. */}}
{{ define "dialect/sql/query/selector/modify" }}
{{- if or ($.FeatureEnabled "sql/lock") ($.FeatureEnabled "sql/modifier") }}
{{- $receiver := $.Scope.Receiver }}
for _, m := range {{ $receiver }}.modifiers {
m(selector)
}
{{- end }}
{{- end -}}
{{/* Template for passing the modifiers to the sqlgraph.QuerySpec. */}}
{{ define "dialect/sql/query/spec/modify" }}
{{- if or ($.FeatureEnabled "sql/lock") ($.FeatureEnabled "sql/modifier") }}
{{- $receiver := $.Scope.Receiver }}
if len({{ $receiver }}.modifiers) > 0 {
_spec.Modifiers = {{ $receiver }}.modifiers
}
{{- end }}
{{- end -}}
{{/* A template for adding the Modify method to the query-builder. */}}
{{ define "dialect/sql/query/additional/modify" }}
{{ if $.FeatureEnabled "sql/modifier" }}
{{ $builder := pascal $.Scope.Builder }}
{{ $receiver := $.Scope.Receiver }}
{{ $selectBuilder := pascal $.Name | printf "%sSelect" }}
// Modify adds a query modifier for attaching custom logic to queries.
func ({{ $receiver }} *{{ $builder }}) Modify(modifiers ...func(s *sql.Selector)) *{{ $selectBuilder }} {
{{ $receiver }}.modifiers = append({{ $receiver }}.modifiers, modifiers...)
return {{ $receiver }}.Select()
}
{{ end }}
{{ end }}
{{/* A template for adding the Modify method to the select-builder. */}}
{{ define "dialect/sql/select/additional/modify" }}
{{ if $.FeatureEnabled "sql/modifier" }}
{{ $builder := pascal $.Scope.Builder }}
{{ $receiver := $.Scope.Receiver }}
// Modify adds a query modifier for attaching custom logic to queries.
func ({{ $receiver }} *{{ $builder }}) Modify(modifiers ...func(s *sql.Selector)) *{{ $builder }} {
{{ $receiver }}.modifiers = append({{ $receiver }}.modifiers, modifiers...)
return {{ $receiver }}
}
{{ end }}
{{ end }}
{{/* Template for adding the "modifiers" field to the update builder. */}}
{{ define "dialect/sql/update/fields/additional/modify" -}}
{{- if $.FeatureEnabled "sql/modifier" }}
modifiers []func(*sql.UpdateBuilder)
{{- end }}
{{- end -}}
{{/* A template for adding the Modify method to the update and updateone builders. */}}
{{ define "dialect/sql/update/additional/modify" }}
{{ if $.FeatureEnabled "sql/modifier" }}
{{ $pkg := $.Scope.Package }}
{{ $builder := pascal $.Scope.Builder }}
{{ $receiver := $.Scope.Receiver }}
// Modify adds a statement modifier for attaching custom logic to the UPDATE statement.
func ({{ $receiver }} *{{ $builder }}) Modify(modifiers ...func(u *sql.UpdateBuilder)) *{{ $builder }} {
{{ $receiver }}.modifiers = append({{ $receiver }}.modifiers, modifiers...)
return {{ $receiver }}
}
{{ end }}
{{ end }}
{{/* Template for passing the modifiers to the sqlgraph.UpdateSpec. */}}
{{ define "dialect/sql/update/spec/modify" }}
{{- if $.FeatureEnabled "sql/modifier" }}
{{- $receiver := $.Scope.Receiver }}
_spec.AddModifiers({{ $receiver }}.modifiers...)
{{- end }}
{{- end -}}

View File

@@ -0,0 +1,121 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.Type */}}
{{/* Templates used by the "namedges" feature-flag to allow eager-loading edges with dynamic names. */}}
{{ define "dialect/sql/model/edges/fields/additional/namedges" }}
{{- if $.FeatureEnabled "namedges" }}
{{- range $e := $.Edges }}
{{- if not $e.Unique }}
named{{ $e.StructField }} map[string][]*{{ $e.Type.Name }}
{{- end }}
{{- end }}
{{- end }}
{{ end }}
{{ define "dialect/sql/model/additional/namedges" }}
{{- if $.FeatureEnabled "namedges" }}
{{ $receiver := $.Receiver }}
{{- range $e := $.Edges }}
{{- if not $e.Unique }}
{{ $func := print "Named" $e.StructField }}
// {{ $func }} returns the {{ $e.StructField }} named value or an error if the edge was not
// loaded in eager-loading with this name.
func ({{ $receiver }} *{{ $.Name }}) Named{{ $e.StructField }}(name string) ([]*{{ $e.Type.Name }}, error) {
if {{ $receiver }}.Edges.named{{ $e.StructField }} == nil {
return nil, &NotLoadedError{edge: name}
}
nodes, ok := {{ $receiver }}.Edges.named{{ $e.StructField }}[name]
if !ok {
return nil, &NotLoadedError{edge: name}
}
return nodes, nil
}
func ({{ $receiver }} *{{ $.Name }}) appendNamed{{ $e.StructField }}(name string, edges ...*{{ $e.Type.Name }}) {
if {{ $receiver }}.Edges.named{{ $e.StructField }} == nil {
{{ $receiver }}.Edges.named{{ $e.StructField }} = make(map[string][]*{{ $e.Type.Name }})
}
if len(edges) == 0 {
{{- /* Prefer empty array over nil to stay consistent with the standard eager-loading API. */}}
{{ $receiver }}.Edges.named{{ $e.StructField }}[name] = []*{{ $e.Type.Name }}{}
} else {
{{ $receiver }}.Edges.named{{ $e.StructField }}[name] = append({{ $receiver }}.Edges.named{{ $e.StructField }}[name], edges...)
}
}
{{- end }}
{{- end }}
{{- end }}
{{ end }}
{{- define "dialect/sql/query/fields/additional/namedges" }}
{{- if $.FeatureEnabled "namedges" }}
{{- range $e := $.Edges }}
{{- if not $e.Unique }}
{{ $e.EagerLoadNamedField }} map[string]*{{ $e.Type.QueryName }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{ define "dialect/sql/query/additional/namedges" }}
{{- if $.FeatureEnabled "namedges" }}
{{ $builder := $.QueryName }}
{{ $receiver := $.QueryReceiver }}
{{- range $e := $.Edges }}
{{- if not $e.Unique }}
{{ $ebuilder := $e.Type.QueryName }}
{{ $func := print "WithNamed" $e.StructField }}
// {{ $func }} tells the query-builder to eager-load the nodes that are connected to the "{{ $e.Name }}"
// edge with the given name. The optional arguments are used to configure the query builder of the edge.
func ({{ $receiver }} *{{ $builder }}) {{ $func }}(name string, opts ...func(*{{ $ebuilder }})) *{{ $builder }} {
query := (&{{ $e.Type.ClientName }}{config: {{ $receiver }}.config}).Query()
for _, opt := range opts {
opt(query)
}
if {{ $receiver }}.{{ $e.EagerLoadNamedField }} == nil {
{{ $receiver }}.{{ $e.EagerLoadNamedField }} = make(map[string]*{{ $e.Type.QueryName }})
}
{{ $receiver }}.{{ $e.EagerLoadNamedField }}[name] = query
return {{ $receiver }}
}
{{- end }}
{{- end }}
{{- end }}
{{ end }}
{{/* Process nodes before they are returned and resolve named-edges. */}}
{{- define "dialect/sql/query/all/nodes/namedges" }}
{{- if $.FeatureEnabled "namedges" }}
{{- $builder := pascal $.Scope.Builder }}
{{- $receiver := $.Scope.Receiver }}
{{- range $e := $.Edges }}
{{- if not $e.Unique }}
for name, query := range {{ $receiver }}.{{ $e.EagerLoadNamedField }} {
if err := {{ $receiver }}.load{{ $e.StructField }}(ctx, query, nodes,
func(n *{{ $.Name }}) { n.appendNamed{{ $e.StructField }}(name) },
{{- if and ($.FeatureEnabled "bidiedges") $e.Ref $e.Ref.Unique }}
func(n *{{ $.Name }}, e *{{ $e.Type.Name }}){
n.appendNamed{{ $e.StructField }}(name, e)
{{- $idx := $e.Ref.Index }}
{{- /* Set only in case this type was not loaded explicitly (without custom options). */}}
if !e.Edges.loadedTypes[{{ $idx }}] {
e.Edges.{{ $e.Ref.StructField }} = n
}
}); err != nil {
{{- else }}
{{- /* Keep it one-liner if there is not inverse-condition. */}}
func(n *{{ $.Name }}, e *{{ $e.Type.Name }}){ n.appendNamed{{ $e.StructField }}(name, e) }); err != nil {
{{- end }}
return nil, err
}
}
{{- end }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,220 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.Graph */}}
{{- define "dialect/sql/internal/schemaconfig" -}}
{{ with extend $ "Package" "internal" -}}
{{ template "header" . }}
{{ end }}
import "context"
// SchemaConfig represents alternative schema names for all tables
// that can be passed at runtime.
type SchemaConfig struct {
{{- range $n := $.Nodes }}
{{ $n.Name }} string // {{ $n.Name }} table.
{{- range $e := $n.Edges }}
{{- /* Skip adding join-table in case the edge is inverse or already defined as an edge-schema. */}}
{{- if and $e.M2M (not $e.Inverse) }}
{{ $n.Name }}{{ $e.StructField }} string // {{ $n.Name }}-{{ $e.Name }}->{{ $e.Type.Name }} table.
{{- end }}
{{- end }}
{{- end }}
}
type schemaCtxKey struct{}
// SchemaConfigFromContext returns a SchemaConfig stored inside a context, or empty if there isn't one.
func SchemaConfigFromContext(ctx context.Context) SchemaConfig {
config, _ := ctx.Value(schemaCtxKey{}).(SchemaConfig)
return config
}
// NewSchemaConfigContext returns a new context with the given SchemaConfig attached.
func NewSchemaConfigContext(parent context.Context, config SchemaConfig) context.Context {
return context.WithValue(parent, schemaCtxKey{}, config)
}
{{- end }}
{{/* Additional imports by the schemaconfig feature. */}}
{{- define "dialect/sql/import/additional/schemaconfig" -}}
{{- if $.FeatureEnabled "sql/schemaconfig" }}
"{{ $.Config.Package }}/internal"
{{- end }}
{{- end }}
{{/* Additional fields to the config struct. */}}
{{- define "dialect/sql/config/fields/schemaconfig" -}}
{{- if $.FeatureEnabled "sql/schemaconfig" -}}
// schemaConfig contains alternative names for all tables.
schemaConfig SchemaConfig
{{- end }}
{{- end -}}
{{/* Additional top-level code for the generated config.go file. */}}
{{- define "dialect/sql/config/options/schemaconfig" }}
{{- if $.FeatureEnabled "sql/schemaconfig" }}
// SchemaConfig represents alternative schema names for all tables
// that can be passed at runtime.
type SchemaConfig = internal.SchemaConfig
// AlternateSchemas allows alternate schema names to be
// passed into ent operations.
func AlternateSchema(schemaConfig SchemaConfig) Option {
return func(c *config) {
c.schemaConfig = schemaConfig
}
}
{{- end }}
{{- end }}
{{- define "dialect/sql/delete/spec/ctxschemaconfig" }}
{{- template "dialect/sql/spec/ctxschemaconfig" $ }}
{{- end }}
{{- define "dialect/sql/update/spec/ctxschemaconfig" }}
{{- template "dialect/sql/spec/ctxschemaconfig" $ }}
{{- end }}
{{- define "dialect/sql/create/spec/ctxschemaconfig" }}
{{- with extend $ "Ident" "_spec" "SkipContext" true }}
{{- template "dialect/sql/spec/ctxschemaconfig" . }}
{{- end }}
{{- end }}
{{- define "dialect/sql/query/spec/ctxschemaconfig" }}
{{- template "dialect/sql/spec/ctxschemaconfig" . }}
{{- end }}
{{- define "dialect/sql/query/eagerloading/join/schemaconfig" }}
{{- with extend $ "Ident" "joinT" "CallSet" true }}
{{- template "dialect/sql/defedge/spec/schemaconfig" . }}
{{- end }}
{{- end }}
{{- define "dialect/sql/defedge/spec/schemaconfig" }}
{{- $e := $.Scope.Edge }}
{{- $builder := pascal $.Scope.Builder }}
{{- $receiver := $.Scope.Receiver }}
{{- $ident := "edge" }}{{ with $.Scope.Ident }}{{ $ident = . }}{{ end }}
{{- if $.FeatureEnabled "sql/schemaconfig" }}
{{- $schema := $e.Type.Name }}
{{- if $e.OwnFK }}
{{- $schema = $.Name }}
{{- else if $e.M2M }}
{{- if $e.Through }}
{{- $schema = $e.Through.Name }}
{{- else if $e.Inverse }}
{{- $schema = print $e.Type.Name (pascal $e.Inverse) }}
{{- else }}
{{- $schema = print $.Name $e.StructField }}
{{- end }}
{{- end }}
{{- if $.Scope.CallSet }}
{{ $ident }}.Schema({{ $receiver }}.schemaConfig.{{ $schema }})
{{- else }}
{{ $ident }}.Schema = {{ $receiver }}.schemaConfig.{{ $schema }}
{{- end }}
{{- end }}
{{- end }}
{{/* A template for injecting the SchemaConfig to the context. Should be executed before other templates. */}}
{{- define "dialect/sql/spec/ctxschemaconfig" -}}
{{- $builder := pascal $.Scope.Builder }}
{{- $receiver := $.Scope.Receiver }}
{{- $ident := "_spec.Node" }}{{ with $.Scope.Ident }}{{ $ident = . }}{{ end }}
{{- if $.FeatureEnabled "sql/schemaconfig" }}
{{ $ident }}.Schema = {{ $receiver }}.schemaConfig.{{ $.Name }}
{{- if not $.Scope.SkipContext }}
ctx = internal.NewSchemaConfigContext(ctx, {{ $receiver }}.schemaConfig)
{{- end }}
{{- end }}
{{- end -}}
{{- define "dialect/sql/query/selector/ctxschemaconfig" -}}
{{- $builder := pascal $.Scope.Builder }}
{{- $receiver := $.Scope.Receiver }}
{{- if $.FeatureEnabled "sql/schemaconfig" }}
t1.Schema({{ $receiver }}.schemaConfig.{{ $.Name }})
ctx = internal.NewSchemaConfigContext(ctx, {{ $receiver }}.schemaConfig)
selector.WithContext(ctx)
{{- end }}
{{- end -}}
{{- define "dialect/sql/query/path/ctxschemaconfig" }}
{{- if $.FeatureEnabled "sql/schemaconfig" }}
schemaConfig := {{ $.Scope.Receiver }}.schemaConfig
{{- template "dialect/sql/query/step/ctxschemaconfig" . }}
{{- end -}}
{{- end -}}
{{- define "dialect/sql/query/from/ctxschemaconfig" }}
{{- if $.FeatureEnabled "sql/schemaconfig" }}
schemaConfig := {{ $.Scope.Receiver }}.schemaConfig
{{- template "dialect/sql/query/step/ctxschemaconfig" . }}
{{- end -}}
{{- end -}}
{{- define "dialect/sql/predicate/edge/has/ctxschemaconfig" -}}
{{- template "dialect/sql/predicate/edge/ctxschemaconfig" . }}
{{- end -}}
{{- define "dialect/sql/predicate/edge/haswith/ctxschemaconfig" -}}
{{- template "dialect/sql/predicate/edge/ctxschemaconfig" . }}
{{- end -}}
{{- define "dialect/sql/predicate/edge/ctxschemaconfig" -}}
{{- if $.FeatureEnabled "sql/schemaconfig" }}
schemaConfig := internal.SchemaConfigFromContext(s.Context())
{{- template "dialect/sql/query/step/ctxschemaconfig" . }}
{{- end -}}
{{- end -}}
{{- define "dialect/sql/query/step/ctxschemaconfig" -}}
{{- $e := $.Scope.Edge }}
step.To.Schema = schemaConfig.{{ $e.Type.Name }}
{{- $schema := $e.Type.Name }}
{{- if $e.OwnFK }}
{{- $schema = $.Name }}
{{- else if $e.M2M }}
{{- if $e.Through }}
{{- $schema = $e.Through.Name }}
{{- else if $e.Inverse }}
{{- $schema = print $e.Type.Name (pascal $e.Inverse) }}
{{- else }}
{{- $schema = print $.Name $e.StructField }}
{{- end }}
{{- end }}
step.Edge.Schema = schemaConfig.{{ $schema }}
{{- end -}}
{{- define "config/init/fields/multischema" }}
{{- if $.FeatureEnabled "sql/multischema" }}
cfg.schemaConfig = DefaultSchemaConfig
{{- end }}
{{- end }}
{{- define "dialect/sql/config/options/multischema" }}
{{- if $.FeatureEnabled "sql/multischema" }}
{{- $all := $.TableSchemas }}
var (
// DefaultSchemaConfig represents the default schema names for all tables as defined in ent/schema.
DefaultSchemaConfig = SchemaConfig {
{{- range $n := $.Nodes }}
{{ $n.Name }}: tableSchemas[{{ indexOf $all $n.TableSchema }}],
{{- range $e := $n.Edges }}
{{- if and $e.M2M (not $e.Inverse) (not $e.Through) }}
{{ $n.Name }}{{ $e.StructField }}: tableSchemas[{{ indexOf $all $e.TableSchema }}],
{{- end }}
{{- end }}
{{- end }}
}
tableSchemas = [...]string{ {{- range $i, $s := $all }}{{ if $i }},{{ end }}"{{ $s }}"{{ end }} }
)
{{- end }}
{{- end }}

View File

@@ -0,0 +1,493 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.Type */}}
{{/* Templates used by the "sql/upsert" feature-flag to allows configuring the
`ON CONFLICT` / `ON DUPLICATE KEY` clause for `INSERT` statements */}}
{{/* Template for adding the "conflict" field to the create builder. */}}
{{ define "dialect/sql/create/fields/additional/upsert" -}}
{{- if $.FeatureEnabled "sql/upsert" }}
conflict []sql.ConflictOption
{{- end }}
{{- end -}}
{{/* Template for adding the "conflict" field to the create-bulk builder. */}}
{{ define "dialect/sql/create_bulk/fields/additional/upsert" -}}
{{- if $.FeatureEnabled "sql/upsert" }}
conflict []sql.ConflictOption
{{- end }}
{{- end -}}
{{/* Template for passing the "OnConflict" options to the sqlgraph.CreateSpec. */}}
{{- define "dialect/sql/create/spec/upsert" }}
{{- if $.FeatureEnabled "sql/upsert" }}
_spec.OnConflict = {{ $.Scope.Receiver }}.conflict
{{- end }}
{{- end }}
{{/* Template for passing the "OnConflict" options to the sqlgraph.BatchCreateSpec. */}}
{{- define "dialect/sql/create_bulk/spec/upsert" }}
{{- if $.FeatureEnabled "sql/upsert" }}
spec.OnConflict = {{ $.Scope.Receiver }}.conflict
{{- end }}
{{- end }}
{{/* Template for adding the "OnConflict" methods to the create builder. */}}
{{ define "dialect/sql/create/additional/upsert" }}
{{ if $.FeatureEnabled "sql/upsert" }}
{{ template "helper/upsertone" $ }}
{{ end }}
{{ end }}
{{ define "helper/upsertone" }}
{{ $pkg := base $.Config.Package }}
{{ $builder := pascal $.Scope.Builder }}
{{ $receiver := $.Scope.Receiver }}
{{ $upsertOne := print $.Name "UpsertOne" }}
{{ $upsertSet := print $.Name "Upsert" }}
// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
// of the `INSERT` statement. For example:
//
// client.{{ $.Name }}.Create().
{{- with $.Fields }}
{{- $f := index $.Fields 0 }}
// Set{{ index $f.StructField }}(v).
{{- end }}
// OnConflict(
// // Update the row with the new values
// // the was proposed for insertion.
// sql.ResolveWithNewValues(),
// ).
{{- with $.Fields }}
{{- $f := index $.Fields 0 }}
// // Override some of the fields with custom
// // update values.
// Update(func(u *ent.{{ $.Name }}Upsert) {
// Set{{ index $f.StructField }}(v+v).
// }).
{{- end }}
// Exec(ctx)
//
func ({{ $receiver }} *{{ $builder }}) OnConflict(opts ...sql.ConflictOption) *{{ $upsertOne }} {
{{ $receiver }}.conflict = opts
return &{{ $upsertOne }}{
create: {{ $receiver }},
}
}
// OnConflictColumns calls `OnConflict` and configures the columns
// as conflict target. Using this option is equivalent to using:
//
// client.{{ $.Name }}.Create().
// OnConflict(sql.ConflictColumns(columns...)).
// Exec(ctx)
//
func ({{ $receiver }} *{{ $builder }}) OnConflictColumns(columns ...string) *{{ $upsertOne }} {
{{ $receiver }}.conflict = append({{ $receiver }}.conflict, sql.ConflictColumns(columns...))
return &{{ $upsertOne }}{
create: {{ $receiver }},
}
}
type (
// {{ $upsertOne }} is the builder for "upsert"-ing
// one {{ $.Name }} node.
{{ $upsertOne }} struct {
create *{{ $builder }}
}
// {{ $upsertSet }} is the "OnConflict" setter.
{{ $upsertSet }} struct {
*sql.UpdateSet
}
)
{{ range $f := $.UpsertFields }}
{{- if $f.IsBlob }}
{{ $func := print "Update" $f.StructField }}
// {{ $func }} sets the "{{ $f.Name }}" field to the value that was provided on create.
func (u *{{ $upsertSet }}) {{ $func }}() *{{ $upsertSet }} {
{{- if not $f.IsBlobNoColumn }}
u.SetExcluded({{ $.Package }}.{{ $f.Constant }})
{{- end }}
u.SetExcluded("{{ $f.BlobKeyColumn }}")
return u
}
{{ if $f.Optional }}
{{ $func := print "Clear" $f.StructField }}
// {{ $func }} clears the value of the "{{ $f.Name }}" field.
func (u *{{ $upsertSet }}) {{ $func }}() *{{ $upsertSet }} {
{{- if not $f.IsBlobNoColumn }}
u.SetNull({{ $.Package }}.{{ $f.Constant }})
{{- end }}
u.SetNull("{{ $f.BlobKeyColumn }}")
return u
}
{{ end }}
{{- continue }}{{ end }}
{{ $func := print "Set" $f.StructField }}
// {{ $func }} sets the "{{ $f.Name }}" field.
func (u *{{ $upsertSet }}) {{ $func }}(v {{ $f.Type }}) *{{ $upsertSet }} {
u.Set({{ $.Package }}.{{ $f.Constant }}, v)
return u
}
{{ $func = print "Update" $f.StructField }}
// {{ $func }} sets the "{{ $f.Name }}" field to the value that was provided on create.
func (u *{{ $upsertSet }}) {{ $func }}() *{{ $upsertSet }} {
u.SetExcluded({{ $.Package }}.{{ $f.Constant }})
return u
}
{{ if $f.SupportsMutationAdd }}
{{ $func := print "Add" $f.StructField }}
// {{ $func }} adds v to the "{{ $f.Name }}" field.
func (u *{{ $upsertSet }}) {{ $func }}(v {{ $f.Type }}) *{{ $upsertSet }} {
u.Add({{ $.Package }}.{{ $f.Constant }}, v)
return u
}
{{ end }}
{{ if $f.Optional }}
{{ $func := print "Clear" $f.StructField }}
// {{ $func }} clears the value of the "{{ $f.Name }}" field.
func (u *{{ $upsertSet }}) {{ $func }}() *{{ $upsertSet }} {
u.SetNull({{ $.Package }}.{{ $f.Constant }})
return u
}
{{ end }}
{{ end }}
{{ $udfID := false }}{{ if $.HasOneFieldID }}{{ $udfID = $.ID.UserDefined }}{{ end }}
// UpdateNewValues updates the mutable fields using the new values that were set on create{{ if $udfID }} except the ID field{{ end }}.
// Using this option is equivalent to using:
//
// client.{{ $.Name }}.Create().
// OnConflict(
// sql.ResolveWithNewValues(),
{{- if $udfID }}
// sql.ResolveWith(func(u *sql.UpdateSet) {
// u.SetIgnore({{ $.Package }}.{{ $.ID.Constant }})
// }),
{{- end }}
// ).
// Exec(ctx)
//
func (u *{{ $upsertOne }}) UpdateNewValues() *{{ $upsertOne }} {
u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())
{{- if or $udfID $.ImmutableFields }}
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) {
{{- if $udfID }}
if _, exists := u.create.mutation.ID(); exists {
s.SetIgnore({{ $.Package }}.{{ $.ID.Constant }})
}
{{- end }}
{{- range $f := $.ImmutableFields }}
if _, exists := u.create.mutation.{{ $f.MutationGet }}(); exists {
s.SetIgnore({{ $.Package }}.{{ $f.Constant }})
}
{{- end }}
}))
{{- end }}
return u
}
// Ignore sets each column to itself in case of conflict.
// Using this option is equivalent to using:
//
// client.{{ $.Name }}.Create().
// OnConflict(sql.ResolveWithIgnore()).
// Exec(ctx)
//
func (u *{{ $upsertOne }}) Ignore() *{{ $upsertOne }} {
u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())
return u
}
// DoNothing configures the conflict_action to `DO NOTHING`.
// Supported only by SQLite and PostgreSQL.
func (u *{{ $upsertOne }}) DoNothing() *{{ $upsertOne }} {
u.create.conflict = append(u.create.conflict, sql.DoNothing())
return u
}
// Update allows overriding fields `UPDATE` values. See the {{ $builder }}.OnConflict
// documentation for more info.
func (u *{{ $upsertOne }}) Update(set func(*{{ $upsertSet }})) *{{ $upsertOne }} {
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
set(&{{ $upsertSet }}{UpdateSet: update})
}))
return u
}
{{ with extend $ "Upsert" $upsertOne "UpsertSet" $upsertSet }}
{{ template "helper/upsert/fields" . }}
{{ end }}
// Exec executes the query.
func (u *{{ $upsertOne }}) Exec(ctx context.Context) error {
if len(u.create.conflict) == 0 {
return errors.New("{{ $pkg }}: missing options for {{ $builder }}.OnConflict")
}
return u.create.Exec(ctx)
}
// ExecX is like Exec, but panics if an error occurs.
func (u *{{ $upsertOne }}) ExecX(ctx context.Context) {
if err := u.create.Exec(ctx); err != nil {
panic(err)
}
}
{{ if $.HasOneFieldID }}
// Exec executes the UPSERT query and returns the inserted/updated ID.
func (u *{{ $upsertOne }}) ID(ctx context.Context) (id {{ $.ID.Type }}, err error) {
{{- if and $udfID (not $.ID.Type.Numeric) }}
if u.create.driver.Dialect() == dialect.MySQL {
// In case of "ON CONFLICT", there is no way to get back non-numeric ID
// fields from the database since MySQL does not support the RETURNING clause.
return id, errors.New("{{ $pkg }}: {{ $upsertOne }}.ID is not supported by MySQL driver. Use {{ $upsertOne }}.Exec instead")
}
{{- end }}
node, err := u.create.Save(ctx)
if err != nil {
return id, err
}
return node.ID, nil
}
// IDX is like ID, but panics if an error occurs.
func (u *{{ $upsertOne }}) IDX(ctx context.Context) {{ $.ID.Type }} {
id, err := u.ID(ctx)
if err != nil {
panic(err)
}
return id
}
{{ end }}
{{ end }}
{{ define "dialect/sql/create_bulk/additional/upsert" }}
{{ if $.FeatureEnabled "sql/upsert" }}
{{ template "helper/upsertbulk" $ }}
{{ end }}
{{ end }}
{{/* Template for adding the "OnConflict" methods to the create-bulk builder. */}}
{{ define "helper/upsertbulk" }}
{{ $pkg := base $.Config.Package }}
{{ $builder := pascal $.Scope.Builder }}
{{ $receiver := $.Scope.Receiver }}
{{ $upsertBulk := print $.Name "UpsertBulk" }}
{{ $upsertSet := print $.Name "Upsert" }}
{{ $udfID := false }}{{ if $.HasOneFieldID }}{{ $udfID = $.ID.UserDefined }}{{ end }}
// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
// of the `INSERT` statement. For example:
//
// client.{{ $.Name }}.CreateBulk(builders...).
// OnConflict(
// // Update the row with the new values
// // the was proposed for insertion.
// sql.ResolveWithNewValues(),
// ).
{{- with $.Fields }}
{{- $f := index $.Fields 0 }}
// // Override some of the fields with custom
// // update values.
// Update(func(u *ent.{{ $.Name }}Upsert) {
// Set{{ index $f.StructField }}(v+v).
// }).
{{- end }}
// Exec(ctx)
//
func ({{ $receiver }} *{{ $builder }}) OnConflict(opts ...sql.ConflictOption) *{{ $upsertBulk }} {
{{ $receiver }}.conflict = opts
return &{{ $upsertBulk }}{
create: {{ $receiver }},
}
}
// OnConflictColumns calls `OnConflict` and configures the columns
// as conflict target. Using this option is equivalent to using:
//
// client.{{ $.Name }}.Create().
// OnConflict(sql.ConflictColumns(columns...)).
// Exec(ctx)
//
func ({{ $receiver }} *{{ $builder }}) OnConflictColumns(columns ...string) *{{ $upsertBulk }} {
{{ $receiver }}.conflict = append({{ $receiver }}.conflict, sql.ConflictColumns(columns...))
return &{{ $upsertBulk }}{
create: {{ $receiver }},
}
}
// {{ $upsertBulk }} is the builder for "upsert"-ing
// a bulk of {{ $.Name }} nodes.
type {{ $upsertBulk }} struct {
create *{{ $builder }}
}
// UpdateNewValues updates the mutable fields using the new values that
// were set on create. Using this option is equivalent to using:
//
// client.{{ $.Name }}.Create().
// OnConflict(
// sql.ResolveWithNewValues(),
{{- if $udfID }}
// sql.ResolveWith(func(u *sql.UpdateSet) {
// u.SetIgnore({{ $.Package }}.{{ $.ID.Constant }})
// }),
{{- end }}
// ).
// Exec(ctx)
//
func (u *{{ $upsertBulk }}) UpdateNewValues() *{{ $upsertBulk }} {
u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())
{{- if or $udfID $.ImmutableFields }}
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) {
for _, b := range u.create.builders {
{{- if $udfID }}
if _, exists := b.mutation.ID(); exists {
s.SetIgnore({{ $.Package }}.{{ $.ID.Constant }})
}
{{- end }}
{{- range $f := $.ImmutableFields }}
if _, exists := b.mutation.{{ $f.MutationGet }}(); exists {
s.SetIgnore({{ $.Package }}.{{ $f.Constant }})
}
{{- end }}
}
}))
{{- end }}
return u
}
// Ignore sets each column to itself in case of conflict.
// Using this option is equivalent to using:
//
// client.{{ $.Name }}.Create().
// OnConflict(sql.ResolveWithIgnore()).
// Exec(ctx)
//
func (u *{{ $upsertBulk }}) Ignore() *{{ $upsertBulk }} {
u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())
return u
}
// DoNothing configures the conflict_action to `DO NOTHING`.
// Supported only by SQLite and PostgreSQL.
func (u *{{ $upsertBulk }}) DoNothing() *{{ $upsertBulk }} {
u.create.conflict = append(u.create.conflict, sql.DoNothing())
return u
}
// Update allows overriding fields `UPDATE` values. See the {{ $builder }}.OnConflict
// documentation for more info.
func (u *{{ $upsertBulk }}) Update(set func(*{{ $upsertSet }})) *{{ $upsertBulk }} {
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
set(&{{ $upsertSet }}{UpdateSet: update})
}))
return u
}
{{ with extend $ "Upsert" $upsertBulk "UpsertSet" $upsertSet }}
{{ template "helper/upsert/fields" . }}
{{ end }}
// Exec executes the query.
func (u *{{ $upsertBulk }}) Exec(ctx context.Context) error {
if u.create.err != nil {
return u.create.err
}
for i, b := range u.create.builders {
if len(b.conflict) != 0 {
return fmt.Errorf("{{ $pkg }}: OnConflict was set for builder %d. Set it on the {{ $builder }} instead", i)
}
}
if len(u.create.conflict) == 0 {
return errors.New("{{ $pkg }}: missing options for {{ $builder }}.OnConflict")
}
return u.create.Exec(ctx)
}
// ExecX is like Exec, but panics if an error occurs.
func (u *{{ $upsertBulk }}) ExecX(ctx context.Context) {
if err := u.create.Exec(ctx); err != nil {
panic(err)
}
}
{{- end }}
{{ define "helper/upsert/fields" }}
{{ $upsert := $.Scope.Upsert }}
{{ $upsertSet := $.Scope.UpsertSet }}
{{ range $f := $.UpsertFields }}
{{- if $f.IsBlob }}
{{ $func := print "Update" $f.StructField }}
// {{ $func }} sets the "{{ $f.Name }}" field to the value that was provided on create.
func (u *{{ $upsert }}) {{ $func }}() *{{ $upsert }} {
return u.Update(func(s *{{ $upsertSet }}) {
s.{{ $func }}()
})
}
{{ if $f.Optional }}
{{ $func := print "Clear" $f.StructField }}
// {{ $func }} clears the value of the "{{ $f.Name }}" field.
func (u *{{ $upsert }}) {{ $func }}() *{{ $upsert }} {
return u.Update(func(s *{{ $upsertSet }}) {
s.{{ $func }}()
})
}
{{ end }}
{{- continue }}{{ end }}
{{ $func := print "Set" $f.StructField }}
// {{ $func }} sets the "{{ $f.Name }}" field.
func (u *{{ $upsert }}) {{ $func }}(v {{ $f.Type }}) *{{ $upsert }} {
return u.Update(func(s *{{ $upsertSet }}) {
s.{{ $func }}(v)
})
}
{{ if $f.SupportsMutationAdd }}
{{ $func := print "Add" $f.StructField }}
// {{ $func }} adds v to the "{{ $f.Name }}" field.
func (u *{{ $upsert }}) {{ $func }}(v {{ $f.Type }}) *{{ $upsert }} {
return u.Update(func(s *{{ $upsertSet }}) {
s.{{ $func }}(v)
})
}
{{ end }}
{{ $func = print "Update" $f.StructField }}
// {{ $func }} sets the "{{ $f.Name }}" field to the value that was provided on create.
func (u *{{ $upsert }}) {{ $func }}() *{{ $upsert }} {
return u.Update(func(s *{{ $upsertSet }}) {
s.{{ $func }}()
})
}
{{ if $f.Optional }}
{{ $func := print "Clear" $f.StructField }}
// {{ $func }} clears the value of the "{{ $f.Name }}" field.
func (u *{{ $upsert }}) {{ $func }}() *{{ $upsert }} {
return u.Update(func(s *{{ $upsertSet }}) {
s.{{ $func }}()
})
}
{{ end }}
{{ end }}
{{ end }}

View File

@@ -0,0 +1,14 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.Graph */}}
{{/* custom globals and helpers for sql dialects */}}
{{ define "dialect/sql/globals" }}
// queryHook describes an internal hook for the different sqlAll methods.
type queryHook func(context.Context, *sqlgraph.QuerySpec)
{{ end }}

View File

@@ -0,0 +1,40 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.typeScope */}}
{{ define "dialect/sql/group" }}
{{ $builder := pascal $.Scope.Builder }}
{{ $receiver := $.Scope.Receiver }}
func ({{ $receiver }} *{{ $builder }}) sqlScan(ctx context.Context, root *{{ $.QueryName }}, v any) error {
selector := root.sqlQuery(ctx).Select()
aggregation := make([]string, 0, len({{ $receiver}}.fns))
for _, fn := range {{ $receiver }}.fns {
aggregation = append(aggregation, fn(selector))
}
{{- /* If no columns were selected, the default selection is the fields used for "group-by", and the aggregation functions.*/}}
if len(selector.SelectedColumns()) == 0 {
columns := make([]string, 0, len(*{{ $receiver }}.flds) + len({{ $receiver}}.fns))
for _, f := range *{{ $receiver }}.flds {
columns = append(columns, selector.C(f))
}
columns = append(columns, aggregation...)
selector.Select(columns...)
}
selector.GroupBy(selector.Columns(*{{ $receiver }}.flds...)...)
if err := selector.Err(); err != nil {
return err
}
rows := &sql.Rows{}
query, args := selector.Query()
if err := {{ $receiver }}.build.driver.Query(ctx, query, args, rows); err != nil {
return err
}
defer rows.Close()
return sql.ScanSlice(rows, v)
}
{{ end }}

View File

@@ -0,0 +1,194 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.Type */}}
{{/* Constants needed for sql dialects. */}}
{{ define "dialect/sql/meta/constants" }}
{{- range $t := $.RelatedTypes }}
{{- $withEID := $.HasCompositeID }}
{{- if and (not $withEID) $t.HasOneFieldID }}
{{- if ne $t.ID.StorageKey $.ID.StorageKey }}{{ $withEID = true }}{{ end }}
{{- end }}
{{- if $withEID }}
// {{ $t.Name }}FieldID holds the string denoting the ID field of the {{ $t.Name }}.
{{ $t.Name }}FieldID = "{{ $t.ID.StorageKey }}"
{{- end }}
{{- end }}
// Table holds the table name of the {{ lower $.Name }} in the database.
Table = "{{ $.Table }}"
{{- range $e := $.Edges }}
// {{ $e.TableConstant }} is the table that holds the {{ $e.Name }} relation/edge.
{{- if $e.M2M }} The primary key declared below.{{ end }}
{{ $e.TableConstant }} = "{{ $e.Rel.Table }}"
{{- if ne $.Table $e.Type.Table }}
// {{ $e.InverseTableConstant }} is the table name for the {{ $e.Type.Name }} entity.
// It exists in this package in order to avoid circular dependency with the "{{ $e.Type.Package }}" package.
{{ $e.InverseTableConstant }} = "{{ $e.Type.Table }}"
{{- end }}
{{- if not $e.M2M }}
// {{ $e.ColumnConstant }} is the table column denoting the {{ $e.Name }} relation/edge.
{{ $e.ColumnConstant }} = "{{ $e.Rel.Column }}"
{{- end }}
{{- end }}
{{- with $tmpls := matchTemplate "dialect/sql/meta/constants/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{ end }}
{{/* Variables needed for sql dialects. */}}
{{ define "dialect/sql/meta/variables" }}
// Columns holds all SQL columns for {{ lower $.Name }} fields.
var Columns = []string{
{{- if $.HasOneFieldID }}
{{ $.ID.Constant }},
{{- end }}
{{- range $f := $.Fields }}
{{- if and (not $f.IsDeprecated) (not $f.IsBlobNoColumn) (not $f.IsBlobLazy) }}
{{ $f.Constant }},
{{- end }}
{{- end }}
{{- range $k := $.BlobKeys }}
"{{ $k.Field.Name }}",
{{- end }}
}
{{/* If any of the edges owns a foreign-key */}}
{{ with $.UnexportedForeignKeys }}
// ForeignKeys holds the SQL foreign-keys that are owned by the "{{ $.Table }}"
// table and are not defined as standalone fields in the schema.
var ForeignKeys = []string{
{{- range $fk := . }}
"{{ $fk.Edge.Rel.Column }}",
{{- end }}
}
{{ end }}
{{ with $.BlobKeys }}
// BlobKeys holds the SQL columns for blob storage keys.
var BlobKeys = []string{
{{- range $bk := . }}
"{{ $bk.Field.Name }}",
{{- end }}
}
{{ end }}
{{ with $.NumM2M }}
var (
{{- range $e := $.Edges }}
{{- if $e.M2M }}
// {{ $e.PKConstant }} and {{ $e.ColumnConstant }}2 are the table columns denoting the
// primary key for the {{ $e.Name }} relation (M2M).
{{ $e.PKConstant }} = []string{"{{ index $e.Rel.Columns 0 }}", "{{ index $e.Rel.Columns 1 }}"}
{{- end }}
{{- end }}
)
{{ end }}
{{ end }}
{{/* Functions needed for sql dialects. */}}
{{ define "dialect/sql/meta/functions" }}
// ValidColumn reports if the column name is valid (part of the table columns).
func ValidColumn(column string) bool {
for i := range Columns {
if column == Columns[i] {
return true
}
}
{{- with $.UnexportedForeignKeys }}
for i := range ForeignKeys {
if column == ForeignKeys[i] {
return true
}
}
{{- end }}
{{- with $.BlobKeys }}
for i := range BlobKeys {
if column == BlobKeys[i] {
return true
}
}
{{- end }}
{{- with $.DeprecatedFields }}
for _, f := range [...]string{ {{- range . }}{{ .Constant }},{{ end }} } {
if column == f {
return true
}
}
{{- end }}
return false
}
{{ end }}
{{/* Type-safe order-by builders. */}}
{{ define "dialect/sql/meta/order" }}
{{ if $.HasOneFieldID }}
// {{ $.ID.OrderName }} orders the results by the {{ $.ID.Name }} field.
func {{ $.ID.OrderName }}(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField({{ $.ID.Constant }}, opts...).ToFunc()
}
{{ end }}
{{- range $f := $.Fields }}
{{- if $f.Type.Comparable }}
// {{ $f.OrderName }} orders the results by the {{ $f.Name }} field.
func {{ $f.OrderName }}(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField({{ $f.Constant }}, opts...).ToFunc()
}
{{- end }}
{{- end }}
{{- range $e := $.Edges }}
{{- if $e.Unique }}
// {{ $e.OrderFieldName }} orders the results by {{ $e.Name }} field.
func {{ $e.OrderFieldName }}(field string, opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborTerms(s, new{{ pascal $e.Name }}Step(), sql.OrderByField(field, opts...))
}
}
{{- else }}
// {{ $e.OrderCountName }} orders the results by {{ $e.Name }} count.
func {{ $e.OrderCountName }}(opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborsCount(s, new{{ pascal $e.Name }}Step(), opts...)
}
}
// {{ $e.OrderTermsName }} orders the results by {{ $e.Name }} terms.
func {{ $e.OrderTermsName }}(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborTerms(s, new{{ pascal $e.Name }}Step(), append([]sql.OrderTerm{term}, terms...)...)
}
}
{{- end }}
{{- end }}
{{- range $e := $.Edges }}
func new{{ pascal $e.Name }}Step() *sqlgraph.Step {
return sqlgraph.NewStep(
{{- if $.HasCompositeID }}
{{- /* Query that goes from the edge schema. */}}
sqlgraph.From(Table, {{ $e.ColumnConstant }}),
sqlgraph.To({{ $e.InverseTableConstant }}, {{ print $e.Type.Name "FieldID" }}),
{{- else }}
sqlgraph.From(Table, {{ $.ID.Constant }}),
{{- if $e.Type.HasOneFieldID }}
{{- $refid := $.ID.Constant }}{{ if ne $e.Type.ID.StorageKey $.ID.StorageKey }}{{ $refid = print $e.Type.Name "FieldID" }}{{ end }}
sqlgraph.To({{ if ne $.Table $e.Type.Table }}{{ $e.InverseTableConstant }}{{ else }}Table{{ end }}, {{ $refid }}),
{{- else }}
{{- /* Query that goes to the edge schema. */}}
sqlgraph.To({{ if ne $.Table $e.Type.Table }}{{ $e.InverseTableConstant }}{{ else }}Table{{ end }}, {{ $e.ColumnConstant }}),
{{- end }}
{{- end }}
sqlgraph.Edge(sqlgraph.{{ $e.Rel.Type }}, {{ $e.IsInverse }}, {{ $e.TableConstant }},
{{- if $e.M2M -}}
{{ $e.PKConstant }}...
{{- else -}}
{{ $e.ColumnConstant }}
{{- end -}}
),
)
}
{{- end }}
{{ end }}

View File

@@ -0,0 +1,15 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.Graph */}}
{{ define "dialect/sql/client/open" }}
drv, err := sql.Open(driverName, dataSourceName)
if err != nil {
return nil, err
}
return NewClient(append(options, Driver(drv))...), nil
{{ end }}

View File

@@ -0,0 +1,99 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.typeScope */}}
{{ define "dialect/sql/predicate/id" -}}
{{- $arg := "id" }}
{{- with $.Scope.Arg }}
{{- $arg = . }}
{{- end -}}
sql.FieldEQ({{ $.ID.Constant }}, {{ $arg }})
{{- end }}
{{ define "dialect/sql/predicate/id/ops" -}}
{{- $op := $.Scope.Op -}}
{{- $storage := $.Scope.Storage -}}
{{- $arg := "id" -}}
{{- if $op.Variadic }}{{ $arg = "ids" }}{{ end -}}
{{- with $.Scope.Arg -}}
{{- $arg = . -}}
{{- end -}}
sql.Field{{ call $storage.OpCode $op }}({{ $.ID.Constant }}{{ if not $op.Niladic }}, {{ $arg }}{{ if $op.Variadic }}...{{ end }}{{ end }})
{{- end }}
{{ define "dialect/sql/predicate/field" -}}
{{- $f := $.Scope.Field -}}
{{- $arg := $.Scope.Arg -}}
sql.FieldEQ({{ $f.Constant }}, {{ $arg }})
{{- end }}
{{ define "dialect/sql/predicate/field/ops" -}}
{{- $f := $.Scope.Field -}}
{{- $op := $.Scope.Op -}}
{{- $arg := $.Scope.Arg -}}
{{- $storage := $.Scope.Storage -}}
sql.Field{{ call $storage.OpCode $op }}({{ $f.Constant }}{{ if not $op.Niladic }}, {{ $arg }}{{ if $op.Variadic }}...{{ end }}{{ end }})
{{- end }}
{{ define "dialect/sql/predicate/edge/has" -}}
{{- $e := $.Scope.Edge -}}
func(s *sql.Selector) {
step := sqlgraph.NewStep(
{{- if $.HasCompositeID }}
{{- /* Query that goes from the edge schema. */}}
sqlgraph.From(Table, {{ $e.ColumnConstant }}),
{{- else }}
sqlgraph.From(Table, {{ $.ID.Constant }}),
{{- end }}
sqlgraph.Edge(sqlgraph.{{ $e.Rel.Type }}, {{ $e.IsInverse }}, {{ $e.TableConstant }},
{{- if $e.M2M -}}
{{ $e.PKConstant }}...
{{- else -}}
{{ $e.ColumnConstant }}
{{- end -}}
),
)
{{- /* Allow mutating the sqlgraph.Step by ent extensions or user templates.*/}}
{{- with $tmpls := matchTemplate "dialect/sql/predicate/edge/has/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{- /* sqlgraph.To is meaningless on Has<E> (without predicates), because unlike Has<E>With no predicates are applied on the "other" table. */}}
sqlgraph.HasNeighbors(s, step)
}
{{- end }}
{{ define "dialect/sql/predicate/edge/haswith" -}}
{{- $e := $.Scope.Edge -}}
func(s *sql.Selector) {
step := new{{ pascal $e.Name }}Step()
{{- /* Allow mutating the sqlgraph.Step by ent extensions or user templates.*/}}
{{- with $tmpls := matchTemplate "dialect/sql/predicate/edge/haswith/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds {
p(s)
}
})
}
{{- end }}
{{ define "dialect/sql/predicate/and" -}}
sql.AndPredicates(predicates...)
{{- end }}
{{ define "dialect/sql/predicate/or" -}}
sql.OrPredicates(predicates...)
{{- end }}
{{ define "dialect/sql/predicate/not" -}}
sql.NotPredicates(p)
{{- end }}

View File

@@ -0,0 +1,601 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.typeScope */}}
{{/* Additional fields for the builder. */}}
{{ define "dialect/sql/query/fields" }}
{{- with $.UnexportedForeignKeys }}
withFKs bool
{{- end }}
{{- with $tmpls := matchTemplate "dialect/sql/query/fields/additional/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{- end }}
{{ define "dialect/sql/query" }}
{{ $pkg := $.Scope.Package }}
{{ $builder := pascal $.Scope.Builder }}
{{ $receiver := $.Scope.Receiver }}
func ({{ $receiver }} *{{ $builder }}) sqlAll(ctx context.Context, hooks ...queryHook) ([]*{{ $.Name }}, error) {
var (
nodes = []*{{ $.Name }}{}
{{- with $.UnexportedForeignKeys }}
withFKs = {{ $receiver }}.withFKs
{{- end }}
_spec = {{ $receiver }}.querySpec()
{{- with $.Edges }}
loadedTypes = [{{ len . }}]bool{
{{- range $e := . }}
{{ $receiver }}.{{ $e.EagerLoadField }} != nil,
{{- end }}
}
{{- end }}
)
{{- with $.UnexportedForeignKeys }}
{{- $edgesWithoutField := list }}
{{- range $.FKEdges }}{{ if not .Field }}{{ $edgesWithoutField = append $edgesWithoutField . }}{{ end }}{{ end }}
{{- if $edgesWithoutField }}
if {{ range $i, $e := $edgesWithoutField }}{{ if $i }} || {{ end }}{{ $receiver }}.{{ $e.EagerLoadField }} != nil{{ end }} {
withFKs = true
}
{{- end }}
if withFKs {
_spec.Node.Columns = append(_spec.Node.Columns, {{ $.Package }}.ForeignKeys...)
}
{{- end }}
_spec.ScanValues = func(columns []string) ([]any, error) {
return (*{{ $.Name }}).scanValues(nil, columns)
}
_spec.Assign = func(columns []string, values []any) error {
node := &{{ $.Name }}{config: {{ $receiver }}.config}
nodes = append(nodes, node)
{{- with $.Edges }}
node.Edges.loadedTypes = loadedTypes
{{- end }}
return node.assignValues(columns, values)
}
{{- /* Allow mutating the sqlgraph.QuerySpec by ent extensions or user templates.*/}}
{{- with $tmpls := matchTemplate "dialect/sql/query/spec/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
for i := range hooks {
hooks[i](ctx, _spec)
}
if err := sqlgraph.QueryNodes(ctx, {{ $receiver }}.driver, _spec); err != nil {
return nil, err
}
if len(nodes) == 0 {
return nodes, nil
}
{{- range $e := $.Edges }}
if query := {{ $receiver }}.{{ $e.EagerLoadField }}; query != nil {
if err := {{ $receiver }}.load{{ $e.StructField }}(ctx, query, nodes, {{ if $e.Unique }}nil{{ else }}
func(n *{{ $.Name }}){ n.Edges.{{ $e.StructField }} = []*{{ $e.Type.Name }}{} }{{ end }},
{{- $lhs := printf "n.Edges.%s" $e.StructField }}
{{- $rhs := print "e" }}{{- if not $e.Unique }}{{ $rhs = printf "append(%s, e)" $lhs }}{{ end }}
{{- if and ($.FeatureEnabled "bidiedges") $e.Ref $e.Ref.Unique }}
func(n *{{ $.Name }}, e *{{ $e.Type.Name }}){
{{ printf "%s = %s" $lhs $rhs }}
{{- $idx := $e.Ref.Index }}
{{- /* Set only in case this type was not loaded explicitly (without custom options). */}}
if !e.Edges.loadedTypes[{{ $idx }}] {
e.Edges.{{ $e.Ref.StructField }} = n
}
}); err != nil {
{{- else }}
{{- /* Keep it one-liner if there is not inverse-condition. */}}
func(n *{{ $.Name }}, e *{{ $e.Type.Name }}){ {{ printf "%s = %s" $lhs $rhs }} }); err != nil {
{{- end }}
return nil, err
}
}
{{- end }}
{{- /* Allow extensions to inject code using templates to process nodes before they are returned. */}}
{{- with $tmpls := matchTemplate "dialect/sql/query/all/nodes/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{- if $.HasLoadOnScanFields }}
if err := {{ $receiver }}.loadBlobFields(ctx, nodes); err != nil {
return nil, err
}
{{- end }}
return nodes, nil
}
{{- if $.HasLoadOnScanFields }}
func ({{ $receiver }} *{{ $builder }}) loadBlobFields(ctx context.Context, nodes []*{{ $.Name }}) error {
_blobs := ent.NewBlobStore({{ $receiver }}.blobOpeners.{{ $.Name }})
for _, n := range nodes {
{{- range $f := $.LoadOnScanFields }}
if n.{{ $f.BlobKeyColumn }} != nil && *n.{{ $f.BlobKeyColumn }} != "" {
{{- if $f.IsBlobNoColumn }}
{{- /* Non-DualWrite: blob is the only source of data. */}}
data, err := _blobs.Read(ctx, {{ $.Package }}.{{ $f.Constant }}, *n.{{ $f.BlobKeyColumn }})
if err != nil {
return errors.Join(fmt.Errorf("loading {{ $f.Name }}: %w", err), _blobs.Close())
}
if data == nil {
return errors.Join(fmt.Errorf("loading {{ $f.Name }}: object %q not found in blob storage", *n.{{ $f.BlobKeyColumn }}), _blobs.Close())
}
{{- if $f.HasValueScanner }}
sv := {{ $f.ScanValueFunc }}()
if err := sv.Scan(data); err != nil {
return errors.Join(fmt.Errorf("scanning {{ $f.Name }}: %w", err), _blobs.Close())
}
v, err := {{ $f.FromValueFunc }}(sv)
if err != nil {
return errors.Join(fmt.Errorf("scanning {{ $f.Name }}: %w", err), _blobs.Close())
}
n.{{ $f.StructField }} = v
{{- else if $f.IsBlobGoString }}
n.{{ $f.StructField }} = {{ $f.Type }}(data)
{{- else }}
n.{{ $f.StructField }} = data
{{- end }}
{{- else }}
{{- /* DualWrite: prefer blob value, but preserve the column value when blob is missing. */}}
switch data, err := _blobs.Read(ctx, {{ $.Package }}.{{ $f.Constant }}, *n.{{ $f.BlobKeyColumn }}); {
case err != nil:
return errors.Join(fmt.Errorf("loading {{ $f.Name }}: %w", err), _blobs.Close())
case data != nil:
{{- if $f.HasValueScanner }}
sv := {{ $f.ScanValueFunc }}()
if err := sv.Scan(data); err != nil {
return errors.Join(fmt.Errorf("scanning {{ $f.Name }}: %w", err), _blobs.Close())
}
v, err := {{ $f.FromValueFunc }}(sv)
if err != nil {
return errors.Join(fmt.Errorf("scanning {{ $f.Name }}: %w", err), _blobs.Close())
}
n.{{ $f.StructField }} = v
{{- else if $f.IsBlobGoString }}
n.{{ $f.StructField }} = {{ $f.Type }}(data)
{{- else }}
n.{{ $f.StructField }} = data
{{- end }}
}
{{- end }}
}
{{- end }}
}
return _blobs.Close()
}
{{- end }}
{{/* Generate a method to eager-load each edge. */}}
{{- range $e := $.Edges }}
func ({{ $receiver }} *{{ $builder }}) load{{ $e.StructField }}(ctx context.Context, query *{{ $e.Type.QueryName }}, nodes []*{{ $.Name }}, init func(*{{ $.Name }}), assign func(*{{ $.Name }}, *{{ $e.Type.Name }})) error {
{{- if $e.M2M }}
edgeIDs := make([]driver.Value, len(nodes))
byID := make(map[{{ $.ID.Type }}]*{{ $.Name }})
nids := make(map[{{ $e.Type.ID.Type }}]map[*{{ $.Name }}]struct{})
for i, node := range nodes {
{{- if $.ID.HasValueScanner }}
vv, err := {{ $.ID.ValueFunc }}(node.ID)
if err != nil {
return err
}
edgeIDs[i] = vv
{{- else }}
edgeIDs[i] = node.ID
{{- end }}
byID[node.ID] = node
if init != nil {
init(node)
}
}
query.Where(func(s *sql.Selector) {
joinT := sql.Table({{ $.Package }}.{{ $e.TableConstant }})
{{- with $tmpls := matchTemplate "dialect/sql/query/eagerloading/join/*" }}
{{- range $tmpl := $tmpls }}
{{- with extend $ "Edge" $e }}
{{- xtemplate $tmpl . }}
{{- end }}
{{- end }}
{{- end }}
{{- $edgeid := print $e.Type.Package "." $e.Type.ID.Constant }}
{{- $fk1idx := 1 }}{{- $fk2idx := 0 }}{{ if $e.IsInverse }}{{ $fk1idx = 0 }}{{ $fk2idx = 1 }}{{ end }}
s.Join(joinT).On(s.C({{ $edgeid }}), joinT.C({{ $.Package }}.{{ $e.PKConstant }}[{{ $fk1idx }}]))
s.Where(sql.InValues(joinT.C({{ $.Package }}.{{ $e.PKConstant }}[{{ $fk2idx }}]), edgeIDs...))
columns := s.SelectedColumns()
s.Select(joinT.C({{ $.Package }}.{{ $e.PKConstant }}[{{ $fk2idx }}]))
s.AppendSelect(columns...)
s.SetDistinct(false)
})
if err := query.prepareQuery(ctx); err != nil {
return err
}
qr := QuerierFunc(func(ctx context.Context, q Query) (Value, error) {
return query.sqlAll(ctx, func(_ context.Context, spec *sqlgraph.QuerySpec) {
assign := spec.Assign
values := spec.ScanValues
{{- $out := "sql.NullInt64" }}{{ if $.ID.UserDefined }}{{ $out = $.ID.ScanType }}{{ end }}
{{- $in := "sql.NullInt64" }}{{ if $e.Type.ID.UserDefined }}{{ $in = $e.Type.ID.ScanType }}{{ end }}
spec.ScanValues = func(columns []string) ([]any, error) {
values, err := values(columns[1:])
if err != nil {
return nil, err
}
{{- if $.ID.HasValueScanner }}
return append([]any{ {{ $.ID.ScanValueFunc }}() }, values...), nil
{{- else }}
return append([]any{new({{ $out }})}, values...), nil
{{- end }}
}
spec.Assign = func(columns []string, values []any) error {
{{- if $.ID.HasValueScanner }}
var outValue {{ $.ID.Type }}
{{- with extend $ "Arg" "values[0]" "Field" $.ID "ScanType" $out "Ident" "outValue" }}
{{ template "dialect/sql/query/eagerloading/m2massign" . }}
{{- end }}
{{- else }}
outValue := {{- with extend $ "Arg" "values[0]" "Field" $.ID "ScanType" $out }}{{ template "dialect/sql/query/eagerloading/m2massignexpr" . }}{{- end }}
{{- end }}
{{- if $e.Type.ID.HasValueScanner }}
var inValue {{ $e.Type.ID.Type }}
{{- with extend $ "Arg" "values[1]" "Field" $e.Type.ID "ScanType" $in "Ident" "inValue" }}
{{ template "dialect/sql/query/eagerloading/m2massign" . }}
{{- end }}
{{- else }}
inValue := {{- with extend $ "Arg" "values[1]" "Field" $e.Type.ID "ScanType" $in }}{{ template "dialect/sql/query/eagerloading/m2massignexpr" . }}{{- end }}
{{- end }}
if nids[inValue] == nil {
nids[inValue] = map[*{{ $.Name }}]struct{}{byID[outValue]: {}}
return assign(columns[1:], values[1:])
}
nids[inValue][byID[outValue]] = struct{}{}
return nil
}
})
})
neighbors, err := withInterceptors[[]*{{ $e.Type.Name }}](ctx, query, qr, query.inters)
if err != nil {
return err
}
for _, n := range neighbors {
nodes, ok := nids[n.ID]
if !ok {
return fmt.Errorf(`unexpected "{{ $e.Name }}" node returned %v`, n.ID)
}
for kn := range nodes {
assign(kn, n)
}
}
{{- else if $e.OwnFK }}
ids := make([]{{ $e.Type.ID.Type }}, 0, len(nodes))
nodeids := make(map[{{ $e.Type.ID.Type }}][]*{{ $.Name }})
for i := range nodes {
{{- $fk := $e.ForeignKey }}
{{- if $fk.Field.Nillable }}
if nodes[i].{{ $fk.StructField }} == nil {
continue
}
{{- end }}
fk := {{ if $fk.Field.Nillable }}*{{ end }}nodes[i].{{ $fk.StructField }}
if _, ok := nodeids[fk]; !ok {
ids = append(ids, fk)
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where({{ $e.Type.Package }}.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
nodes, ok := nodeids[n.ID]
if !ok {
return fmt.Errorf(`unexpected foreign-key "{{ $fk.Field.Name }}" returned %v`, n.ID)
}
for i := range nodes {
assign(nodes[i], n)
}
}
{{- else }}
fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[{{ $.ID.Type }}]*{{ $.Name }})
for i := range nodes {
{{- if $.ID.HasValueScanner }}
vv, err := {{ $.ID.ValueFunc }}(nodes[i].ID)
if err != nil {
return err
}
fks = append(fks, vv)
{{- else }}
fks = append(fks, nodes[i].ID)
{{- end }}
nodeids[nodes[i].ID] = nodes[i]
{{- if $e.O2M }}
if init != nil {
init(nodes[i])
}
{{- end }}
}
{{- with $e.Type.UnexportedForeignKeys }}
query.withFKs = true
{{- end }}
{{- /* In case of custom field selection, ensure edge-fields used for binding below were selected. */}}
{{- if and $e.Ref $e.Ref.Field }}
if len(query.ctx.Fields) > 0 {
query.ctx.AppendFieldOnce({{ $e.Type.Package }}.{{ $e.Ref.Field.Constant }})
}
{{- end }}
query.Where(predicate.{{ $e.Type.Name }}(func(s *sql.Selector) {
s.Where(sql.InValues(s.C({{ $.Package }}.{{ $e.ColumnConstant }}), fks...))
}))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
{{- $fk := $e.ForeignKey }}
fk := n.{{ $fk.StructField }}
{{- if $fk.Field.Nillable }}
if fk == nil {
return fmt.Errorf(`foreign-key "{{ $fk.Field.Name }}" is nil for node %v`, n.ID)
}
{{- end }}
node, ok := nodeids[{{ if $fk.Field.Nillable }}*{{ end }}fk]
if !ok {
return fmt.Errorf(`unexpected referenced foreign-key "{{ $fk.Field.Name }}" returned %v for node %v`, {{ if $fk.Field.Nillable }}*{{ end }}fk, n{{ if $e.Type.HasOneFieldID }}.ID{{ end }})
}
assign(node, n)
}
{{- end }}
return nil
}
{{- end }}
func ({{ $receiver }} *{{ $builder }}) sqlCount(ctx context.Context) (int, error) {
_spec := {{ $receiver }}.querySpec()
{{- /* Allow mutating the sqlgraph.QuerySpec by ent extensions or user templates. */}}
{{- with $tmpls := matchTemplate "dialect/sql/query/spec/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{- if $.HasCompositeID }}
{{- /* In case of an edge schema with composite primary-key, there is no need to SELECT DISTINCT. */}}
_spec.Unique = false
_spec.Node.Columns = nil
{{- else }}
_spec.Node.Columns = {{ $receiver }}.ctx.Fields
if len({{ $receiver }}.ctx.Fields) > 0 {
{{- /* In case of field selection, configure query to unique only if was explicitly set to true. */}}
_spec.Unique = {{ $receiver }}.ctx.Unique != nil && *{{ $receiver }}.ctx.Unique
}
{{- end }}
return sqlgraph.CountNodes(ctx, {{ $receiver }}.driver, _spec)
}
func ({{ $receiver }} *{{ $builder }}) querySpec() *sqlgraph.QuerySpec {
_spec := sqlgraph.NewQuerySpec({{ $.Package }}.Table, {{ $.Package }}.Columns, {{ if $.HasOneFieldID }}sqlgraph.NewFieldSpec({{ $.Package }}.{{ $.ID.Constant }}, field.{{ $.ID.Type.ConstName }}){{ else }}nil{{ end }})
{{- /* Setup any intermediate queries if exist (traversal path). */}}
_spec.From = {{ $receiver }}.sql
if unique := {{ $receiver }}.ctx.Unique; unique != nil {
_spec.Unique = *unique
} else if {{ $receiver }}.path != nil {
_spec.Unique = true
}
if fields := {{ $receiver }}.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
{{- if $.HasOneFieldID }}
_spec.Node.Columns = append(_spec.Node.Columns, {{ $.Package }}.{{ $.ID.Constant }})
for i := range fields {
if fields[i] != {{ $.Package }}.{{ $.ID.Constant }} {
_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
}
}
{{- else }}
for i := range fields {
_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
}
{{- end }}
{{- /* In case of custom field selection, ensure edge-fields are loaded in case their edges were loaded. */}}
{{- range $.FKEdges }}
{{- $f := .Field }}
{{- if not $f }}
{{- continue }}
{{- end }}
if {{ $receiver }}.{{ .EagerLoadField }} != nil {
_spec.Node.AddColumnOnce({{ $.Package }}.{{ $f.Constant }})
}
{{- end }}
}
if ps := {{ $receiver }}.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if limit := {{ $receiver }}.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := {{ $receiver }}.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := {{ $receiver }}.order; len(ps) > 0 {
_spec.Order = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
return _spec
}
{{ template "dialect/sql/query/selector" $ }}
{{- /* Allow adding methods to the query-builder by ent extensions or user templates.*/}}
{{- with $tmpls := matchTemplate "dialect/sql/query/additional/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{ end }}
{{ define "dialect/sql/query/selector" }}
{{ $builder := pascal $.Scope.Builder }}
{{ $receiver := $.Scope.Receiver }}
func ({{ $receiver }} *{{ $builder }}) sqlQuery(ctx context.Context) *sql.Selector {
{{- $builderV := "builder" }}{{ if eq $.Package $builderV }}{{ $builderV = "builderC" }}{{ end }}
{{ $builderV }} := sql.Dialect({{ $receiver }}.driver.Dialect())
t1 := {{ $builderV }}.Table({{ $.Package }}.Table)
columns := {{ $receiver }}.ctx.Fields
if len(columns) == 0 {
columns = {{ $.Package }}.Columns
}
selector := {{ $builderV }}.Select(t1.Columns(columns...)...).From(t1)
if {{ $receiver }}.sql != nil {
selector = {{ $receiver }}.sql
selector.Select(selector.Columns(columns...)...)
}
if {{ $receiver }}.ctx.Unique != nil && *{{ $receiver }}.ctx.Unique {
selector.Distinct()
}
{{- /* Allow mutating the sql.Selector by ent extensions or user templates.*/}}
{{- with $tmpls := matchTemplate "dialect/sql/query/selector/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
for _, p := range {{ $receiver }}.predicates {
p(selector)
}
for _, p := range {{ $receiver }}.order {
p(selector)
}
if offset := {{ $receiver }}.ctx.Offset; offset != nil {
// limit is mandatory for offset clause. We start
// with default value, and override it below if needed.
selector.Offset(*offset).Limit(math.MaxInt32)
}
if limit := {{ $receiver }}.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
}
{{ end }}
{{/* query/path defines the query generation for path of a given edge. */}}
{{ define "dialect/sql/query/path" }}
{{- $n := $ }} {{/* the node we start the query from. */}}
{{- $e := $.Scope.Edge }} {{/* the edge we need to generate the path to. */}}
{{- $ident := $.Scope.Ident -}}
{{- $receiver := $.Scope.Receiver }}
selector := {{ $receiver }}.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From({{ $n.Package }}.Table, {{ $n.Package }}.{{ if $n.HasCompositeID }}{{ $e.ColumnConstant }}{{ else }}{{ $n.ID.Constant }}{{ end }}, selector),
sqlgraph.To({{ $e.Type.Package }}.Table, {{ $e.Type.Package }}.{{ if $e.Type.HasCompositeID }}{{ $e.Ref.ColumnConstant }}{{ else }}{{ $e.Type.ID.Constant }}{{ end }}),
sqlgraph.Edge(sqlgraph.{{ $e.Rel.Type }}, {{ $e.IsInverse }}, {{ $n.Package }}.{{ $e.TableConstant }},
{{- if $e.M2M -}}
{{ $n.Package }}.{{ $e.PKConstant }}...
{{- else -}}
{{ $n.Package }}.{{ $e.ColumnConstant }}
{{- end -}}
),
)
{{- /* Allow mutating the sqlgraph.Step by ent extensions or user templates.*/}}
{{- with $tmpls := matchTemplate "dialect/sql/query/path/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{ $ident }} = sqlgraph.SetNeighbors({{ $receiver }}.driver.Dialect(), step)
{{ end }}
{{/* query/from defines the query generation for an edge query from a given node. */}}
{{ define "dialect/sql/query/from" }}
{{- $n := $ }} {{/* the node we start the query from. */}}
{{- $e := $.Scope.Edge }} {{/* the edge we need to genegrate the path to. */}}
{{- $ident := $.Scope.Ident -}}
{{- $receiver := $.Scope.Receiver -}}
{{- if $n.ID.HasValueScanner -}}
id := any({{ $receiver }}.ID)
vv, err := {{ $n.ID.ValueFunc }}({{ $receiver }}.ID)
if err != nil {
return nil, err
}
id = vv
{{- else -}}
id := {{ $receiver }}.ID
{{- end }}
step := sqlgraph.NewStep(
sqlgraph.From({{ $n.Package }}.Table, {{ $n.Package }}.{{ $n.ID.Constant }}, id),
sqlgraph.To({{ $e.Type.Package }}.Table, {{ $e.Type.Package }}.{{ if $e.Type.HasCompositeID }}{{ $e.Ref.ColumnConstant }}{{ else }}{{ $e.Type.ID.Constant }}{{ end }}),
sqlgraph.Edge(sqlgraph.{{ $e.Rel.Type }}, {{ $e.IsInverse }}, {{ $n.Package }}.{{ $e.TableConstant }},
{{- if $e.M2M -}}
{{ $n.Package }}.{{ $e.PKConstant }}...
{{- else -}}
{{ $n.Package }}.{{ $e.ColumnConstant }}
{{- end -}}
),
)
{{- /* Allow mutating the sqlgraph.Step by ent extensions or user templates.*/}}
{{- with $tmpls := matchTemplate "dialect/sql/query/from/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{ $ident }} = sqlgraph.Neighbors({{ $receiver }}.driver.Dialect(), step)
{{ end }}
{{ define "dialect/sql/query/eagerloading/m2massign" -}}
{{- $arg := $.Scope.Arg -}}
{{- $field := $.Scope.Field -}}
{{- $scantype := $.Scope.ScanType -}}
{{- $ident := $.Scope.Ident -}}
{{- if $field.HasValueScanner }}
if value, err := {{ $field.FromValueFunc }}({{ $arg }}); err != nil {
return err
} else {
{{ $ident }} = value
}
{{- else if hasPrefix $scantype "sql" -}}
{{ $ident }} = {{ printf "%s.(*%s)" $arg $scantype | $field.ScanTypeField }}
{{- else -}}
{{ $ident }} = {{ if not $field.Nillable }}*{{ end }}{{ printf "%s.(*%s)" $arg $scantype }}
{{- end }}
{{- end }}
{{ define "dialect/sql/query/eagerloading/m2massignexpr" -}}
{{- $arg := $.Scope.Arg -}}
{{- $field := $.Scope.Field -}}
{{- $scantype := $.Scope.ScanType -}}
{{- if hasPrefix $scantype "sql" -}}
{{ printf "%s.(*%s)" $arg $scantype | $field.ScanTypeField -}}
{{- else -}}
{{ if not $field.Nillable }}*{{ end }}{{ printf "%s.(*%s)" $arg $scantype }}
{{- end }}
{{- end }}
{{ define "dialect/sql/query/preparecheck" }}
{{- $pkg := $.Scope.Package }}
{{- $receiver := $.Scope.Receiver }}
for _, f := range {{ $receiver }}.ctx.Fields {
if !{{ $.Package }}.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("{{ $pkg }}: invalid field %q for query", f)}
}
}
{{- end }}

View File

@@ -0,0 +1,42 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.typeScope */}}
{{ define "dialect/sql/select" }}
{{ $builder := pascal $.Scope.Builder }}
{{ $receiver := $.Scope.Receiver }}
func ({{ $receiver }} *{{ $builder }}) sqlScan(ctx context.Context, root *{{ $.QueryName }}, v any) error {
selector := root.sqlQuery(ctx)
aggregation := make([]string, 0, len({{ $receiver}}.fns))
for _, fn := range {{ $receiver }}.fns {
aggregation = append(aggregation, fn(selector))
}
switch n := len(*{{ $receiver }}.selector.flds); {
{{- /* If no columns were selected, the default selection is the aggregation.*/}}
case n == 0 && len(aggregation) > 0:
selector.Select(aggregation...)
case n != 0 && len(aggregation) > 0:
selector.AppendSelect(aggregation...)
}
rows := &sql.Rows{}
query, args := selector.Query()
if err := {{ $receiver }}.driver.Query(ctx, query, args, rows); err != nil {
return err
}
defer rows.Close()
return sql.ScanSlice(rows, v)
}
{{/* Allow adding methods to the select-builder by ent extensions or user templates.*/}}
{{ with $tmpls := matchTemplate "dialect/sql/select/additional/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{ end }}
{{ end }}

View File

@@ -0,0 +1,31 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.Graph */}}
{{ define "dialect/sql/txoptions" }}
// BeginTx returns a transactional client with specified options.
func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
if _, ok := c.driver.(*txDriver); ok {
return nil, errors.New("ent: cannot start a transaction within a transaction")
}
tx, err := c.driver.(interface {
BeginTx(context.Context, *sql.TxOptions) (dialect.Tx, error)
}).BeginTx(ctx, opts)
if err != nil {
return nil, fmt.Errorf("ent: starting a transaction: %w", err)
}
cfg := c.config
cfg.driver = &txDriver{tx: tx, drv: c.driver}
return &Tx{
ctx: ctx,
config: cfg,
{{- range $n := $.Nodes }}
{{ $n.Name }}: New{{ $n.ClientName }}(cfg),
{{- end }}
}, nil
}
{{ end }}

View File

@@ -0,0 +1,395 @@
{{/*
Copyright 2019-present Facebook Inc. All rights reserved.
This source code is licensed under the Apache 2.0 license found
in the LICENSE file in the root directory of this source tree.
*/}}
{{/* gotype: entgo.io/ent/entc/gen.typeScope */}}
{{/* Additional fields for the builder. */}}
{{ define "dialect/sql/update/fields" }}
{{- with $tmpls := matchTemplate "dialect/sql/update/fields/additional/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{- end }}
{{ define "dialect/sql/update" }}
{{ $pkg := $.Scope.Package }}
{{ $builder := pascal $.Scope.Builder }}
{{ $receiver := $.Scope.Receiver }}
{{ $mutation := print $receiver ".mutation" }}
{{ $one := hasSuffix $builder "One" }}
{{- $zero := 0 }}{{ if $one }}{{ $zero = "nil" }}{{ end }}
{{- /* Allow adding methods to the update-builder by ent extensions or user templates.*/}}
{{- with $tmpls := matchTemplate "dialect/sql/update/additional/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
func ({{ $receiver }} *{{ $builder }}) sqlSave(ctx context.Context) (_node {{ if $one }}*{{ $.Name }}{{ else }}int{{ end }}, err error) {
{{- if $.HasUpdateCheckers }}
if err := {{ $receiver }}.check(); err != nil {
return _node, err
}
{{- end }}
_spec := sqlgraph.NewUpdateSpec({{ $.Package }}.Table, {{ $.Package }}.Columns,
{{- if $.HasOneFieldID -}}
sqlgraph.NewFieldSpec({{ $.Package }}.{{ $.ID.Constant }}, field.{{ $.ID.Type.ConstName }})
{{- else -}}
{{- range $id := $.EdgeSchema.ID -}}
sqlgraph.NewFieldSpec({{ $.Package }}.{{ $id.Constant }}, field.{{ $id.Type.ConstName }}),
{{- end -}}
{{- end }})
{{- if $one }}
{{- if $.HasOneFieldID }}
id, ok := {{ $mutation }}.{{ $.ID.MutationGet }}()
if !ok {
return {{ $zero }}, &ValidationError{Name: "{{ $.ID.Name }}", err: errors.New(`{{ $pkg }}: missing "{{ $.Name }}.{{ $.ID.Name }}" for update`)}
}
{{- if $.ID.HasValueScanner }}
vv, err := {{ $.ID.ValueFunc }}(id)
if err != nil {
return {{ $zero }}, err
}
_spec.Node.ID.Value = vv
{{- else }}
_spec.Node.ID.Value = id
{{- end }}
if fields := {{ $receiver }}.fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, {{ $.Package }}.{{ $.ID.Constant }})
for _, f := range fields {
if !{{ $.Package }}.ValidColumn(f) {
return nil, &ValidationError{Name: f, err: fmt.Errorf("{{ $pkg }}: invalid field %q for query", f)}
}
if f != {{ $.Package }}.{{ $.ID.Constant }} {
_spec.Node.Columns = append(_spec.Node.Columns, f)
}
}
}
{{- else }}{{/* Composite ID. */}}
{{- range $i, $id := $.EdgeSchema.ID }}
if id, ok := {{ $mutation }}.{{ $id.MutationGet }}(); !ok {
return {{ $zero }}, &ValidationError{Name: "{{ $id.Name }}", err: errors.New(`{{ $pkg }}: missing "{{ $.Name }}.{{ $id.Name }}" for update`)}
} else {
_spec.Node.CompositeID[{{ $i }}].Value = id
}
{{- end }}
if fields := {{ $receiver }}.fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, len(fields))
for i, f := range fields {
if !{{ $.Package }}.ValidColumn(f) {
return nil, &ValidationError{Name: f, err: fmt.Errorf("{{ $pkg }}: invalid field %q for query", f)}
}
_spec.Node.Columns[i] = f
}
}
{{- end }}
{{- end }}
if ps := {{ $mutation }}.Predicates(); len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
{{- range $f := $.MutationFields }}
{{- if $f.IsBlobNoColumn }}{{ continue }}{{ end }}
{{- if or (not $f.Immutable) $f.UpdateDefault }}
if value, ok := {{ $mutation }}.{{ $f.MutationGet }}(); ok {
{{- if $f.HasValueScanner }}
vv, err := {{ $f.ValueFunc }}(value)
if err != nil {
return {{ $zero }}, err
}
_spec.SetField({{ $.Package }}.{{ $f.Constant }}, field.{{ $f.Type.ConstName }}, vv)
{{- else }}
_spec.SetField({{ $.Package }}.{{ $f.Constant }}, field.{{ $f.Type.ConstName }}, value)
{{- end }}
}
{{- if $f.SupportsMutationAdd }}
if value, ok := {{ $mutation }}.{{ $f.MutationAdded }}(); ok {
{{- if $f.HasValueScanner }}
vv, err := {{ $f.ValueFunc }}(value)
if err != nil {
return {{ $zero }}, err
}
_spec.AddField({{ $.Package }}.{{ $f.Constant }}, field.{{ $f.Type.ConstName }}, vv)
{{- else }}
_spec.AddField({{ $.Package }}.{{ $f.Constant }}, field.{{ $f.Type.ConstName }}, value)
{{- end }}
}
{{- end }}
{{- if $f.SupportsMutationAppend }}
if value, ok := {{ $mutation }}.{{ $f.MutationAppended }}(); ok {
_spec.AddModifier(func(u *sql.UpdateBuilder) {
sqljson.Append(u, {{ $.Package }}.{{ $f.Constant }}, value)
})
}
{{- end }}
{{- end }}
{{- if $f.Optional }}
if {{ $mutation }}.{{ $f.StructField }}Cleared() {
_spec.ClearField({{ $.Package }}.{{ $f.Constant }}, field.{{ $f.Type.ConstName }})
}
{{- end }}
{{- end }}
{{- range $e := $.EdgesWithID }}
{{- if $e.Immutable }}
{{- /* Skip to the next one as immutable edges cannot be updated. */}}
{{- continue }}
{{- end }}
if {{ $mutation }}.{{ $e.MutationCleared }}() {
{{- with extend $ "Edge" $e }}
{{ template "dialect/sql/defedge" . }}
{{- end }}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
{{- if not $e.Unique }}
if nodes := {{ $mutation }}.Removed{{ $e.StructField }}IDs(); len(nodes) > 0 && !{{ $mutation }}.{{ $e.MutationCleared }}() {
{{- with extend $ "Edge" $e "Nodes" true "Zero" $zero }}
{{ template "dialect/sql/defedge" . }}
{{- end }}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
{{- end }}
if nodes := {{ $mutation }}.{{ $e.StructField }}IDs(); len(nodes) > 0 {
{{- with extend $ "Edge" $e "Nodes" true "Zero" $zero }}
{{ template "dialect/sql/defedge" . }}
{{- end }}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
{{- end }}
{{- /* Allow mutating the sqlgraph.UpdateSpec by ent extensions or user templates.*/}}
{{- with $tmpls := matchTemplate "dialect/sql/update/spec/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{- if and $one $.HasBlobFields }}
_blobs := ent.NewBlobs({{ $mutation }}.blobOpeners.{{ $.Name }})
{{- range $f := $.BlobFields }}
{{- if not $f.IsBlobLazy }}
if value, ok := {{ $mutation }}.{{ $f.MutationGet }}(); ok {
{{- if $f.HasValueScanner }}
_blobDV, err := {{ $f.ValueFunc }}(value)
if err != nil {
return {{ $zero }}, fmt.Errorf("{{ $pkg }}: encoding {{ $f.Name }}: %w", err)
}
var _blobData []byte
switch v := _blobDV.(type) {
case []byte:
_blobData = v
case string:
_blobData = []byte(v)
default:
return {{ $zero }}, fmt.Errorf("{{ $pkg }}: encoding {{ $f.Name }}: expected []byte or string, got %T", _blobDV)
}
_blobs.Set({{ $.Package }}.{{ $f.Constant }}, _blobData,
{{ if $f.HasBlobKey }}{{ $.Package }}.{{ $f.BlobKeyName }}{{ else }}defaultBlobKey{{ end }},
func(k string) {
_spec.SetField("{{ $f.BlobKeyColumn }}", field.TypeString, k)
},
)
{{- else if $f.IsBlobGoString }}
_blobs.Set({{ $.Package }}.{{ $f.Constant }}, []byte(value),
{{ if $f.HasBlobKey }}{{ $.Package }}.{{ $f.BlobKeyName }}{{ else }}defaultBlobKey{{ end }},
func(k string) {
_spec.SetField("{{ $f.BlobKeyColumn }}", field.TypeString, k)
},
)
{{- else }}
_blobs.Set({{ $.Package }}.{{ $f.Constant }}, value,
{{ if $f.HasBlobKey }}{{ $.Package }}.{{ $f.BlobKeyName }}{{ else }}defaultBlobKey{{ end }},
func(k string) {
_spec.SetField("{{ $f.BlobKeyColumn }}", field.TypeString, k)
},
)
{{- end }}
}
{{- if $f.Optional }}
if {{ $mutation }}.{{ $f.StructField }}Cleared() {
_blobs.SetCleared({{ $.Package }}.{{ $f.Constant }}, func() {
_spec.ClearField("{{ $f.BlobKeyColumn }}", field.TypeString)
})
}
{{- end }}
{{- else }}
if r, ok := {{ $mutation }}.{{ $f.StructField }}(); ok {
_blobData, err := io.ReadAll(r)
if err != nil {
return {{ $zero }}, fmt.Errorf("{{ $pkg }}: reading {{ $f.Name }}: %w", err)
}
_blobs.Set({{ $.Package }}.{{ $f.Constant }}, _blobData,
{{ if $f.HasBlobKey }}{{ $.Package }}.{{ $f.BlobKeyName }}{{ else }}defaultBlobKey{{ end }},
func(k string) {
_spec.SetField("{{ $f.BlobKeyColumn }}", field.TypeString, k)
},
)
}
{{- if $f.Optional }}
if {{ $mutation }}.{{ $f.MutationCleared }}() {
_blobs.SetCleared({{ $.Package }}.{{ $f.Constant }}, func() {
_spec.ClearField("{{ $f.BlobKeyColumn }}", field.TypeString)
})
}
{{- end }}
{{- end }}
{{- end }}
_blobResult, err := _blobs.Update(ctx, &sqlgraph.BlobSpec{
Driver: {{ $receiver }}.driver,
Table: {{ $.Package }}.Table,
Columns: map[string]string{
{{- range $f := $.BlobFields }}
{{ $.Package }}.{{ $f.Constant }}: "{{ $f.BlobKeyColumn }}",
{{- end }}
},
{{- if $.HasBlobRefCheckedFields }}
CheckRefs: map[string]bool{
{{- range $f := $.BlobRefCheckedFields }}
{{ $.Package }}.{{ $f.Constant }}: true,
{{- end }}
},
{{- end }}
Predicate: func(s *sql.Selector) {
s.Where(sql.EQ({{ $.Package }}.{{ $.ID.Constant }}, _spec.Node.ID.Value))
},
})
if err != nil {
return {{ $zero }}, err
}
{{- end }}
{{- if $one }}
_node = &{{ $.Name }}{config: {{ $receiver }}.config}
_spec.Assign = _node.assignValues
_spec.ScanValues = _node.scanValues
{{- end }}
{{- if $one }}
if err = sqlgraph.UpdateNode(ctx, {{ $receiver }}.driver, _spec); err != nil {
{{- else }}
if _node, err = sqlgraph.UpdateNodes(ctx, {{ $receiver }}.driver, _spec); err != nil {
{{- end }}
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{ {{ $.Package }}.Label}
} else if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
{{- if and $one $.HasBlobFields }}
return {{ $zero }}, errors.Join(err, _blobResult.Rollback(ctx))
{{- else }}
return {{ $zero }}, err
{{- end }}
}
{{ $mutation }}.done = true
{{- if and $one $.HasBlobFields }}
// Resolve which replaced blobs are unreferenced now that the row moved to its new
// keys, while the transaction is still open, and remove them once it commits.
_blobCleanup, err := _blobResult.Cleanup(ctx)
if err != nil {
return {{ $zero }}, err
}
if txd, ok := {{ $receiver }}.driver.(*txDriver); ok {
txd.mu.Lock()
txd.onCommit = append(txd.onCommit, func(next Committer) Committer {
return CommitFunc(func(ctx context.Context, tx *Tx) error {
if err := next.Commit(ctx, tx); err != nil {
return err
}
return _blobCleanup(ctx)
})
})
txd.onRollback = append(txd.onRollback, func(next Rollbacker) Rollbacker {
return RollbackFunc(func(ctx context.Context, tx *Tx) error {
err := next.Rollback(ctx, tx)
return errors.Join(err, _blobResult.Rollback(ctx))
})
})
txd.mu.Unlock()
} else if err := _blobCleanup(ctx); err != nil {
return {{ $zero }}, err
}
{{- end }}
{{- if and $one $.HasLoadOnScanFields }}
{{- /* Blob values are consistent after write — use mutation value for mutated fields
instead of re-reading from storage. For DualWrite fields, assignValues already
populated the value from the SQL column. For non-DualWrite fields not mutated,
read from blob storage. */}}
_blobReader := ent.NewBlobStore({{ $mutation }}.blobOpeners.{{ $.Name }})
{{- range $f := $.LoadOnScanFields }}
if value, ok := {{ $mutation }}.{{ $f.MutationGet }}(); ok {
_node.{{ $f.StructField }} = value
}
{{- if $f.IsBlobNoColumn }} else if _node.{{ $f.BlobKeyColumn }} != nil && *_node.{{ $f.BlobKeyColumn }} != "" {
data, err := _blobReader.Read(ctx, {{ $.Package }}.{{ $f.Constant }}, *_node.{{ $f.BlobKeyColumn }})
if err != nil {
return nil, errors.Join(fmt.Errorf("loading {{ $f.Name }} after update: %w", err), _blobReader.Close())
}
{{- if $f.HasValueScanner }}
sv := {{ $f.ScanValueFunc }}()
if err := sv.Scan(data); err != nil {
return nil, errors.Join(fmt.Errorf("scanning {{ $f.Name }} after update: %w", err), _blobReader.Close())
}
v, err := {{ $f.FromValueFunc }}(sv)
if err != nil {
return nil, errors.Join(fmt.Errorf("scanning {{ $f.Name }} after update: %w", err), _blobReader.Close())
}
_node.{{ $f.StructField }} = v
{{- else if $f.IsBlobGoString }}
_node.{{ $f.StructField }} = {{ $f.Type }}(data)
{{- else }}
_node.{{ $f.StructField }} = data
{{- end }}
}
{{- end }}
{{- end }}
if err := _blobReader.Close(); err != nil {
return nil, err
}
{{- end }}
return _node, nil
}
{{ end }}
{{ define "dialect/sql/defedge" }}
{{- $e := $.Scope.Edge -}}
{{- $receiver := $.Scope.Receiver -}}
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.{{ $e.Rel.Type }},
Inverse: {{ $e.IsInverse }},
Table: {{ $.Package }}.{{ $e.TableConstant }},
Columns: {{ if $e.M2M }}{{ $.Package }}.{{ $e.PKConstant }}{{ else }}[]string{ {{ $.Package }}.{{ $e.ColumnConstant }} }{{ end }},
Bidi: {{ $e.Bidi }},
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec({{ $e.Type.Package }}.{{ $e.Type.ID.Constant }}, field.{{ $e.Type.ID.Type.ConstName }}),
},
}
{{- /* Allow mutating the sqlgraph.EdgeSpec by ent extensions or user templates.*/}}
{{- with $tmpls := matchTemplate "dialect/sql/defedge/spec/*" }}
{{- range $tmpl := $tmpls }}
{{- xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{- with $.Scope.Nodes }}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
{{- end }}
{{- with $e.Through }}
{{- if .HasDefault }}
createE := &{{ .CreateName }}{config: {{ $receiver }}.config, mutation: new{{ .MutationName }}({{ $receiver }}.config, OpCreate)}
{{- /* Skip error handling here as this check was already handled. */}}
{{ if or .NumHooks .NumPolicy }}_ = {{ end }}createE.defaults()
_, specE := createE.createSpec()
edge.Target.Fields = specE.Fields
{{- if and .HasOneFieldID .ID.Default }}
if specE.ID.Value != nil {
edge.Target.Fields = append(edge.Target.Fields, specE.ID)
}
{{- end }}
{{- end }}
{{- end }}
{{- end }}