entc: support schema/blob annotation

This commit is contained in:
Giau. Tran Minh
2026-05-03 18:00:38 +00:00
parent 665007afec
commit 7a21ec2e29
37 changed files with 1611 additions and 417 deletions

View File

@@ -10,6 +10,7 @@ in the LICENSE file in the root directory of this source tree.
{{ $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 {
@@ -76,6 +77,30 @@ func ({{ $receiver }} *{{ $builder }}) sqlSave(ctx context.Context) (*{{ $.Name
{{ $mutation }}.{{ $.ID.BuilderField }} = &_node.{{ $.ID.StructField }}
{{ $mutation }}.done = true
{{- end }}
{{- if $.HasBlobFields }}
{{- range $f := $.BlobFields }}
if data, ok := {{ $mutation }}.{{ $f.StructField }}(); ok {
b, err := {{ $mutation }}.blobOpeners.{{ $.Name }}(ctx, {{ $.Package }}.{{ $f.Constant }})
if err != nil {
return nil, fmt.Errorf("{{ $pkg }}: opening blob bucket for {{ $f.Name }}: %w", err)
}
key, err := _node.{{ $f.StructField }}Key(ctx)
if err != nil {
return nil, errors.Join(fmt.Errorf("{{ $pkg }}: blob key for {{ $f.Name }}: %w", err), b.Close())
}
w, err := b.NewWriter(ctx, key)
if err != nil {
return nil, errors.Join(fmt.Errorf("{{ $pkg }}: creating writer for {{ $f.Name }}: %w", err), b.Close())
}
if _, err := w.Write(data); err != nil {
return nil, errors.Join(fmt.Errorf("{{ $pkg }}: writing blob for {{ $f.Name }}: %w", err), w.Close(), b.Close())
}
if err := errors.Join(w.Close(), b.Close()); err != nil {
return nil, fmt.Errorf("{{ $pkg }}: closing blob for {{ $f.Name }}: %w", err)
}
}
{{- end }}
{{- end }}
return _node, nil
}
@@ -163,6 +188,7 @@ func ({{ $receiver }} *{{ $builder }}) createSpec() (*{{ $.Name }}, *sqlgraph.Cr
{{ 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) {
@@ -173,6 +199,20 @@ func ({{ $receiver }} *{{ $builder }}) Save(ctx context.Context) ([]*{{ $.Name }
specs := make([]*sqlgraph.CreateSpec, len({{ $receiver }}.builders))
nodes := make([]*{{ $.Name }}, len({{ $receiver }}.builders))
mutators := make([]Mutator, len({{ $receiver }}.builders))
{{- if $.HasBlobFields }}
{{- range $f := $.BlobFields }}
var _blob{{ $f.StructField }} Blob
{{- end }}
closeBlobs := func() error {
var errs []error
{{- range $f := $.BlobFields }}
if _blob{{ $f.StructField }} != nil {
errs = append(errs, _blob{{ $f.StructField }}.Close())
}
{{- end }}
return errors.Join(errs...)
}
{{- end }}
for i := range {{ $receiver }}.builders {
func(i int, root context.Context) {
builder := {{ $receiver }}.builders[i]
@@ -248,6 +288,29 @@ func ({{ $receiver }} *{{ $builder }}) Save(ctx context.Context) ([]*{{ $.Name }
{{- end }}
{{- end }}
mutation.done = true
{{- range $f := $.BlobFields }}
if data, ok := mutation.{{ $f.StructField }}(); ok {
if _blob{{ $f.StructField }} == nil {
if _blob{{ $f.StructField }}, err = mutation.blobOpeners.{{ $.Name }}(ctx, {{ $.Package }}.{{ $f.Constant }}); err != nil {
return nil, fmt.Errorf("{{ $pkg }}: opening blob bucket for {{ $f.Name }}: %w", err)
}
}
key, err := nodes[i].{{ $f.StructField }}Key(ctx)
if err != nil {
return nil, fmt.Errorf("{{ $pkg }}: blob key for {{ $f.Name }}: %w", err)
}
w, err := _blob{{ $f.StructField }}.NewWriter(ctx, key)
if err != nil {
return nil, fmt.Errorf("{{ $pkg }}: creating writer for {{ $f.Name }}: %w", err)
}
if _, err := w.Write(data); err != nil {
return nil, errors.Join(fmt.Errorf("{{ $pkg }}: writing blob for {{ $f.Name }}: %w", err), w.Close())
}
if err := w.Close(); err != nil {
return nil, fmt.Errorf("{{ $pkg }}: closing writer for {{ $f.Name }}: %w", err)
}
}
{{- end }}
return nodes[i], nil
})
for i := len(builder.hooks) - 1; i >= 0; i-- {
@@ -258,10 +321,18 @@ func ({{ $receiver }} *{{ $builder }}) Save(ctx context.Context) ([]*{{ $.Name }
}
if len(mutators) > 0 {
if _, err := mutators[0].Mutate(ctx, {{ $receiver }}.builders[0].mutation); err != nil {
{{- if $.HasBlobFields }}
return nil, errors.Join(err, closeBlobs())
{{- else }}
return nil, err
{{- end }}
}
}
{{- if $.HasBlobFields }}
return nodes, closeBlobs()
{{- else }}
return nodes, nil
{{- end }}
}
// SaveX is like Save, but panics if an error occurs.

View File

@@ -20,6 +20,9 @@ in the LICENSE file in the root directory of this source tree.
{{- if $f.HasValueScanner }}
{{- continue }}
{{- end }}
{{- if $f.IsBlob }}
{{- continue }}
{{- end }}
{{ $names := list }}
{{ if hasKey $ctypes $f.NewScanType }}
{{ $names = get $ctypes $f.NewScanType }}
@@ -42,6 +45,7 @@ func (*{{ $.Name }}) scanValues(columns []string) ([]any, error) {
values[i] = {{ $type }}
{{- end }}
{{- range $f := $.Fields }}
{{- if $f.IsBlob }}{{ continue }}{{ end }}
{{- if $f.HasValueScanner }}
case {{ $.Package }}.{{ $f.Constant }}:
values[i] = {{ $f.ScanValueFunc }}()
@@ -83,6 +87,9 @@ func ({{ $receiver }} *{{ $.Name }}) assignValues(columns []string, values []any
{{- end }}
{{- end }}
{{- range $f := $.Fields }}
{{- if $f.IsBlob }}
{{- continue }}
{{- end }}
case {{ $.Package }}.{{ $f.Constant }}:
{{- with extend $ "Idx" "i" "Field" $f "Rec" $receiver }}
{{ template "dialect/sql/decode/field" . }}

View File

@@ -53,7 +53,9 @@ var schemaGraph = func() *sqlgraph.Schema {
Type: "{{ $n.Name }}",
Fields: map[string]*sqlgraph.FieldSpec{
{{- range $f := $n.Fields }}
{{- if not $f.IsBlob }}
{{ $n.Package }}.{{ $f.Constant }}: {Type: field.{{ $f.Type.ConstName }}, Column: {{ $n.Package }}.{{ $f.Constant }}},
{{- end }}
{{- end }}
},
}
@@ -140,6 +142,7 @@ type predicateAdder interface {
{{- end }}
{{ range $f := $n.Fields }}
{{- if $f.IsBlob }}{{ continue }}{{ end }}
{{ $type := $f.Type.Type.String }}
{{ $iface := print (pascal $type) "P" }}
{{- if $f.IsTime }}{{ $iface = "TimeP" }}

View File

@@ -49,7 +49,7 @@ in the LICENSE file in the root directory of this source tree.
{{ $.ID.Constant }},
{{- end }}
{{- range $f := $.Fields }}
{{- if not $f.IsDeprecated }}
{{- if and (not $f.IsDeprecated) (not $f.IsBlob) }}
{{ $f.Constant }},
{{- end }}
{{- end }}

View File

@@ -187,6 +187,30 @@ func ({{ $receiver }} *{{ $builder }}) sqlSave(ctx context.Context) (_node {{ if
return {{ $zero }}, err
}
{{ $mutation }}.done = true
{{- if and $one $.HasBlobFields }}
{{- range $f := $.BlobFields }}
if data, ok := {{ $mutation }}.{{ $f.StructField }}(); ok {
b, err := {{ $mutation }}.blobOpeners.{{ $.Name }}(ctx, {{ $.Package }}.{{ $f.Constant }})
if err != nil {
return nil, fmt.Errorf("{{ $pkg }}: opening blob bucket for {{ $f.Name }}: %w", err)
}
key, err := _node.{{ $f.StructField }}Key(ctx)
if err != nil {
return nil, errors.Join(fmt.Errorf("{{ $pkg }}: blob key for {{ $f.Name }}: %w", err), b.Close())
}
w, err := b.NewWriter(ctx, key)
if err != nil {
return nil, errors.Join(fmt.Errorf("{{ $pkg }}: creating writer for {{ $f.Name }}: %w", err), b.Close())
}
if _, err := w.Write(data); err != nil {
return nil, errors.Join(fmt.Errorf("{{ $pkg }}: writing blob for {{ $f.Name }}: %w", err), w.Close(), b.Close())
}
if err := errors.Join(w.Close(), b.Close()); err != nil {
return nil, fmt.Errorf("{{ $pkg }}: closing blob for {{ $f.Name }}: %w", err)
}
}
{{- end }}
{{- end }}
return _node, nil
}
{{ end }}