github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/sqlx/gen/model_crud.go (about)

     1  package gen
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/johnnyeven/libtools/godash"
     9  	"github.com/johnnyeven/libtools/sqlx/builder"
    10  )
    11  
    12  func (m *Model) methodsForCRUD() string {
    13  	return strings.Join([]string{
    14  		m.methodsForBasic(),
    15  		m.methodsForKeys(),
    16  	}, "\n\n")
    17  }
    18  
    19  func (m *Model) EnableIfNeed() string {
    20  	buf := &bytes.Buffer{}
    21  
    22  	if m.HasSoftDelete {
    23  		m.ParseTo(buf, `{{ var .StructName }}.{{ .FieldSoftDelete }} = {{ use .ConstSoftDeleteTrue }}
    24  		`)
    25  	}
    26  
    27  	return buf.String()
    28  }
    29  
    30  func (m *Model) TypeTime(fieldName string) string {
    31  	if field, ok := m.Fields[fieldName]; ok {
    32  		return field.Type().String()
    33  	}
    34  	return ""
    35  }
    36  
    37  func (m *Model) SetCreatedAtIfNeed() string {
    38  	buf := &bytes.Buffer{}
    39  
    40  	if m.HasCreatedAt {
    41  		m.ParseTo(buf, `if {{ var .StructName }}.{{ .FieldCreatedAt }}.IsZero() {
    42  			{{ var .StructName }}.{{ .FieldCreatedAt }} = {{ use ( .TypeTime .FieldCreatedAt ) }}({{ use "time" }}.Now())
    43  		}
    44  		`)
    45  
    46  		if m.HasUpdatedAt {
    47  			m.ParseTo(buf, `{{ var .StructName }}.{{ .FieldUpdatedAt }} = {{ var .StructName }}.{{ .FieldCreatedAt }}
    48  			`)
    49  		}
    50  	}
    51  
    52  	return buf.String()
    53  }
    54  
    55  func (m *Model) SetUpdatedForFieldValuesAtIfNeed() string {
    56  	buf := &bytes.Buffer{}
    57  
    58  	if m.HasCreatedAt {
    59  		if m.HasUpdatedAt {
    60  			m.ParseTo(buf, `
    61  			if _, ok := fieldValues["{{ .FieldUpdatedAt }}"]; !ok {
    62  				fieldValues["{{ .FieldUpdatedAt }}"] = {{ use ( .TypeTime .FieldUpdatedAt ) }}({{ use "time" }}.Now())
    63  			}
    64  			`)
    65  		}
    66  	}
    67  
    68  	return buf.String()
    69  }
    70  
    71  func (m *Model) SetEnabledForFieldValuesAtIfNeed() string {
    72  	buf := &bytes.Buffer{}
    73  
    74  	if m.HasSoftDelete {
    75  		m.ParseTo(buf, `
    76  		if _, ok := fieldValues["{{ .FieldSoftDelete }}"]; !ok {
    77  			fieldValues["{{ .FieldSoftDelete }}"] = {{ use .ConstSoftDeleteTrue }}
    78  		}
    79  		`)
    80  	}
    81  
    82  	return buf.String()
    83  }
    84  
    85  func (m *Model) SetUpdatedAtIfNeed() string {
    86  	buf := &bytes.Buffer{}
    87  
    88  	if m.HasCreatedAt {
    89  		if m.HasUpdatedAt {
    90  			m.ParseTo(buf, `{{ var .StructName }}.{{ .FieldUpdatedAt }} = {{ use ( .TypeTime .FieldUpdatedAt ) }}({{ use "time" }}.Now())
    91  			`)
    92  		}
    93  	}
    94  
    95  	return buf.String()
    96  }
    97  
    98  func (m *Model) methodsForBasic() string {
    99  	buf := &bytes.Buffer{}
   100  
   101  	m.ParseTo(buf, `
   102  	{{ $method := "Create"}}
   103  	func ({{ var .StructName }} *{{ .StructName }}) {{ $method }}(db *{{ use "github.com/johnnyeven/libtools/sqlx" }}.DB) error {
   104  	{{ ( .EnableIfNeed ) }}
   105  	{{ ( .SetCreatedAtIfNeed ) }}
   106  
   107  	stmt := {{ var .StructName }}.D().
   108  		Insert({{ var .StructName }}).
   109  		Comment("{{ .StructName }}.{{ $method }}")
   110  
   111  	dbRet := db.Do(stmt)
   112  	err := dbRet.Err()
   113  
   114  	{{ if .HasAutoIncrement }}
   115  		if err == nil {
   116  			lastInsertID, _ := dbRet.LastInsertId()
   117  			{{ var .StructName }}.{{ .FieldAutoIncrement }} = {{ .FieldType .FieldAutoIncrement }}(lastInsertID)
   118  		}
   119  	{{ end }}
   120  
   121  	return err
   122  	}
   123  	`)
   124  
   125  	m.ParseTo(buf, fmt.Sprintf(
   126  		`
   127  {{ $method := "DeleteByStruct" }}
   128  func ({{ var .StructName }} *{{ .StructName }}) {{ $method }}(db *{{ use "github.com/johnnyeven/libtools/sqlx" }}.DB) (err error) {
   129  	table :=  {{ var .StructName }}.T()
   130  
   131  	stmt := table.Delete().
   132  		Comment("{{ .StructName }}.{{ $method }}").
   133  		Where({{ var .StructName }}.ConditionByStruct())
   134  
   135  	err = db.Do(stmt).Err()
   136  	return
   137  }
   138  `))
   139  
   140  	if len(m.Keys.UniqueIndexes) > 0 {
   141  		m.ParseTo(buf, `
   142  {{ $method := "CreateOnDuplicateWithUpdateFields"}}
   143  func ({{ var .StructName }} *{{ .StructName }}) {{ $method }}(db *{{ use "github.com/johnnyeven/libtools/sqlx" }}.DB, updateFields []string) error {
   144  	if len(updateFields) == 0 {
   145  		panic({{ use "fmt"}}.Errorf("must have update fields"))
   146  	}
   147  
   148  	{{ ( .EnableIfNeed ) }}
   149  	{{ ( .SetCreatedAtIfNeed ) }}
   150  
   151  	table := {{ var .StructName }}.T()
   152  
   153  	fieldValues := {{ use "github.com/johnnyeven/libtools/sqlx" }}.FieldValuesFromStructByNonZero({{ var .StructName }}, updateFields...)
   154  
   155  	{{ if .HasAutoIncrement }}
   156  		delete(fieldValues, "{{ .FieldAutoIncrement }}")
   157  	{{ end }}
   158  
   159  	cols, vals := table.ColumnsAndValuesByFieldValues(fieldValues)
   160  
   161  	m := make(map[string]bool, len(updateFields))
   162  	for _, field := range updateFields {
   163  		m[field] = true
   164  	}
   165  
   166  	// fields of unique index can not update
   167  	{{ if .HasCreatedAt }} delete(m, "{{ .FieldCreatedAt }}")
   168  	{{ end }}
   169  
   170  	for _, fieldNames := range {{ var .StructName }}.UniqueIndexes() {
   171  		for _, field := range fieldNames {
   172  			delete(m, field)
   173  		}
   174  	}
   175  
   176  	if len(m) == 0 {
   177  		panic(fmt.Errorf("no fields for updates"))
   178  	}
   179  
   180  	for field := range fieldValues {
   181  		if !m[field] {
   182  			delete(fieldValues, field)
   183  		}
   184  	}
   185  
   186  	stmt := table.
   187  		Insert().Columns(cols).Values(vals...).
   188  		OnDuplicateKeyUpdate(table.AssignsByFieldValues(fieldValues)...).
   189  		Comment("{{ .StructName }}.{{ $method }}")
   190  
   191  	return db.Do(stmt).Err()
   192  }
   193  	`)
   194  	}
   195  
   196  	return buf.String()
   197  }
   198  
   199  func toExactlyConditionFrom(fieldNames ...string) string {
   200  	buf := &bytes.Buffer{}
   201  	for _, fieldName := range fieldNames {
   202  		buf.WriteString(fmt.Sprintf(`table.F("%s").Eq({{ var .StructName }}.%s),
   203  		`, fieldName, fieldName))
   204  	}
   205  	return buf.String()
   206  }
   207  
   208  func createMethod(method string, fieldNames ...string) string {
   209  	return fmt.Sprintf(method, strings.Join(fieldNames, "And"))
   210  }
   211  
   212  func (m *Model) methodsForKeys() string {
   213  	buf := &bytes.Buffer{}
   214  
   215  	m.Table.Keys.Range(func(key *builder.Key, idx int) {
   216  		fieldNames := key.Columns.FieldNames()
   217  		fieldNamesWithoutEnabled := godash.StringFilter(fieldNames, func(item string, i int) bool {
   218  			if m.HasSoftDelete {
   219  				return item != m.FieldSoftDelete
   220  			}
   221  			return true
   222  		})
   223  		if m.HasSoftDelete && key.Type == builder.PRIMARY {
   224  			fieldNames = append(fieldNames, m.FieldSoftDelete)
   225  		}
   226  		if key.Type == builder.PRIMARY || key.Type == builder.UNIQUE_INDEX {
   227  
   228  			m.ParseTo(buf, fmt.Sprintf(`
   229  {{ $method := "%s" }}
   230  func ({{ var .StructName }} *{{ .StructName }}) {{ $method }}(db *{{ use "github.com/johnnyeven/libtools/sqlx" }}.DB) error {
   231  	{{ ( .EnableIfNeed ) }}
   232  
   233  	table :=  {{ var .StructName }}.T()
   234  	stmt := table.Select().
   235  		Comment("{{ .StructName }}.{{ $method }}").
   236  		Where({{ use "github.com/johnnyeven/libtools/sqlx/builder" }}.And(
   237  			%s
   238  		))
   239  
   240  	return db.Do(stmt).Scan({{ var .StructName }}).Err()
   241  }
   242  	`,
   243  				createMethod("FetchBy%s", fieldNamesWithoutEnabled...),
   244  				toExactlyConditionFrom(fieldNames...),
   245  			))
   246  
   247  			m.ParseTo(buf, fmt.Sprintf(`
   248  {{ $method := "%s" }}
   249  func ({{ var .StructName }} *{{ .StructName }}) {{ $method }}(db *{{ use "github.com/johnnyeven/libtools/sqlx" }}.DB) error {
   250  	{{ ( .EnableIfNeed ) }}
   251  
   252  	table :=  {{ var .StructName }}.T()
   253  	stmt := table.Select().
   254  		Comment("{{ .StructName }}.{{ $method }}").
   255  		Where({{ use "github.com/johnnyeven/libtools/sqlx/builder" }}.And(
   256  			%s
   257  		)).
   258  		ForUpdate()
   259  
   260  	return db.Do(stmt).Scan({{ var .StructName }}).Err()
   261  }
   262  					`,
   263  				createMethod("FetchBy%sForUpdate", fieldNamesWithoutEnabled...),
   264  				toExactlyConditionFrom(fieldNames...),
   265  			))
   266  
   267  			m.ParseTo(buf, fmt.Sprintf(`
   268  {{ $method := "%s" }}
   269  func ({{ var .StructName }} *{{ .StructName }}) {{ $method }}(db *{{ use "github.com/johnnyeven/libtools/sqlx" }}.DB) error {
   270  	{{ ( .EnableIfNeed ) }}
   271  
   272  	table :=  {{ var .StructName }}.T()
   273  	stmt := table.Delete().
   274  		Comment("{{ .StructName }}.{{ $method }}").
   275  		Where({{ use "github.com/johnnyeven/libtools/sqlx/builder" }}.And(
   276  			%s
   277  		))
   278  
   279  	return db.Do(stmt).Scan({{ var .StructName }}).Err()
   280  }
   281  					`,
   282  				createMethod("DeleteBy%s", fieldNamesWithoutEnabled...),
   283  				toExactlyConditionFrom(fieldNames...),
   284  			))
   285  
   286  			m.ParseTo(buf, fmt.Sprintf(`
   287  {{ $method := "%s" }}
   288  {{ $methodForFetch := "%s" }}
   289  func ({{ var .StructName }} *{{ .StructName }}) {{ $method }}(db *{{ use "github.com/johnnyeven/libtools/sqlx" }}.DB, fieldValues {{ use "github.com/johnnyeven/libtools/sqlx/builder" }}.FieldValues) error {
   290  	{{ ( .SetUpdatedForFieldValuesAtIfNeed ) }}
   291  	{{ ( .EnableIfNeed ) }}
   292  
   293  	table := {{ var .StructName }}.T()
   294  
   295  	{{ if .HasAutoIncrement }}
   296  		delete(fieldValues, "{{ .FieldAutoIncrement }}")
   297  	{{ end }}
   298  
   299  	stmt := table.Update().
   300  		Comment("{{ .StructName }}.{{ $method }}").
   301  		Set(table.AssignsByFieldValues(fieldValues)...).
   302  		Where({{ use "github.com/johnnyeven/libtools/sqlx/builder" }}.And(
   303  			%s
   304  		))
   305  
   306  	dbRet := db.Do(stmt).Scan({{ var .StructName }})
   307  	err := dbRet.Err()
   308  	if err != nil {
   309  		return err
   310  	}
   311  
   312  	rowsAffected, _ := dbRet.RowsAffected()
   313  	if rowsAffected == 0 {
   314  		return {{ var .StructName }}.{{ $methodForFetch }}(db)
   315  	}
   316  	return nil
   317  }
   318  					`,
   319  				createMethod("UpdateBy%sWithMap", fieldNamesWithoutEnabled...),
   320  				createMethod("FetchBy%s", fieldNamesWithoutEnabled...),
   321  				toExactlyConditionFrom(fieldNames...),
   322  			))
   323  
   324  			m.ParseTo(buf, fmt.Sprintf(`
   325  {{ $method := "%s" }}
   326  {{ $methodForUpdateWithMap := "%s" }}
   327  func ({{ var .StructName }} *{{ .StructName }}) {{ $method }}(db *{{ use "github.com/johnnyeven/libtools/sqlx" }}.DB, zeroFields ...string) error {
   328  	fieldValues := {{ use "github.com/johnnyeven/libtools/sqlx" }}.FieldValuesFromStructByNonZero({{ var .StructName }}, zeroFields...)
   329  	return {{ var .StructName }}.{{ $methodForUpdateWithMap }}(db, fieldValues)
   330  }
   331  					`,
   332  				createMethod("UpdateBy%sWithStruct", fieldNamesWithoutEnabled...),
   333  				createMethod("UpdateBy%sWithMap", fieldNamesWithoutEnabled...),
   334  			))
   335  
   336  			if m.HasSoftDelete {
   337  
   338  				m.ParseTo(buf, fmt.Sprintf(`
   339  {{ $method := "%s" }}
   340  {{ $methodForDelete := "%s" }}
   341  func ({{ var .StructName }} *{{ .StructName }}) {{ $method }}(db *{{ use "github.com/johnnyeven/libtools/sqlx" }}.DB) error {
   342  	{{ ( .EnableIfNeed ) }}
   343  	table :=  {{ var .StructName }}.T()
   344  
   345  	fieldValues := {{ use "github.com/johnnyeven/libtools/sqlx/builder" }}.FieldValues{}
   346  	fieldValues["{{ .FieldSoftDelete }}"] = {{ use .ConstSoftDeleteFalse }}
   347  
   348  	{{ ( .SetUpdatedForFieldValuesAtIfNeed ) }}
   349  
   350  	stmt := table.Update().
   351  		Comment("{{ .StructName }}.{{ $method }}").
   352  		Set(table.AssignsByFieldValues(fieldValues)...).
   353  		Where({{ use "github.com/johnnyeven/libtools/sqlx/builder" }}.And(
   354  			%s
   355  		))
   356  
   357  	dbRet := db.Do(stmt).Scan({{ var .StructName }})
   358  	err := dbRet.Err()
   359  	if err != nil {
   360  		dbErr := {{ use "github.com/johnnyeven/libtools/sqlx" }}.DBErr(err)
   361  		if dbErr.IsConflict() {
   362  			return 	{{ var .StructName }}.{{ $methodForDelete }}(db)
   363  		}
   364  		return err
   365  	}
   366  	return nil
   367  }
   368  					`,
   369  					createMethod("SoftDeleteBy%s", fieldNamesWithoutEnabled...),
   370  					createMethod("DeleteBy%s", fieldNamesWithoutEnabled...),
   371  					toExactlyConditionFrom(fieldNames...),
   372  				))
   373  			}
   374  		}
   375  	})
   376  
   377  	return buf.String()
   378  }