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 }