ent/field: add update_default option time field

Reviewed By: alexsn

Differential Revision: D17070907

fbshipit-source-id: 63c9ce75c58e524044c38f9461cb04e8e45c8017
This commit is contained in:
Ariel Mashraki
2019-08-27 06:53:44 -07:00
committed by Facebook Github Bot
parent bd07c86b60
commit 772b8a33f8
30 changed files with 376 additions and 100 deletions

File diff suppressed because one or more lines are too long

View File

@@ -26,9 +26,9 @@ type {{ $builder }} struct {
// Save creates the {{ $.Name }} in the database.
func ({{ $receiver }} *{{ $builder }}) Save(ctx context.Context) (*{{ $.Name }}, error) {
{{ range $_, $f := $.Fields -}}
{{- if or $f.HasDefault (not $f.Optional) -}}
{{- if or $f.Default (not $f.Optional) -}}
if {{ $receiver }}.{{ $f.StructField }} == nil {
{{ if $f.HasDefault -}}
{{ if $f.Default -}}
v := {{ $.Package }}.{{ $f.DefaultName }}{{ if $f.IsTime }}(){{ end }}
{{ $receiver }}.{{ $f.StructField }} = &v
{{ else -}}
@@ -38,7 +38,7 @@ func ({{ $receiver }} *{{ $builder }}) Save(ctx context.Context) (*{{ $.Name }},
{{ end -}}
{{ with $f.Validators -}}
{{/* add nullable check only for optional fields without default value */ -}}
{{ $nullable := and $f.Optional (not $f.HasDefault) -}}
{{ $nullable := and $f.Optional (not $f.Default) -}}
{{- if $nullable }} if {{ $receiver }}.{{ $f.StructField }} != nil { {{ end -}}
if err := {{ $.Package }}.{{ $f.Validator }}(*{{ $receiver }}.{{ $f.StructField }}); err != nil {
return nil, fmt.Errorf("{{ $pkg }}: validator failed for field \"{{ $f.Name }}\": %v", err)

View File

@@ -2,7 +2,9 @@
{{ $builder := pascal $.Scope.Builder }}
{{ $receiver := receiver $builder }}
{{ $fields := $.Fields }}
{{ $updater := false }}
{{- if or (hasSuffix $builder "Update") (hasSuffix $builder "UpdateOne") }}
{{ $updater := true }}
{{ $fields = $.MutableFields }}
{{- end }}
@@ -15,7 +17,7 @@
return {{ $receiver }}
}
{{/* avoid generting nillable setters for slices because the nil value for slice is valid */}}
{{ if and (not $f.Type.Slice) (or $f.Optional $f.Nillable $f.HasDefault) }}
{{ if and (not $f.Type.Slice) (or $f.Optional $f.Default) (not (and $updater $f.UpdateDefault)) }}
{{ $nillableFunc := print "SetNillable" (pascal $f.Name) }}
// {{ $nillableFunc }} sets the {{ $f.Name }} field if the given value is not nil.
func ({{ $receiver }} *{{ $builder }}) {{ $nillableFunc }}({{ $p }} *{{ $f.Type }}) *{{ $builder }} {

View File

@@ -33,7 +33,7 @@ func ({{ $receiver}} *{{ $builder }}) Where(ps ...predicate.{{ $.Name }}) *{{ $b
// Save executes the query and returns the number of rows/vertices matched by this operation.
func ({{ $receiver }} *{{ $builder }}) Save(ctx context.Context) (int, error) {
{{ with extend $ "Receiver" $receiver "Package" $pkg "ZeroValue" 0 -}}
{{ template "update/validators" . }}
{{ template "update/save" . }}
{{- end -}}
{{- if $multistorage -}}
switch {{ $receiver }}.driver.Dialect() {
@@ -100,7 +100,7 @@ type {{ $onebuilder }} struct {
// Save executes the query and returns the updated entity.
func ({{ $receiver }} *{{ $onebuilder }} ) Save(ctx context.Context) (*{{ $.Name }}, error) {
{{ with extend $ "Receiver" $receiver "Package" $pkg "ZeroValue" "nil" -}}
{{ template "update/validators" . }}
{{ template "update/save" . }}
{{- end -}}
{{- if $multistorage -}}
switch {{ $receiver }}.driver.Dialect() {
@@ -149,8 +149,10 @@ func ({{ $receiver }} *{{ $onebuilder }}) ExecX(ctx context.Context) {
{{/* shared struct fields between the two updaters */}}
{{ define "update/fields"}}
{{ range $_, $f := $.MutableFields }}
{{- $f.StructField }} *{{ $f.Type }}
{{ range $_, $f := $.Fields }}
{{- if or (not $f.Immutable) $f.UpdateDefault }}
{{- $f.StructField }} *{{ $f.Type }}
{{- end }}
{{ end }}
{{- range $_, $e := $.Edges }}
{{- $e.StructField }} map[{{ $.ID.Type }}]struct{}
@@ -203,12 +205,18 @@ func ({{ $receiver }} *{{ $onebuilder }}) ExecX(ctx context.Context) {
{{ end }}
{{ end }}
{{/* shared templates for validators. */}}
{{ define "update/validators" }}
{{/* shared template for the save method of the 2 builders */}}
{{ define "update/save" }}
{{- $pkg := .Scope.Package -}}
{{- $zero := .Scope.ZeroValue }}
{{- $receiver := .Scope.Receiver -}}
{{- range $_, $f := $.Fields -}}
{{- if $f.UpdateDefault -}}
if {{ $receiver }}.{{ $f.StructField }} == nil {
v := {{ $.Package }}.{{ $f.UpdateDefaultName }}{{ if $f.IsTime }}(){{ end }}
{{ $receiver }}.{{ $f.StructField }} = &v
}
{{ end -}}
{{ with $f.Validators -}}
if {{ $receiver }}.{{ $f.StructField }} != nil {
if err := {{ $.Package }}.{{ $f.Validator }}(*{{ $receiver }}.{{ $f.StructField }}); err != nil {

View File

@@ -49,7 +49,7 @@ func ({{ $receiver }} *{{ $slice }}) FromResponse(res *gremlin.Response) error {
*{{ $receiver }} = append(*{{ $receiver }}, &{{ $.Name }}{
ID: v.ID,
{{ range $_, $f := $.Fields }}
{{- pascal $f.Name }}: {{- if $f.IsTime }}time.Unix(v.{{ pascal $f.Name }}, 0) {{ else }}v.{{ pascal $f.Name }}{{ end }},
{{- pascal $f.Name }}: {{- if $f.IsTime }}time.Unix(0, v.{{ pascal $f.Name }}) {{ else }}v.{{ pascal $f.Name }}{{ end }},
{{ end -}}
})
}

View File

@@ -50,16 +50,18 @@ func ({{ $receiver }} *{{ $builder }}) gremlin({{ if $one }}id {{ $.ID.Type }}{{
{{ end }}
trs []*dsl.Traversal
)
{{- range $_, $f := $.MutableFields }}
if {{ $receiver }}.{{ $f.StructField }} != nil {
{{- if $f.Unique }}
constraints = append(constraints, &constraint{
pred: g.V().Has({{ $.Package }}.Label, {{ $.Package }}.{{ $f.Constant }}, *{{ $receiver }}.{{ $f.StructField }}).Count(),
test: __.Is(p.NEQ(0)).Constant(NewErrUniqueField({{ $.Package }}.Label, {{ $.Package }}.{{ $f.Constant }}, *{{ $receiver }}.{{ $f.StructField }})),
})
{{- range $_, $f := $.Fields }}
{{- if or (not $f.Immutable) $f.UpdateDefault }}
if {{ $receiver }}.{{ $f.StructField }} != nil {
{{- if $f.Unique }}
constraints = append(constraints, &constraint{
pred: g.V().Has({{ $.Package }}.Label, {{ $.Package }}.{{ $f.Constant }}, *{{ $receiver }}.{{ $f.StructField }}).Count(),
test: __.Is(p.NEQ(0)).Constant(NewErrUniqueField({{ $.Package }}.Label, {{ $.Package }}.{{ $f.Constant }}, *{{ $receiver }}.{{ $f.StructField }})),
})
{{- end }}
v.Property(dsl.Single, {{ $.Package }}.{{ $f.Constant }}, *{{ $receiver }}.{{ $f.StructField }})
}
{{- end }}
v.Property(dsl.Single, {{ $.Package }}.{{ $f.Constant }}, *{{ $receiver }}.{{ $f.StructField }})
}
{{- end }}
{{- range $_, $e := $.Edges }}
{{- $direction := "In" }}

View File

@@ -60,18 +60,20 @@ func ({{ $receiver }} *{{ $builder }}) sqlSave(ctx context.Context) ({{ $ret }}
res sql.Result
builder = sql.Update({{ $.Package }}.Table).Where(sql.InInts({{ $.Package }}.{{ $.ID.Constant }}, ids...))
)
{{- range $_, $f := $.MutableFields }}
if {{ $receiver }}.{{ $f.StructField }} != nil {
update = true
builder.Set({{ $.Package }}.{{ $f.Constant }}, *{{ $receiver }}.{{ $f.StructField }})
{{- if $one }}
{{- if $f.Nillable }}
{{ $.Receiver }}.{{ pascal $f.Name }} = {{ $receiver }}.{{ $f.StructField }}
{{- else }}
{{ $.Receiver }}.{{ pascal $f.Name }} = *{{ $receiver }}.{{ $f.StructField }}
{{- range $_, $f := $.Fields }}
{{- if or (not $f.Immutable) $f.UpdateDefault }}
if {{ $receiver }}.{{ $f.StructField }} != nil {
update = true
builder.Set({{ $.Package }}.{{ $f.Constant }}, *{{ $receiver }}.{{ $f.StructField }})
{{- if $one }}
{{- if $f.Nillable }}
{{ $.Receiver }}.{{ pascal $f.Name }} = {{ $receiver }}.{{ $f.StructField }}
{{- else }}
{{ $.Receiver }}.{{ pascal $f.Name }} = *{{ $receiver }}.{{ $f.StructField }}
{{- end }}
{{- end }}
{{- end }}
}
}
{{- end }}
{{- end }}
if update {
query, args := builder.Query()

View File

@@ -33,15 +33,20 @@ var (
fields = {{ base $.Schema }}.{{ $.Name }}{}.Fields()
{{ range $i, $f := $.Fields -}}
{{- $desc := print "desc" (pascal $f.Name) -}}
{{ if or $f.HasDefault $f.Validators -}}
{{ if or $f.Default $f.UpdateDefault $f.Validators -}}
// {{ $desc }} is the schema descriptor for {{ $f.Name }} field.
{{ $desc }} = fields[{{ $i }}].Descriptor()
{{ end -}}
{{ if $f.HasDefault }}
{{ if $f.Default }}
{{- $default := $f.DefaultName -}}
// {{ $default }} holds the default value for the {{ $f.Name }} field.
// {{ $default }} holds the default value on creation for the {{ $f.Name }} field.
{{ $default }} = {{ $desc }}.Default.({{ if $f.IsTime }}func() {{ end }}{{ $f.Type }})
{{ end -}}
{{ if $f.UpdateDefault }}
{{- $default := $f.UpdateDefaultName -}}
// {{ $default }} holds the default value on update for the {{ $f.Name }} field.
{{ $default }} = {{ $desc }}.UpdateDefault.({{ if $f.IsTime }}func() {{ end }}{{ $f.Type }})
{{ end -}}
{{ with $f.Validators -}}
{{ $name := $f.Validator -}}
{{ $type := printf "func (%s) error" $f.Type -}}

View File

@@ -52,8 +52,10 @@ type (
// Nillable indicates that this field can be null in the
// database and pointer in the generated entities.
Nillable bool
// HasDefault indicates if this field a default value.
HasDefault bool
// Default indicates if this field has a default value for creation.
Default bool
// UpdateDefault indicates if this field has a default value for update.
UpdateDefault bool
// Immutable indicates is this field cannot be updated.
Immutable bool
// StructTag of the field. default to "json".
@@ -142,16 +144,17 @@ func NewType(c Config, schema *load.Schema) (*Type, error) {
return nil, fmt.Errorf("field %q redeclared for type %q", f.Name, typ.Name)
}
typ.Fields[i] = &Field{
def: f,
Name: f.Name,
Type: f.Type,
Unique: f.Unique,
Nillable: f.Nillable,
Optional: f.Optional,
HasDefault: f.Default,
Immutable: f.Immutable,
StructTag: structTag(f.Name, f.Tag),
Validators: f.Validators,
def: f,
Name: f.Name,
Type: f.Type,
Unique: f.Unique,
Nillable: f.Nillable,
Optional: f.Optional,
Default: f.Default,
UpdateDefault: f.UpdateDefault,
Immutable: f.Immutable,
StructTag: structTag(f.Name, f.Tag),
Validators: f.Validators,
}
typ.fields[f.Name] = typ.Fields[i]
}
@@ -194,10 +197,20 @@ func (t Type) HasValidators() bool {
return false
}
// HasDefault indicates if any of this type's fields has default value.
// HasDefault indicates if any of this type's fields has default value on creation.
func (t Type) HasDefault() bool {
for _, f := range t.Fields {
if f.HasDefault {
if f.Default {
return true
}
}
return false
}
// HasUpdateDefault indicates if any of this type's fields has default value on update.
func (t Type) HasUpdateDefault() bool {
for _, f := range t.Fields {
if f.Default {
return true
}
}
@@ -331,6 +344,9 @@ func (f Field) Constant() string { return "Field" + pascal(f.Name) }
// DefaultName returns the variable name of the default value of this field.
func (f Field) DefaultName() string { return "Default" + pascal(f.Name) }
// UpdateDefaultName returns the variable name of the update default value of this field.
func (f Field) UpdateDefaultName() string { return "Update" + f.DefaultName() }
// StructField returns the struct member of the field.
func (f Field) StructField() string {
if token.Lookup(f.Name).IsKeyword() {
@@ -404,7 +420,7 @@ func (f Field) Column() *schema.Column {
c.Charset = *f.def.Charset
}
}
if f.HasDefault && !f.IsTime() {
if f.Default && !f.IsTime() {
// since this column is used only for codegen, the actual default
// value is imported by the migrate package and used directly.
c.Default = true