snapshot of https://github.com/ent/ent.git (master, 2026-09-15; blobs > 131072B omitted)
This commit is contained in:
71
entc/gen/template/dialect/sql/feature/execquery.tmpl
Normal file
71
entc/gen/template/dialect/sql/feature/execquery.tmpl
Normal 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 }}
|
||||
46
entc/gen/template/dialect/sql/feature/lock.tmpl
Normal file
46
entc/gen/template/dialect/sql/feature/lock.tmpl
Normal 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 }}
|
||||
40
entc/gen/template/dialect/sql/feature/migratediff.tmpl
Normal file
40
entc/gen/template/dialect/sql/feature/migratediff.tmpl
Normal 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 }}
|
||||
92
entc/gen/template/dialect/sql/feature/modifier.tmpl
Normal file
92
entc/gen/template/dialect/sql/feature/modifier.tmpl
Normal 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 -}}
|
||||
121
entc/gen/template/dialect/sql/feature/namedges.tmpl
Normal file
121
entc/gen/template/dialect/sql/feature/namedges.tmpl
Normal 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 }}
|
||||
220
entc/gen/template/dialect/sql/feature/schemaconfig.tmpl
Normal file
220
entc/gen/template/dialect/sql/feature/schemaconfig.tmpl
Normal 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 }}
|
||||
493
entc/gen/template/dialect/sql/feature/upsert.tmpl
Normal file
493
entc/gen/template/dialect/sql/feature/upsert.tmpl
Normal 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 }}
|
||||
Reference in New Issue
Block a user