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,173 @@
{{/*
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 "create" }}
{{ $pkg := base $.Config.Package }}
{{ $runtimeRequired := or $.NumHooks $.NumPolicy }}
{{ template "header" $ }}
{{ with extend $ "Imports" $.SiblingImports }}
{{ template "import" . }}
{{ end }}
{{ $builder := $.CreateName }}
{{ $receiver := $.CreateReceiver }}
{{ $mutation := print $receiver ".mutation" }}
// {{ $builder }} is the builder for creating a {{ $.Name }} entity.
type {{ $builder }} struct {
config
mutation *{{ $.MutationName }}
hooks []Hook
{{- /* Additional fields to add to the builder. */}}
{{- $tmpl := printf "dialect/%s/create/fields" $.Storage }}
{{- if hasTemplate $tmpl }}
{{- xtemplate $tmpl . }}
{{- end }}
}
{{ with extend $ "Receiver" $receiver "Builder" $builder }}
{{ template "setter" . }}
{{ end }}
// Save creates the {{ $.Name }} in the database.
func ({{ $receiver }} *{{ $builder }}) Save(ctx context.Context) (*{{ $.Name }}, error) {
{{- if $.HasDefault }}
{{- if $runtimeRequired }}
if err := {{ $receiver }}.defaults(); err != nil {
return nil, err
}
{{- else }}
{{ $receiver }}.defaults()
{{- end }}
{{- end }}
return withHooks(ctx, {{ $receiver }}.{{ $.Storage }}Save, {{ $mutation }}, {{ $receiver }}.hooks)
}
// SaveX calls Save and panics if Save returns an error.
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)
}
}
{{- $fields := $.Fields }}{{ if $.HasOneFieldID }}{{ if $.ID.UserDefined }}{{ $fields = append $fields $.ID }}{{ end }}{{ end }}
{{ if $.HasDefault }}
// defaults sets the default values of the builder before save.
func ({{ $receiver }} *{{ $builder }}) defaults() {{ if $runtimeRequired }}error{{ end }}{
{{- range $f := $fields }}
{{- if $f.Default }}
if _, ok := {{ $mutation }}.{{ $f.MutationGet }}(); !ok {
{{- if and $runtimeRequired $f.DefaultFunc }}
if {{ $.Package }}.{{ $f.DefaultName }} == nil {
return fmt.Errorf("{{ $pkg }}: uninitialized {{ $.Package }}.{{ $f.DefaultName }} (forgotten import {{ $pkg }}/runtime?)")
}
{{- end }}
v := {{ $.Package }}.{{ $f.DefaultName }}{{ if $f.DefaultFunc }}(){{ end }}
{{ $mutation }}.{{ $f.MutationSet }}(v)
}
{{- end }}
{{- end }}
{{- if $runtimeRequired }}
return nil
{{- end }}
}
{{ end }}
// check runs all checks and user-defined validators on the builder.
func ({{ $receiver }} *{{ $builder }}) check() error {
{{- range $f := $fields }}
{{- if and $f.IsBlobLazy (not (hasTemplate (printf "dialect/%s/model/fields" $.Storage))) }}{{ continue }}{{ end }}
{{- $skip := false }}{{ if $.HasOneFieldID }}{{ if eq $f.Name $.ID.Name }}{{ $skip = true }}{{ end }}{{ end }}
{{- if and (not $f.Optional) (not $skip) }}
{{- $dialects := $f.RequiredFor }}
{{- $n := len $dialects }}
{{- if $n }}
{{- $partially := ne $n (len $.Config.Storage.Dialects) }}
{{- if $partially }}
switch {{ $receiver }}.driver.Dialect() {
case {{ join $dialects ", " }}:
{{- end }}
if _, ok := {{ $mutation }}.{{ $f.MutationGet }}(); !ok {
return &ValidationError{Name: "{{ $f.Name }}", err: errors.New(`{{ $pkg }}: missing required field "{{ $.Name }}.{{ $f.Name }}"`)}
}
{{- if $partially }}
}
{{- end }}
{{- end }}
{{- end }}
{{- $isValidator := and ($f.HasGoType) ($f.Type.Validator) }}
{{- with or $f.Validators $f.IsEnum $isValidator }}
if v, ok := {{ $mutation }}.{{ $f.MutationGet }}(); ok {
if err := {{ if or $f.Validators $f.IsEnum }}{{ $.Package }}.{{ $f.Validator }}({{ $f.BasicType "v" }}){{ else }}v.Validate(){{ end }}; err != nil {
return &ValidationError{Name: "{{ $f.Name }}", err: fmt.Errorf(`{{ $pkg }}: validator failed for field "{{ $.Name }}.{{ $f.Name }}": %w`, err)}
}
}
{{- end }}
{{- end }}
{{- range $e := $.EdgesWithID }}
{{- if not $e.Optional }}
if len({{ $mutation }}.{{ $e.StructField }}IDs()) == 0 {
return &ValidationError{Name: "{{ $e.Name }}", err: errors.New(`{{ $pkg }}: missing required edge "{{ $.Name }}.{{ $e.Name }}"`)}
}
{{- end }}
{{- end }}
return nil
}
{{ with extend $ "Receiver" $receiver "Builder" $builder }}
{{ $tmpl := printf "dialect/%s/create" $.Storage }}
{{ xtemplate $tmpl . }}
{{ end }}
{{- /* Support adding create methods by global templates. */}}
{{- with $tmpls := matchTemplate "create/additional/*" }}
{{- range $tmpl := $tmpls }}
{{ xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{ $bulk := $.CreateBulkName }}
{{ $receiver = $.CreateBulReceiver }}
// {{ $bulk }} is the builder for creating many {{ $.Name }} entities in bulk.
type {{ $bulk }} struct {
config
err error
builders []*{{ $builder }}
{{- /* Additional fields to add to the builder. */}}
{{- $tmpl = printf "dialect/%s/create_bulk/fields" $.Storage }}
{{- if hasTemplate $tmpl }}
{{- xtemplate $tmpl . }}
{{- end }}
}
{{/* If the storage driver supports bulk creation */}}
{{ $tmpl = printf "dialect/%s/create_bulk" $.Storage }}
{{ if hasTemplate $tmpl }}
{{ with extend $ "Receiver" $receiver "Builder" $bulk }}
{{ xtemplate $tmpl . }}
{{ end }}
{{ end }}
{{ end }}

View File

@@ -0,0 +1,97 @@
{{/*
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 "delete" }}
{{ $pkg := base $.Config.Package }}
{{ template "header" $ }}
{{ template "import" $ }}
import (
{{ $.PackageAlias }} "{{ $.Config.Package }}/{{ $.PackageDir }}"
)
{{ $builder := $.DeleteName }}
{{ $receiver := $.DeleteReceiver }}
{{ $mutation := print $receiver ".mutation" }}
// {{ $builder }} is the builder for deleting a {{ $.Name }} entity.
type {{ $builder }} struct {
config
hooks []Hook
mutation *{{ $.MutationName }}
}
// Where appends a list predicates to the {{ $builder }} builder.
func ({{ $receiver }} *{{ $builder }}) Where(ps ...predicate.{{ $.Name }}) *{{ $builder }} {
{{ $mutation }}.Where(ps...)
return {{ $receiver }}
}
// Exec executes the deletion query and returns how many vertices were deleted.
func ({{ $receiver }} *{{ $builder }}) Exec(ctx context.Context) (int, error) {
return withHooks(ctx, {{ $receiver }}.{{ $.Storage }}Exec, {{ $mutation }}, {{ $receiver }}.hooks)
}
// ExecX is like Exec, but panics if an error occurs.
func ({{ $receiver }} *{{ $builder }}) ExecX(ctx context.Context) int {
n, err := {{ $receiver }}.Exec(ctx)
if err != nil {
panic(err)
}
return n
}
{{ with extend $ "Receiver" $receiver "Builder" $builder }}
{{ $tmpl := printf "dialect/%s/delete" $.Storage }}
{{ xtemplate $tmpl . }}
{{ end }}
{{- /* Support adding delete methods by global templates. */}}
{{- with $tmpls := matchTemplate "delete/additional/*" }}
{{- range $tmpl := $tmpls }}
{{ xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{ $onebuilder := $.DeleteOneName }}
{{ $oneReceiver := $.DeleteOneReceiver }}
// {{ $onebuilder }} is the builder for deleting a single {{ $.Name }} entity.
type {{ $onebuilder }} struct {
{{ $receiver }} *{{ $builder }}
}
// Where appends a list predicates to the {{ $builder }} builder.
func ({{ $oneReceiver }} *{{ $onebuilder }}) Where(ps ...predicate.{{ $.Name }}) *{{ $onebuilder }} {
{{ $oneReceiver }}.{{ $mutation }}.Where(ps...)
return {{ $oneReceiver }}
}
// Exec executes the deletion query.
func ({{ $oneReceiver }} *{{ $onebuilder }}) Exec(ctx context.Context) error {
n, err := {{ $oneReceiver }}.{{ $receiver }}.Exec(ctx)
switch {
case err != nil:
return err
case n == 0:
return &NotFoundError{ {{ $.Package }}.Label}
default:
return nil
}
}
// ExecX is like Exec, but panics if an error occurs.
func ({{ $oneReceiver }} *{{ $onebuilder }}) ExecX(ctx context.Context) {
if err := {{ $oneReceiver }}.Exec(ctx); err != nil {
panic(err)
}
}
{{ 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 */}}
{{ define "entql" }}
{{ $tmpl := printf "dialect/%s/entql" $.Storage }}
{{ if hasTemplate $tmpl }}
{{ xtemplate $tmpl . }}
{{ end }}
{{ end }}

View File

@@ -0,0 +1,213 @@
{{/*
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 "mutation_graph" }}
{{ $pkg := base $.Config.Package }}
{{ template "header" $ }}
import (
"context"
"errors"
"fmt"
"sync"
{{- range $n := $.Nodes }}
{{ $n.PackageAlias }} "{{ $.Config.Package }}/{{ $n.PackageDir }}"
{{- template "import/types" $n }}
{{- end }}
"entgo.io/ent"
"entgo.io/ent/schema/field"
)
const (
// Operation types.
OpCreate = ent.OpCreate
OpDelete = ent.OpDelete
OpDeleteOne = ent.OpDeleteOne
OpUpdate = ent.OpUpdate
OpUpdateOne = ent.OpUpdateOne
// Node types.
{{- range $n := $.Nodes }}
{{ $n.TypeName }} = "{{ $n.Name }}"
{{- end }}
)
{{ range $n := $.MutableNodes }}
{{ $mutation := $n.MutationName }}
{{ $baseMutation := print $n.Package ".Mutation" }}
// {{ $mutation }} represents an operation that mutates the {{ $n.Name }} nodes in the graph.
type {{ $mutation }} struct {
{{ $baseMutation }}
config
{{- with $n.HasOneFieldID }}
{{ $n.ID.BuilderField }} *{{ $n.ID.Type }}
{{- end }}
done bool
oldValue func(context.Context) (*{{ $n.Name }}, error)
}
var _ ent.Mutation = (*{{ $mutation }})(nil)
{{ $mutationOption := print (camel $n.Name) "Option" }}
// {{ $mutationOption }} allows management of the mutation configuration using functional options.
type {{ $mutationOption }} func(*{{ $mutation }})
// new{{ $mutation }} creates new mutation for the {{ $n.Name }} entity.
func new{{ $mutation }}(c config, op Op, opts ...{{ $mutationOption }}) *{{ $mutation }} {
m := &{{ $mutation }}{
Mutation: *{{ $n.Package }}.NewMutation(op),
config: c,
}
for _, opt := range opts {
opt(m)
}
return m
}
{{ with $n.HasOneFieldID }}
{{ if $n.ID.UserDefined }}
// SetID sets the value of the id field. Note that this
// operation is only accepted on creation of {{ $n.Name }} entities.
func (m *{{ $mutation }}) SetID(id {{ $n.ID.Type }}) {
m.{{ $n.ID.BuilderField }} = &id
}
{{ end }}
// ID returns the ID value in the mutation. Note that the ID is only available
// if it was provided to the builder or after it was returned from the database.
func (m *{{ $mutation }}) ID() (id {{ $n.ID.Type }}, exists bool) {
if m.{{ $n.ID.BuilderField }} == nil {
return
}
return *m.{{ $n.ID.BuilderField }}, true
}
{{ $opt := print "with" $n.Name "ID" }}
// {{ $opt }} sets the ID field of the mutation.
func {{ $opt }}(id {{ $n.ID.Type }}) {{ $mutationOption }} {
return func(m *{{ $mutation }}) {
var (
err error
once sync.Once
value *{{ $n.Name }}
)
m.oldValue = func(ctx context.Context) (*{{ $n.Name }}, error) {
once.Do(func() {
if m.done {
err = errors.New("querying old values post mutation is not allowed")
} else {
value, err = m.Client().{{ $n.Name }}.Get(ctx, id)
}
})
return value, err
}
m.{{ $n.ID.BuilderField }} = &id
}
}
{{ $opt = print "with" $n.Name }}
// {{ $opt }} sets the old {{ $n.Name }} of the mutation.
func {{ $opt }}(node *{{ $n.Name }}) {{ $mutationOption }} {
return func(m *{{ $mutation }}) {
m.oldValue = func(context.Context) (*{{ $n.Name }}, error) {
return node, nil
}
m.{{ $n.ID.BuilderField }} = &node.ID
}
}
{{ end }}
// Client returns a new `ent.Client` from the mutation. If the mutation was
// executed in a transaction (ent.Tx), a transactional client is returned.
func (m {{ $mutation }}) Client() *Client {
client := &Client{config: m.config}
client.init()
return client
}
// Tx returns an `ent.Tx` for mutations that were executed in transactions;
// it returns an error otherwise.
func (m {{ $mutation }}) Tx() (*Tx, error) {
if _, ok := m.driver.(*txDriver); !ok {
return nil, errors.New("{{ $pkg }}: mutation is not running in a transaction")
}
tx := &Tx{config: m.config}
tx.init()
return tx, nil
}
{{ with $n.HasOneFieldID }}
// IDs queries the database and returns the entity ids that match the mutation's predicate.
// That means, if the mutation is applied within a transaction with an isolation level such
// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated
// or updated by the mutation.
func (m *{{ $mutation }}) IDs(ctx context.Context) ([]{{ $n.ID.Type }}, error) {
switch {
case m.Op().Is(OpUpdateOne | OpDeleteOne):
id, exists := m.ID()
if exists {
return []{{ $n.ID.Type }}{id}, nil
}
fallthrough
case m.Op().Is(OpUpdate | OpDelete):
return m.Client().{{ $n.Name }}.Query().Where(m.Predicates()...).IDs(ctx)
default:
return nil, fmt.Errorf("IDs is not allowed on %s operations", m.Op())
}
}
{{ end }}
{{ range $f := $n.Fields }}
{{- if $f.IsBlobLazy }}{{ continue }}{{ end }}
{{ if $n.HasOneFieldID }}
{{ $const := print $n.Package "." $f.Constant }}
// {{ $f.MutationGetOld }} returns the old "{{ $f.Name }}" field's value of the {{ $n.Name }} entity.
// If the {{ $n.Name }} object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *{{ $mutation }}) {{ $f.MutationGetOld }}(ctx context.Context) (v {{ if $f.NillableValue }}*{{ end }}{{ $f.Type }}, err error) {
if !m.Op().Is(OpUpdateOne) {
return v, errors.New("{{ $f.MutationGetOld }} is only allowed on UpdateOne operations")
}
if _, exists := m.ID(); !exists || m.oldValue == nil {
return v, errors.New("{{ $f.MutationGetOld }} requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for {{ $f.MutationGetOld }}: %w", err)
}
return oldValue.{{ $f.StructField }}, nil
}
{{ end }}
{{ end }}
// OldField returns the old value of the field from the database. An error is
// returned if the mutation operation is not UpdateOne, or the query to the
// database failed.
func (m *{{ $mutation }}) OldField(ctx context.Context, name string) (ent.Value, error) {
{{- if $n.HasCompositeID }}
return nil, errors.New("edge schema {{ $n.Name }} does not support getting old values")
{{- else }}
{{- with $n.Fields }}
switch name {
{{- range $f := . }}
{{- if $f.IsBlobLazy }}{{ continue }}{{ end }}
{{- $const := print $n.Package "." $f.Constant }}
case {{ $const }}:
return m.{{ $f.MutationGetOld }}(ctx)
{{- end }}
}
{{- end }}
return nil, fmt.Errorf("unknown {{ $n.Name }} field %s", name)
{{- end }}
}
{{ end }}
{{ end }}

View File

@@ -0,0 +1,500 @@
{{/*
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 "query" }}
{{ $pkg := base $.Config.Package }}
{{ template "header" $ }}
{{ with extend $ "Imports" $.SiblingImports }}
{{ template "import" . }}
{{ end }}
{{ $builder := $.QueryName }}
{{ $receiver := $.QueryReceiver }}
// {{ $builder }} is the builder for querying {{ $.Name }} entities.
type {{ $builder }} struct {
config
ctx *QueryContext
order []{{ $.Package }}.OrderOption
inters []Interceptor
predicates []predicate.{{ $.Name }}
{{- /* Eager loading fields. */}}
{{- range $e := $.Edges }}
{{ $e.EagerLoadField }} *{{ $e.Type.QueryName }}
{{- end }}
{{- /* Additional fields to add to the builder. */}}
{{- $tmpl := printf "dialect/%s/query/fields" $.Storage }}
{{- if hasTemplate $tmpl }}
{{- xtemplate $tmpl . }}
{{- end }}
// intermediate query (i.e. traversal path).
{{ $.Storage }} {{ $.Storage.Builder }}
path func(context.Context) ({{ $.Storage.Builder }}, error)
}
// Where adds a new predicate for the {{ $builder }} builder.
func ({{ $receiver }} *{{ $builder }}) Where(ps ...predicate.{{ $.Name }}) *{{ $builder }} {
{{ $receiver}}.predicates = append({{ $receiver }}.predicates, ps...)
return {{ $receiver }}
}
// Limit the number of records to be returned by this query.
func ({{ $receiver }} *{{ $builder }}) Limit(limit int) *{{ $builder }} {
{{ $receiver }}.ctx.Limit = &limit
return {{ $receiver }}
}
// Offset to start from.
func ({{ $receiver }} *{{ $builder }}) Offset(offset int) *{{ $builder }} {
{{ $receiver }}.ctx.Offset = &offset
return {{ $receiver }}
}
// Unique configures the query builder to filter duplicate records on query.
// By default, unique is set to true, and can be disabled using this method.
func ({{ $receiver }} *{{ $builder }}) Unique(unique bool) *{{ $builder }} {
{{ $receiver }}.ctx.Unique = &unique
return {{ $receiver }}
}
// Order specifies how the records should be ordered.
func ({{ $receiver }} *{{ $builder }}) Order(o ...{{ $.Package }}.OrderOption) *{{ $builder }} {
{{ $receiver }}.order = append({{ $receiver }}.order, o...)
return {{ $receiver }}
}
{{/* this code has similarity with edge queries in client.tmpl */}}
{{ range $e := $.Edges }}
{{ $edge_builder := print $e.Type.QueryName }}
// Query{{ pascal $e.Name }} chains the current query on the "{{ $e.Name }}" edge.
func ({{ $receiver }} *{{ $builder }}) Query{{ pascal $e.Name }}() *{{ $edge_builder }} {
query := (&{{ $e.Type.ClientName }}{config: {{ $receiver }}.config}).Query()
query.path = func(ctx context.Context) (fromU {{ $.Storage.Builder }}, err error) {
if err := {{ $receiver }}.prepareQuery(ctx); err != nil {
return nil, err
}
{{- with extend $ "Receiver" $receiver "Edge" $e "Ident" "fromU" -}}
{{ $tmpl := printf "dialect/%s/query/path" $.Storage }}
{{- xtemplate $tmpl . }}
{{- end -}}
return fromU, nil
}
return query
}
{{ end }}
// First returns the first {{ $.Name }} entity from the query.
// Returns a *NotFoundError when no {{ $.Name }} was found.
func ({{ $receiver }} *{{ $builder }}) First(ctx context.Context) (*{{ $.Name }}, error) {
nodes, err := {{ $receiver }}.Limit(1).All(setContextOp(ctx, {{ $receiver }}.ctx, ent.OpQueryFirst))
if err != nil {
return nil, err
}
if len(nodes) == 0 {
return nil, &NotFoundError{ {{ $.Package }}.Label}
}
return nodes[0], nil
}
// FirstX is like First, but panics if an error occurs.
func ({{ $receiver }} *{{ $builder }}) FirstX(ctx context.Context) *{{ $.Name }} {
node, err := {{ $receiver }}.First(ctx)
if err != nil && !IsNotFound(err) {
panic(err)
}
return node
}
{{ if $.HasOneFieldID }}
// FirstID returns the first {{ $.Name }} ID from the query.
// Returns a *NotFoundError when no {{ $.Name }} ID was found.
func ({{ $receiver }} *{{ $builder }}) FirstID(ctx context.Context) (id {{ $.ID.Type }}, err error) {
var ids []{{ $.ID.Type }}
if ids, err = {{ $receiver }}.Limit(1).IDs(setContextOp(ctx, {{ $receiver }}.ctx, ent.OpQueryFirstID)); err != nil {
return
}
if len(ids) == 0 {
err = &NotFoundError{ {{ $.Package }}.Label}
return
}
return ids[0], nil
}
// FirstIDX is like FirstID, but panics if an error occurs.
func ({{ $receiver }} *{{ $builder }}) FirstIDX(ctx context.Context) {{ $.ID.Type }} {
id, err := {{ $receiver }}.FirstID(ctx)
if err != nil && !IsNotFound(err) {
panic(err)
}
return id
}
{{ end }}
// Only returns a single {{ $.Name }} entity found by the query, ensuring it only returns one.
// Returns a *NotSingularError when more than one {{ $.Name }} entity is found.
// Returns a *NotFoundError when no {{ $.Name }} entities are found.
func ({{ $receiver }} *{{ $builder }}) Only(ctx context.Context) (*{{ $.Name }}, error) {
nodes, err := {{ $receiver }}.Limit(2).All(setContextOp(ctx, {{ $receiver }}.ctx, ent.OpQueryOnly))
if err != nil {
return nil, err
}
switch len(nodes) {
case 1:
return nodes[0], nil
case 0:
return nil, &NotFoundError{ {{ $.Package }}.Label}
default:
return nil, &NotSingularError{ {{ $.Package }}.Label}
}
}
// OnlyX is like Only, but panics if an error occurs.
func ({{ $receiver }} *{{ $builder }}) OnlyX(ctx context.Context) *{{ $.Name }} {
node, err := {{ $receiver }}.Only(ctx)
if err != nil {
panic(err)
}
return node
}
{{ if $.HasOneFieldID }}
// OnlyID is like Only, but returns the only {{ $.Name }} ID in the query.
// Returns a *NotSingularError when more than one {{ $.Name }} ID is found.
// Returns a *NotFoundError when no entities are found.
func ({{ $receiver }} *{{ $builder }}) OnlyID(ctx context.Context) (id {{ $.ID.Type }}, err error) {
var ids []{{ $.ID.Type }}
if ids, err = {{ $receiver }}.Limit(2).IDs(setContextOp(ctx, {{ $receiver }}.ctx, ent.OpQueryOnlyID)); err != nil {
return
}
switch len(ids) {
case 1:
id = ids[0]
case 0:
err = &NotFoundError{ {{ $.Package }}.Label}
default:
err = &NotSingularError{ {{ $.Package }}.Label}
}
return
}
// OnlyIDX is like OnlyID, but panics if an error occurs.
func ({{ $receiver }} *{{ $builder }}) OnlyIDX(ctx context.Context) {{ $.ID.Type }} {
id, err := {{ $receiver }}.OnlyID(ctx)
if err != nil {
panic(err)
}
return id
}
{{ end }}
// All executes the query and returns a list of {{ plural $.Name }}.
func ({{ $receiver }} *{{ $builder }}) All(ctx context.Context) ([]*{{ $.Name }}, error) {
ctx = setContextOp(ctx, {{ $receiver }}.ctx, ent.OpQueryAll)
if err := {{ $receiver }}.prepareQuery(ctx); err != nil {
return nil, err
}
qr := querierAll[[]*{{ $.Name }}, *{{ $builder }}]()
return withInterceptors[[]*{{ $.Name }}](ctx, {{ $receiver }}, qr, {{ $receiver }}.inters)
}
// AllX is like All, but panics if an error occurs.
func ({{ $receiver }} *{{ $builder }}) AllX(ctx context.Context) []*{{ $.Name }} {
nodes, err := {{ $receiver }}.All(ctx)
if err != nil {
panic(err)
}
return nodes
}
{{ if $.HasOneFieldID }}
// IDs executes the query and returns a list of {{ $.Name }} IDs.
func ({{ $receiver }} *{{ $builder }}) IDs(ctx context.Context) (ids []{{ $.ID.Type }}, err error) {
{{- /* Since a graph traversal such as JOINs can return duplicate IDs, set the Unique modifier unless specified otherwise. */}}
if {{ $receiver }}.ctx.Unique == nil && {{ $receiver }}.path != nil {
{{ $receiver }}.Unique(true)
}
ctx = setContextOp(ctx, {{ $receiver }}.ctx, ent.OpQueryIDs)
{{- if and $.ID.HasValueScanner (eq $.Storage.Name "sql") }}
var nodes []*{{ $.Name }}
if nodes, err = {{ $receiver }}.Select({{ $.Package }}.FieldID).All(ctx); err != nil {
return nil, err
}
ids = make([]{{ $.ID.Type }}, len(nodes))
for i := range nodes {
ids[i] = nodes[i].ID
}
{{- else }}
if err = {{ $receiver }}.Select({{ $.Package }}.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
{{- end }}
return ids, nil
}
// IDsX is like IDs, but panics if an error occurs.
func ({{ $receiver }} *{{ $builder }}) IDsX(ctx context.Context) []{{ $.ID.Type }} {
ids, err := {{ $receiver }}.IDs(ctx)
if err != nil {
panic(err)
}
return ids
}
{{ end }}
// Count returns the count of the given query.
func ({{ $receiver }} *{{ $builder }}) Count(ctx context.Context) (int, error) {
ctx = setContextOp(ctx, {{ $receiver }}.ctx, ent.OpQueryCount)
if err := {{ $receiver }}.prepareQuery(ctx); err != nil {
return 0, err
}
return withInterceptors[int](ctx, {{ $receiver }}, querierCount[*{{ $builder }}](), {{ $receiver }}.inters)
}
// CountX is like Count, but panics if an error occurs.
func ({{ $receiver }} *{{ $builder }}) CountX(ctx context.Context) int {
count, err := {{ $receiver }}.Count(ctx)
if err != nil {
panic(err)
}
return count
}
// Exist returns true if the query has elements in the graph.
func ({{ $receiver }} *{{ $builder }}) Exist(ctx context.Context) (bool, error) {
ctx = setContextOp(ctx, {{ $receiver }}.ctx, ent.OpQueryExist)
switch _, err := {{ $receiver }}.First{{ if $.HasOneFieldID }}ID{{ end }}(ctx);{
case IsNotFound(err):
return false, nil
case err != nil:
return false, fmt.Errorf("{{ $pkg }}: check existence: %w", err)
default:
return true, nil
}
}
// ExistX is like Exist, but panics if an error occurs.
func ({{ $receiver }} *{{ $builder }}) ExistX(ctx context.Context) bool {
exist, err := {{ $receiver }}.Exist(ctx)
if err != nil {
panic(err)
}
return exist
}
// Clone returns a duplicate of the {{ $builder }} builder, including all associated steps. It can be
// used to prepare common query builders and use them differently after the clone is made.
func ({{ $receiver }} *{{ $builder }}) Clone() *{{ $builder }} {
if {{ $receiver }} == nil {
return nil
}
return &{{ $builder }}{
config: {{ $receiver }}.config,
ctx: {{ $receiver }}.ctx.Clone(),
order: append([]{{ $.Package }}.OrderOption{}, {{ $receiver }}.order...),
inters: append([]Interceptor{}, {{ $receiver }}.inters...),
predicates: append([]predicate.{{ $.Name }}{}, {{ $receiver }}.predicates...),
{{- range $e := $.Edges }}
{{ $e.EagerLoadField }}: {{ $receiver }}.{{ $e.EagerLoadField }}.Clone(),
{{- end }}
// clone intermediate query.
{{ $.Storage }}: {{ $receiver }}.{{ $.Storage }}.Clone(),
path: {{ $receiver }}.path,
{{- if $.FeatureEnabled "sql/modifier" }}
modifiers: append([]func(*sql.Selector){}, {{ $receiver }}.modifiers...),
{{- end }}
}
}
{{- range $e := $.Edges }}
{{ $ebuilder := $e.Type.QueryName }}
{{ $func := print "With" $e.StructField }}
// {{ $func }} tells the query-builder to eager-load the nodes that are connected to
// the "{{ $e.Name }}" edge. The optional arguments are used to configure the query builder of the edge.
func ({{ $receiver }} *{{ $builder }}) {{ $func }}(opts ...func(*{{ $ebuilder }})) *{{ $builder }} {
query := (&{{ $e.Type.ClientName }}{config: {{ $receiver }}.config}).Query()
for _, opt := range opts {
opt(query)
}
{{ $receiver }}.{{ $e.EagerLoadField }} = query
return {{ $receiver }}
}
{{- end }}
{{ $groupBuilder := pascal $.Name | printf "%sGroupBy" }}
// GroupBy is used to group vertices by one or more fields/columns.
// It is often used with aggregate functions, like: {{ join (keys aggregate) ", " }}.
{{- with len $.Fields }}
{{- $f := index $.Fields 0 }}
//
// Example:
//
// var v []struct {
// {{ $f.StructField }} {{ $f.Type }} `{{ $f.StructTag }}`
// Count int `json:"count,omitempty"`
// }
//
// client.{{ pascal $.Name }}.Query().
// GroupBy({{ $.Package }}.{{ $f.Constant }}).
// Aggregate({{ $pkg }}.Count()).
// Scan(ctx, &v)
//
{{- end }}
func ({{ $receiver }} *{{ $builder }}) GroupBy(field string, fields ...string) *{{ $groupBuilder }} {
{{ $receiver }}.ctx.Fields = append([]string{field}, fields...)
grbuild := &{{ $groupBuilder }}{build: {{ $receiver }}}
grbuild.flds = &{{ $receiver }}.ctx.Fields
grbuild.label = {{ $.Package }}.Label
grbuild.scan = grbuild.Scan
return grbuild
}
{{ $selectBuilder := pascal $.Name | printf "%sSelect" }}
// Select allows the selection one or more fields/columns for the given query,
// instead of selecting all fields in the entity.
{{- with len $.Fields }}
{{- $f := index $.Fields 0 }}
//
// Example:
//
// var v []struct {
// {{ $f.StructField }} {{ $f.Type }} `{{ $f.StructTag }}`
// }
//
// client.{{ pascal $.Name }}.Query().
// Select({{ $.Package }}.{{ $f.Constant }}).
// Scan(ctx, &v)
//
{{- end }}
func ({{ $receiver }} *{{ $builder }}) Select(fields ...string) *{{ $selectBuilder }} {
{{ $receiver }}.ctx.Fields = append({{ $receiver }}.ctx.Fields, fields...)
sbuild := &{{ $selectBuilder }}{ {{ $builder }}: {{ $receiver }} }
sbuild.label = {{ $.Package }}.Label
sbuild.flds, sbuild.scan = &{{ $receiver }}.ctx.Fields, sbuild.Scan
return sbuild
}
// Aggregate returns a {{ $selectBuilder }} configured with the given aggregations.
func ({{ $receiver }} *{{ $builder }}) Aggregate(fns ...AggregateFunc) *{{ $selectBuilder }} {
return {{ $receiver }}.Select().Aggregate(fns...)
}
func ({{ $receiver }} *{{ $builder }}) prepareQuery(ctx context.Context) error {
for _, inter := range {{ $receiver }}.inters {
if inter == nil {
return fmt.Errorf("{{ $pkg }}: uninitialized interceptor (forgotten import {{ $pkg }}/runtime?)")
}
if trv, ok := inter.(Traverser); ok {
if err := trv.Traverse(ctx, {{ $receiver }}); err != nil {
return err
}
}
}
{{- /* Optional prepare checks per dialect. */}}
{{- $tmpl = printf "dialect/%s/query/preparecheck" $.Storage }}
{{- if hasTemplate $tmpl }}
{{- with extend $ "Receiver" $receiver "Package" $pkg }}
{{- xtemplate $tmpl . }}
{{- end }}
{{- end }}
if {{ $receiver }}.path != nil {
prev, err := {{ $receiver }}.path(ctx)
if err != nil {
return err
}
{{ $receiver }}.{{ $.Storage }} = prev
}
{{- if $.NumPolicy }}
if {{ $.Package }}.Policy == nil {
return errors.New("{{ $pkg }}: uninitialized {{ $.Package }}.Policy (forgotten import {{ $pkg }}/runtime?)")
}
if err := {{ $.Package }}.Policy.EvalQuery(ctx, {{ $receiver }}); err != nil {
return err
}
{{- end }}
return nil
}
{{ with extend $ "Receiver" $receiver "Builder" $builder "Package" $pkg }}
{{ $tmpl := printf "dialect/%s/query" $.Storage }}
{{ xtemplate $tmpl . }}
{{ end }}
{{- /* Support adding query methods by global templates. In order to generate dialect-specific methods,
prefix this template with "dialect/{{ .Storage }}". For example: "dialect/sql/query/additional/*". */}}
{{- with $tmpls := matchTemplate "query/additional/*" }}
{{- range $tmpl := $tmpls }}
{{ xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{/* groupby builder */}}
{{ $groupReceiver := $.GroupReceiver }}
// {{ $groupBuilder }} is the group-by builder for {{ $.Name }} entities.
type {{ $groupBuilder }} struct {
selector
build *{{ $builder }}
}
// Aggregate adds the given aggregation functions to the group-by query.
func ({{ $groupReceiver }} *{{ $groupBuilder }}) Aggregate(fns ...AggregateFunc) *{{ $groupBuilder }} {
{{ $groupReceiver }}.fns = append({{ $groupReceiver }}.fns, fns...)
return {{ $groupReceiver }}
}
// Scan applies the selector query and scans the result into the given value.
func ({{ $groupReceiver }} *{{ $groupBuilder }}) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, {{ $groupReceiver }}.build.ctx, ent.OpQueryGroupBy)
if err := {{ $groupReceiver }}.build.prepareQuery(ctx); err != nil {
return err
}
return scanWithInterceptors[*{{ $builder }}, *{{ $groupBuilder }}](ctx, {{ $groupReceiver }}.build, {{ $groupReceiver }}, {{ $groupReceiver }}.build.inters, v)
}
{{ with extend $ "Receiver" $groupReceiver "Builder" $groupBuilder }}
{{ $tmpl := printf "dialect/%s/group" $.Storage }}
{{ xtemplate $tmpl . }}
{{ end }}
{{/* select builder */}}
{{ $selectReceiver := $.SelectReceiver }}
// {{ $selectBuilder }} is the builder for selecting fields of {{ pascal $.Name }} entities.
type {{ $selectBuilder }} struct {
*{{ $builder }}
selector
}
// Aggregate adds the given aggregation functions to the selector query.
func ({{ $selectReceiver }} *{{ $selectBuilder }}) Aggregate(fns ...AggregateFunc) *{{ $selectBuilder }} {
{{ $selectReceiver }}.fns = append({{ $selectReceiver }}.fns, fns...)
return {{ $selectReceiver }}
}
// Scan applies the selector query and scans the result into the given value.
func ({{ $selectReceiver }} *{{ $selectBuilder }}) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, {{ $selectReceiver }}.ctx, ent.OpQuerySelect)
if err := {{ $selectReceiver }}.prepareQuery(ctx); err != nil {
return err
}
return scanWithInterceptors[*{{ $builder }}, *{{ $selectBuilder }}](ctx, {{ $selectReceiver }}.{{ $.QueryName }}, {{ $selectReceiver }}, {{ $selectReceiver }}.inters, v)
}
{{ with extend $ "Receiver" $selectReceiver "Builder" $selectBuilder }}
{{ $tmpl := printf "dialect/%s/select" $.Storage }}
{{ xtemplate $tmpl . }}
{{ end }}
{{ end }}

