model merging
This commit is contained in:
parent
b160e5c1f4
commit
31fe8b6e1d
3 changed files with 144 additions and 1 deletions
|
@ -179,11 +179,16 @@ func newImporter() importer {
|
||||||
}
|
}
|
||||||
|
|
||||||
imp.Singleton = mapImports{
|
imp.Singleton = mapImports{
|
||||||
"boil_queries": {
|
"boil_queries": imports{
|
||||||
|
standard: importList{
|
||||||
|
`"database/sql"`,
|
||||||
|
`"strings"`,
|
||||||
|
},
|
||||||
thirdParty: importList{
|
thirdParty: importList{
|
||||||
`"github.com/lbryio/sqlboiler/boil"`,
|
`"github.com/lbryio/sqlboiler/boil"`,
|
||||||
`"github.com/lbryio/sqlboiler/queries"`,
|
`"github.com/lbryio/sqlboiler/queries"`,
|
||||||
`"github.com/lbryio/sqlboiler/queries/qm"`,
|
`"github.com/lbryio/sqlboiler/queries/qm"`,
|
||||||
|
`"github.com/pkg/errors"`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"boil_types": {
|
"boil_types": {
|
||||||
|
|
84
templates/23_merge.tpl
Normal file
84
templates/23_merge.tpl
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
{{- $tableNamePlural := .Table.Name | plural | titleCase -}}
|
||||||
|
{{- $tableNameSingular := .Table.Name | singular | titleCase -}}
|
||||||
|
{{- if .Table.IsJoinTable -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- $dot := . }}
|
||||||
|
// Merge combines two {{$tableNamePlural}} into one. The primary record will be kept, and the secondary will be deleted.
|
||||||
|
func Merge{{$tableNamePlural}}(exec boil.Executor, primaryID uint64, secondaryID uint64) error {
|
||||||
|
txdb, ok := exec.(boil.Beginner)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("database does not support transactions")
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, txErr := txdb.Begin()
|
||||||
|
if txErr != nil {
|
||||||
|
return txErr
|
||||||
|
}
|
||||||
|
|
||||||
|
primary, err := Find{{$tableNameSingular}}(tx, primaryID)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if primary == nil {
|
||||||
|
return errors.New("Primary {{$tableNameSingular}} not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
secondary, err := Find{{$tableNameSingular}}(tx, secondaryID)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if secondary == nil {
|
||||||
|
return errors.New("Secondary {{$tableNameSingular}} not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
relatedFields := map[string]string{
|
||||||
|
{{- range .Tables -}}
|
||||||
|
{{- range .FKeys -}}
|
||||||
|
{{- if eq $dot.Table.Name .ForeignTable }}
|
||||||
|
"{{.Table }}": "{{ .Column}}",
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end }}
|
||||||
|
}
|
||||||
|
err = mergeModels(tx, primaryID, secondaryID, relatedFields)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pr := reflect.ValueOf(primary)
|
||||||
|
sr := reflect.ValueOf(secondary)
|
||||||
|
// for any column thats null on the primary and not null on the secondary, copy from secondary to primary
|
||||||
|
for i := 0; i < sr.Elem().NumField(); i++ {
|
||||||
|
pf := pr.Elem().Field(i)
|
||||||
|
sf := sr.Elem().Field(i)
|
||||||
|
if sf.IsValid() {
|
||||||
|
if nullable, ok := sf.Interface().(Nullable); ok && !nullable.IsZero() && pf.Interface().(Nullable).IsZero() {
|
||||||
|
pf.Set(sf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = primary.Update(tx)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = secondary.Delete(tx)
|
||||||
|
if err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.Commit()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge combines two {{$tableNamePlural}} into one. The primary record will be kept, and the secondary will be deleted.
|
||||||
|
func Merge{{$tableNamePlural}}G(primaryID uint64, secondaryID uint64) error {
|
||||||
|
return Merge{{$tableNamePlural}}(boil.GetDB(), primaryID, secondaryID)
|
||||||
|
}
|
||||||
|
{{- end -}}{{/* join table */}}
|
|
@ -19,3 +19,57 @@ func NewQuery(exec boil.Executor, mods ...qm.QueryMod) *queries.Query {
|
||||||
|
|
||||||
return q
|
return q
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mergeModels(tx *sql.Tx, primaryID uint64, secondaryID uint64, relatedFields map[string]string) error {
|
||||||
|
if len(relatedFields) < 1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for table, column := range relatedFields {
|
||||||
|
// TODO: use NewQuery here, not plain sql
|
||||||
|
query := "UPDATE " + table + " SET " + column + " = ? WHERE " + column + " = ?"
|
||||||
|
_, err := tx.Exec(query, primaryID, secondaryID)
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return checkMerge(tx, relatedFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkMerge(tx *sql.Tx, fields map[string]string) error {
|
||||||
|
columns := []interface{}{}
|
||||||
|
seenColumns := map[string]bool{}
|
||||||
|
placeholders := []string{}
|
||||||
|
for _, column := range fields {
|
||||||
|
if _, ok := seenColumns[column]; !ok {
|
||||||
|
columns = append(columns, column)
|
||||||
|
seenColumns[column] = true
|
||||||
|
placeholders = append(placeholders, "?")
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
placeholder := strings.Join(placeholders, ", ")
|
||||||
|
|
||||||
|
q := `SELECT table_name, column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND column_name IN (` + placeholder + `)`
|
||||||
|
rows, err := tx.Query(q, columns...)
|
||||||
|
defer rows.Close()
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var tableName string
|
||||||
|
var columnName string
|
||||||
|
err = rows.Scan(&tableName, &columnName)
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, exists := fields[tableName]; !exists {
|
||||||
|
return errors.New("Missing merge for " + tableName + "." + columnName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue