github.com/tufanbarisyildirim/pop@v4.13.1+incompatible/dialect_common.go (about)

     1  package pop
     2  
     3  import (
     4  	"bytes"
     5  	"database/sql"
     6  	"encoding/gob"
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"os"
    11  	"os/exec"
    12  	"strings"
    13  
    14  	"github.com/gobuffalo/pop/columns"
    15  	"github.com/gobuffalo/pop/logging"
    16  	"github.com/gofrs/uuid"
    17  	"github.com/jmoiron/sqlx"
    18  	"github.com/pkg/errors"
    19  )
    20  
    21  func init() {
    22  	gob.Register(uuid.UUID{})
    23  }
    24  
    25  type commonDialect struct {
    26  	ConnectionDetails *ConnectionDetails
    27  }
    28  
    29  func (commonDialect) Lock(fn func() error) error {
    30  	return fn()
    31  }
    32  
    33  func (commonDialect) Quote(key string) string {
    34  	parts := strings.Split(key, ".")
    35  
    36  	for i, part := range parts {
    37  		part = strings.Trim(part, `"`)
    38  		part = strings.TrimSpace(part)
    39  
    40  		parts[i] = fmt.Sprintf(`"%v"`, part)
    41  	}
    42  
    43  	return strings.Join(parts, ".")
    44  }
    45  
    46  func genericCreate(s store, model *Model, cols columns.Columns, quoter quotable) error {
    47  	keyType := model.PrimaryKeyType()
    48  	switch keyType {
    49  	case "int", "int64":
    50  		var id int64
    51  		w := cols.Writeable()
    52  		query := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", quoter.Quote(model.TableName()), w.QuotedString(quoter), w.SymbolizedString())
    53  		log(logging.SQL, query)
    54  		res, err := s.NamedExec(query, model.Value)
    55  		if err != nil {
    56  			return err
    57  		}
    58  		id, err = res.LastInsertId()
    59  		if err == nil {
    60  			model.setID(id)
    61  		}
    62  		if err != nil {
    63  			return err
    64  		}
    65  		return nil
    66  	case "UUID", "string":
    67  		if keyType == "UUID" {
    68  			if model.ID() == emptyUUID {
    69  				u, err := uuid.NewV4()
    70  				if err != nil {
    71  					return err
    72  				}
    73  				model.setID(u)
    74  			}
    75  		} else if model.ID() == "" {
    76  			return fmt.Errorf("missing ID value")
    77  		}
    78  		w := cols.Writeable()
    79  		w.Add("id")
    80  		query := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", quoter.Quote(model.TableName()), w.QuotedString(quoter), w.SymbolizedString())
    81  		log(logging.SQL, query)
    82  		stmt, err := s.PrepareNamed(query)
    83  		if err != nil {
    84  			return err
    85  		}
    86  		_, err = stmt.Exec(model.Value)
    87  		if err != nil {
    88  			if err := stmt.Close(); err != nil {
    89  				return errors.WithMessage(err, "failed to close statement")
    90  			}
    91  			return err
    92  		}
    93  		return errors.WithMessage(stmt.Close(), "failed to close statement")
    94  	}
    95  	return errors.Errorf("can not use %s as a primary key type!", keyType)
    96  }
    97  
    98  func genericUpdate(s store, model *Model, cols columns.Columns, quoter quotable) error {
    99  	stmt := fmt.Sprintf("UPDATE %s SET %s WHERE %s", quoter.Quote(model.TableName()), cols.Writeable().QuotedUpdateString(quoter), model.whereNamedID())
   100  	log(logging.SQL, stmt, model.ID())
   101  	_, err := s.NamedExec(stmt, model.Value)
   102  	if err != nil {
   103  		return err
   104  	}
   105  	return nil
   106  }
   107  
   108  func genericDestroy(s store, model *Model, quoter quotable) error {
   109  	stmt := fmt.Sprintf("DELETE FROM %s WHERE %s", quoter.Quote(model.TableName()), model.whereID())
   110  	_, err := genericExec(s, stmt, model.ID())
   111  	if err != nil {
   112  		return err
   113  	}
   114  	return nil
   115  }
   116  
   117  func genericExec(s store, stmt string, args ...interface{}) (sql.Result, error) {
   118  	log(logging.SQL, stmt, args...)
   119  	res, err := s.Exec(stmt, args...)
   120  	return res, err
   121  }
   122  
   123  func genericSelectOne(s store, model *Model, query Query) error {
   124  	sqlQuery, args := query.ToSQL(model)
   125  	log(logging.SQL, sqlQuery, args...)
   126  	err := s.Get(model.Value, sqlQuery, args...)
   127  	if err != nil {
   128  		return err
   129  	}
   130  	return nil
   131  }
   132  
   133  func genericSelectMany(s store, models *Model, query Query) error {
   134  	sqlQuery, args := query.ToSQL(models)
   135  	log(logging.SQL, sqlQuery, args...)
   136  	err := s.Select(models.Value, sqlQuery, args...)
   137  	if err != nil {
   138  		return err
   139  	}
   140  	return nil
   141  }
   142  
   143  func genericLoadSchema(deets *ConnectionDetails, migrationURL string, r io.Reader) error {
   144  	// Open DB connection on the target DB
   145  	db, err := sqlx.Open(deets.Dialect, migrationURL)
   146  	if err != nil {
   147  		return errors.WithMessage(err, fmt.Sprintf("unable to load schema for %s", deets.Database))
   148  	}
   149  	defer db.Close()
   150  
   151  	// Get reader contents
   152  	contents, err := ioutil.ReadAll(r)
   153  	if err != nil {
   154  		return err
   155  	}
   156  
   157  	if len(contents) == 0 {
   158  		log(logging.Info, "schema is empty for %s, skipping", deets.Database)
   159  		return nil
   160  	}
   161  
   162  	_, err = db.Exec(string(contents))
   163  	if err != nil {
   164  		return errors.WithMessage(err, fmt.Sprintf("unable to load schema for %s", deets.Database))
   165  	}
   166  
   167  	log(logging.Info, "loaded schema for %s", deets.Database)
   168  	return nil
   169  }
   170  
   171  func genericDumpSchema(deets *ConnectionDetails, cmd *exec.Cmd, w io.Writer) error {
   172  	log(logging.SQL, strings.Join(cmd.Args, " "))
   173  
   174  	bb := &bytes.Buffer{}
   175  	mw := io.MultiWriter(w, bb)
   176  
   177  	cmd.Stdout = mw
   178  	cmd.Stderr = os.Stderr
   179  
   180  	err := cmd.Run()
   181  	if err != nil {
   182  		return err
   183  	}
   184  
   185  	x := bytes.TrimSpace(bb.Bytes())
   186  	if len(x) == 0 {
   187  		return errors.Errorf("unable to dump schema for %s", deets.Database)
   188  	}
   189  
   190  	log(logging.Info, "dumped schema for %s", deets.Database)
   191  	return nil
   192  }