View File

@@ -0,0 +1,150 @@
{{/*
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 "setter" }}
{{ $builder := pascal $.Scope.Builder }}
{{ $receiver := $.Scope.Receiver }}
{{ $fields := $.Fields }}
{{ $updater := false }}
{{ $creator := true }}
{{- if or (hasSuffix $builder "Update") (hasSuffix $builder "UpdateOne") }}
{{ $updater = true }}
{{ $creator = false }}
{{ $fields = $.MutableFields }}
{{- else if $.HasCompositeID }}
{{- else if $.ID.UserDefined }}
{{ $fields = append $fields $.ID }}
{{- end }}
{{ range $f := $fields }}
{{- if $f.IsBlobLazy }}{{ continue }}{{ end }}
{{- /* Skip all blob fields on multi-row Update (blob key updates require UpdateOne). */}}
{{- if and $f.IsBlob $updater (not (hasSuffix $builder "UpdateOne")) }}{{ continue }}{{ end }}
{{ $func := print "Set" $f.StructField }}
// {{ $func }} sets the "{{ $f.Name }}" field.
func ({{ $receiver }} *{{ $builder }}) {{ $func }}(v {{ $f.Type }}) *{{ $builder }} {
{{- /* setting numeric type override previous calls to Add. */}}
{{- if and $updater $f.SupportsMutationAdd }}
{{ $receiver }}.mutation.{{ $f.MutationReset }}()
{{- end }}
{{ $receiver }}.mutation.{{ $f.MutationSet }}(v)
return {{ $receiver }}
}
{{/* Avoid generating nillable setters for nillable types. */}}
{{ $nillableC := and $creator (or $f.Optional $f.Default) }}
{{ $nillableU := and $updater (not $f.UpdateDefault) }}
{{ $nillableFunc := print "SetNillable" $f.StructField }}
{{ $skipNillable := false }}{{ range $fields }}{{ if and (ne .Name $f.Name) (eq .MutationSet $nillableFunc) }}{{ $skipNillable = true }}{{ break }}{{ end }}{{ end }}
{{ if and (not $f.Type.Nillable) (not $skipNillable) (or $nillableC $nillableU) }}
// {{ $nillableFunc }} sets the "{{ $f.Name }}" field if the given value is not nil.
func ({{ $receiver }} *{{ $builder }}) {{ $nillableFunc }}(v *{{ $f.Type }}) *{{ $builder }} {
if v != nil {
{{ $receiver }}.{{ $func }}(*v)
}
return {{ $receiver }}
}
{{ end }}
{{ if and $updater $f.SupportsMutationAdd }}
// {{ $f.MutationAdd }} adds value to the "{{ $f.Name }}" field.
func ({{ $receiver }} *{{ $builder }}) {{ $f.MutationAdd }}(v {{ $f.SignedType }}) *{{ $builder }} {
{{ $receiver }}.mutation.{{ $f.MutationAdd }}(v)
return {{ $receiver }}
}
{{ end }}
{{ if and $updater $f.SupportsMutationAppend }}
// {{ $f.MutationAppend }} appends value to the "{{ $f.Name }}" field.
func ({{ $receiver }} *{{ $builder }}) {{ $f.MutationAppend }}(v {{ $f.Type }}) *{{ $builder }} {
{{ $receiver }}.mutation.{{ $f.MutationAppend }}(v)
return {{ $receiver }}
}
{{ end }}
{{ if and $f.Optional $updater }}
{{ $func := print "Clear" $f.StructField }}
// {{ $func }} clears the value of the "{{ $f.Name }}" field.
func ({{ $receiver }} *{{ $builder }}) {{ $func }}() *{{ $builder }} {
{{ $receiver }}.mutation.{{ $func }}()
return {{ $receiver }}
}
{{ end }}
{{ end }}
{{- /* Lazy blob setters only on Create and UpdateOne (blob writes require a single-row context). */}}
{{- $updateOne := hasSuffix $builder "UpdateOne" }}
{{- if or $creator $updateOne }}
{{- if hasTemplate (printf "dialect/%s/model/fields" $.Storage) }}
{{- range $f := $.BlobFields }}
{{- if not $f.IsBlobLazy }}{{ continue }}{{ end }}
{{ $func := print "Set" $f.StructField }}
// {{ $func }} sets the "{{ $f.Name }}" field.
func ({{ $receiver }} *{{ $builder }}) {{ $func }}(v io.Reader) *{{ $builder }} {
{{ $receiver }}.mutation.Set{{ $f.StructField }}(v)
return {{ $receiver }}
}
{{- if and $f.Optional $updateOne }}
{{ $clearFunc := print "Clear" $f.StructField }}
// {{ $clearFunc }} clears the value of the "{{ $f.Name }}" field.
func ({{ $receiver }} *{{ $builder }}) {{ $clearFunc }}() *{{ $builder }} {
{{ $receiver }}.mutation.{{ $clearFunc }}()
return {{ $receiver }}
}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{ range $e := $.EdgesWithID }}
{{ if and $updater $e.Immutable }}
{{/* Skip to the next one as immutable edges cannot be updated. */}}
{{continue}}
{{ end }}
{{ $op := "add" }}{{ $idsFunc := $e.MutationAdd }}{{ if $e.Unique }}{{ $op = "set" }}{{ $idsFunc = $e.MutationSet }}{{ end }}
{{/* Check if this setter was already defined by the field-setters (e.g. edge-field with the same name). */}}
{{ $withSetter := not $e.HasFieldSetter }}
{{ if $withSetter }}
// {{ $idsFunc }} {{ $op }}s the "{{ $e.Name }}" edge to the {{ $e.Type.Name }} entity by ID{{ if not $e.Unique }}s{{ end }}.
func ({{ $receiver }} *{{ $builder }}) {{ $idsFunc }}({{ if $e.Unique }}id{{ else }}ids ...{{ end }} {{ $e.Type.ID.Type }}) *{{ $builder }} {
{{ $receiver }}.mutation.{{ $idsFunc }}({{ if $e.Unique }}id{{ else }}ids ...{{ end }})
return {{ $receiver }}
}
{{ end }}
{{ if and $e.Unique $e.Optional $withSetter }}
{{ $nillableIDsFunc := print "SetNillable" $e.StructField "ID" }}
// {{ $nillableIDsFunc }} sets the "{{ $e.Name }}" edge to the {{ $e.Type.Name }} entity by ID if the given value is not nil.
func ({{ $receiver }} *{{ $builder }}) {{ $nillableIDsFunc }}(id *{{ $e.Type.ID.Type }}) *{{ $builder }} {
if id != nil {
{{ $receiver}} = {{ $receiver }}.{{ $idsFunc }}(*id)
}
return {{ $receiver }}
}
{{ end }}
{{ $func := print (pascal $op) $e.StructField }}
// {{ $func }} {{ $op }}s the "{{ $e.Name }}" edge{{if not $e.Unique}}s{{ end }} to the {{ $e.Type.Name }} entity.
func ({{ $receiver }} *{{ $builder }}) {{ $func }}(v {{ if not $e.Unique }}...{{ end }}*{{ $e.Type.Name}}) *{{ $builder }} {
{{ if $e.Unique -}}
return {{ $receiver }}.{{ $idsFunc }}(v.ID)
{{- else -}}
ids := make([]{{ $e.Type.ID.Type }}, len(v))
for i := range v {
ids[i] = v[i].ID
}
return {{ $receiver }}.{{ $idsFunc }}(ids...)
{{- end }}
}
{{ end }}
// Mutation returns the {{ $.MutationName }} object of the builder.
func ({{ $receiver }} *{{ $builder }}) Mutation() *{{ $.MutationName }} {
return {{ $receiver }}.mutation
}
{{ end }}

View File

@@ -0,0 +1,277 @@
{{/*
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 "update" }}
{{ $pkg := base $.Config.Package }}
{{ template "header" $ }}
{{ with extend $ "Imports" $.SiblingImports }}
{{ template "import" . }}
{{ end }}
{{ $builder := $.UpdateName }}
{{ $receiver := $.UpdateReceiver }}
{{ $mutation := print $receiver ".mutation" }}
{{ $runtimeRequired := or $.NumHooks $.NumPolicy }}
// {{ $builder }} is the builder for updating {{ $.Name }} entities.
type {{ $builder }} struct {
config
{{- template "update/fields" $ -}}
}
// Where appends a list predicates to the {{ $builder }} builder.
func ({{ $receiver}} *{{ $builder }}) Where(ps ...predicate.{{ $.Name }}) *{{ $builder }} {
{{ $mutation }}.Where(ps...)
return {{ $receiver }}
}
{{ with extend $ "Receiver" $receiver "Builder" $builder }}
{{ template "setter" . }}
{{ end }}
{{ with extend $ "Receiver" $receiver "Builder" $builder }}
{{ template "update/edges" . }}
{{ end }}
// Save executes the query and returns the number of nodes affected by the update operation.
func ({{ $receiver }} *{{ $builder }}) Save(ctx context.Context) (int, error) {
{{- if $.HasUpdateDefault }}
{{- if $runtimeRequired }}
if err := {{ $receiver }}.defaults(); err != nil {
return 0, err
}
{{- else }}
{{ $receiver }}.defaults()
{{- end }}
{{- end }}
return withHooks(ctx, {{ $receiver }}.{{ $.Storage }}Save, {{ $mutation }}, {{ $receiver }}.hooks)
}
// SaveX is like Save, but panics if an error occurs.
func ({{ $receiver }} *{{ $builder }}) SaveX(ctx context.Context) int {
affected, err := {{ $receiver }}.Save(ctx)
if err != nil {
panic(err)
}
return affected
}
// 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)
}
}
{{ with extend $ "Receiver" $receiver "Builder" $builder "Package" $pkg }}
{{ template "update/checks" . }}
{{ end }}
{{ with extend $ "Receiver" $receiver "Builder" $builder "Package" $pkg }}
{{ $tmpl := printf "dialect/%s/update" $.Storage }}
{{ xtemplate $tmpl . }}
{{ end }}
{{ $onebuilder := $.UpdateOneName }}
{{ $receiver = $.UpdateOneReceiver }}
{{ $mutation = print $receiver ".mutation" }}
// {{ $onebuilder }} is the builder for updating a single {{ $.Name }} entity.
type {{ $onebuilder }} struct {
config
fields []string
{{- template "update/fields" $ }}
}
{{ with extend $ "Receiver" $receiver "Builder" $onebuilder }}
{{ template "setter" . }}
{{ end }}
{{ with extend $ "Receiver" $receiver "Builder" $onebuilder }}
{{ template "update/edges" . }}
{{ end }}
// Where appends a list predicates to the {{ $builder }} builder.
func ({{ $receiver }} *{{ $onebuilder }}) Where(ps ...predicate.{{ $.Name }}) *{{ $onebuilder }} {
{{ $mutation }}.Where(ps...)
return {{ $receiver }}
}
// Select allows selecting one or more fields (columns) of the returned entity.
// The default is selecting all fields defined in the entity schema.
func ({{ $receiver }} *{{ $onebuilder }}) Select(field string, fields ...string) *{{ $onebuilder }} {
{{ $receiver }}.fields = append([]string{field}, fields...)
return {{ $receiver }}
}
// Save executes the query and returns the updated {{ $.Name }} entity.
func ({{ $receiver }} *{{ $onebuilder }} ) Save(ctx context.Context) (*{{ $.Name }}, error) {
{{- if $.HasUpdateDefault }}
{{- if $runtimeRequired }}
if err := {{ $receiver }}.defaults(); err != nil {
return nil, err
}
{{- else }}
{{ $receiver }}.defaults()
{{- end }}
{{- end }}
return withHooks(ctx, {{ $receiver }}.{{ $.Storage }}Save, {{ $mutation }}, {{ $receiver }}.hooks)
}
// SaveX is like Save, but panics if an error occurs.
func ({{ $receiver }} *{{ $onebuilder }}) SaveX(ctx context.Context) *{{ $.Name }} {
node, err := {{ $receiver }}.Save(ctx)
if err != nil {
panic(err)
}
return node
}
// Exec executes the query on the entity.
func ({{ $receiver }} *{{ $onebuilder }}) Exec(ctx context.Context) error {
_, err := {{ $receiver }}.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func ({{ $receiver }} *{{ $onebuilder }}) ExecX(ctx context.Context) {
if err := {{ $receiver }}.Exec(ctx); err != nil {
panic(err)
}
}
{{ with extend $ "Receiver" $receiver "Builder" $onebuilder "Package" $pkg }}
{{ template "update/checks" . }}
{{ end }}
{{ with extend $ "Receiver" $receiver "Builder" $onebuilder "Package" $pkg }}
{{ $tmpl := printf "dialect/%s/update" $.Storage }}
{{ xtemplate $tmpl . }}
{{ end }}
{{- /* Support adding update methods by global templates. */}}
{{- with $tmpls := matchTemplate "update/additional/*" }}
{{- range $tmpl := $tmpls }}
{{ xtemplate $tmpl $ }}
{{- end }}
{{- end }}
{{ end }}
{{/* shared struct fields between the two updaters */}}
{{ define "update/fields"}}
hooks []Hook
mutation *{{ $.MutationName }}
{{- /* Additional fields to add to the builder. */}}
{{- $tmpl := printf "dialect/%s/update/fields" $.Storage }}
{{- if hasTemplate $tmpl }}
{{- xtemplate $tmpl . }}
{{- end }}
{{ end }}
{{/* shared edges removal between the two updaters */}}
{{ define "update/edges" }}
{{ $builder := pascal .Scope.Builder }}
{{ $receiver := .Scope.Receiver }}
{{ $mutation := print $receiver ".mutation" }}
{{ range $e := $.EdgesWithID }}
{{ if $e.Immutable }}
{{/* Skip to the next one as immutable edges cannot be updated. */}}
{{continue}}
{{ end }}
{{ $func := $e.MutationClear }}
// {{ $func }} clears {{ if $e.Unique }}the "{{ $e.Name }}" edge{{ else }}all "{{ $e.Name }}" edges{{ end }} to the {{ $e.Type.Name }} entity.
func ({{ $receiver }} *{{ $builder }}) {{ $func }}() *{{ $builder }} {
{{ $mutation }}.{{ $func }}()
return {{ $receiver }}
}
{{ if not $e.Unique }}
{{ $idsFunc := print "Remove" (singular $e.Name | pascal) "IDs" }}
// {{ $idsFunc }} removes the "{{ $e.Name }}" edge to {{ $e.Type.Name }} entities by IDs.
func ({{ $receiver }} *{{ $builder }}) {{ $idsFunc }}(ids ...{{ $e.Type.ID.Type }}) *{{ $builder }} {
{{ $mutation }}.{{ $idsFunc }}(ids...)
return {{ $receiver }}
}
{{ $func := print "Remove" $e.StructField }}
// {{ $func }} removes "{{ $e.Name }}" edges to {{ $e.Type.Name }} entities.
func ({{ $receiver }} *{{ $builder }}) {{ $func }}(v ...*{{ $e.Type.Name }}) *{{ $builder }} {
ids := make([]{{ $e.Type.ID.Type }}, len(v))
for i := range v {
ids[i] = v[i].ID
}
return {{ $receiver }}.{{ $idsFunc }}(ids...)
}
{{ end }}
{{ end }}
{{ end }}
{{/* shared template for the 2 update builders */}}
{{ define "update/checks" }}
{{ $pkg := .Scope.Package }}
{{ $receiver := .Scope.Receiver }}
{{ $builder := pascal .Scope.Builder }}
{{ $mutation := print $receiver ".mutation" }}
{{ $runtimeRequired := or $.NumHooks $.NumPolicy }}
{{ if $.HasUpdateDefault }}
// defaults sets the default values of the builder before save.
func ({{ $receiver }} *{{ $builder }}) defaults() {{ if $runtimeRequired }}error{{ end }}{
{{- range $f := $.Fields }}
{{- if $f.UpdateDefault }}
if _, ok := {{ $mutation }}.{{ $f.MutationGet }}(); !ok {{ if $f.Optional }} && !{{ $mutation }}.{{ $f.StructField }}Cleared() {{ end }} {
{{- if $runtimeRequired }}
if {{ $.Package }}.{{ $f.UpdateDefaultName }} == nil {
return fmt.Errorf("{{ $pkg }}: uninitialized {{ $.Package }}.{{ $f.UpdateDefaultName }} (forgotten import {{ $pkg }}/runtime?)")
}
{{- end }}
v := {{ $.Package }}.{{ $f.UpdateDefaultName }}()
{{ $mutation }}.{{ $f.MutationSet }}(v)
}
{{- end }}
{{- end }}
{{- if $runtimeRequired }}
return nil
{{- end }}
}
{{ end }}
{{ if $.HasUpdateCheckers }}
// check runs all checks and user-defined validators on the builder.
func ({{ $receiver }} *{{ $builder }}) check() error {
{{- range $f := $.Fields }}
{{- $isValidator := and ($f.HasGoType) ($f.Type.Validator) }}
{{- with and (not $f.Immutable) (or $f.Validators $f.IsEnum $isValidator) }}
if v, ok := {{ $mutation }}.{{ $f.MutationGet }}(); ok {
if err := {{ if or $f.Validators $f.IsEnum }}{{ $.Package }}.{{ $f.Validator }}({{ $f.BasicType "v" }}){{ else }}v.Validate(){{ end }}; err != nil {
return &ValidationError{Name: "{{ $f.Name }}", err: fmt.Errorf(`{{ $pkg }}: validator failed for field "{{ $.Name }}.{{ $f.Name }}": %w`, err)}
}
}
{{- end }}
{{- end }}
{{- range $e := $.Edges }}
{{- if and $e.Unique (not $e.Optional) }}
if {{ $mutation }}.{{ $e.StructField }}Cleared() && len({{ $mutation }}.{{ $e.StructField }}IDs()) > 0 {
return errors.New(`{{ $pkg }}: clearing a required unique edge "{{ $.Name }}.{{ $e.Name }}"`)
}
{{- end }}
{{- end }}
return nil
}
{{ end }}
{{ end }}