2017-10-04 19:35:59 -04:00
|
|
|
package db
|
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
|
|
|
"fmt"
|
2017-11-17 21:01:06 -05:00
|
|
|
"github.com/aclindsa/gorp"
|
2017-10-04 19:35:59 -04:00
|
|
|
"github.com/aclindsa/moneygo/internal/config"
|
2017-12-02 06:14:47 -05:00
|
|
|
"github.com/aclindsa/moneygo/internal/models"
|
2017-12-06 21:09:47 -05:00
|
|
|
"github.com/aclindsa/moneygo/internal/store"
|
2017-10-04 19:35:59 -04:00
|
|
|
_ "github.com/go-sql-driver/mysql"
|
|
|
|
_ "github.com/lib/pq"
|
|
|
|
_ "github.com/mattn/go-sqlite3"
|
2017-10-24 20:57:55 -04:00
|
|
|
"log"
|
|
|
|
"strings"
|
2017-10-04 19:35:59 -04:00
|
|
|
)
|
|
|
|
|
2017-12-04 21:05:17 -05:00
|
|
|
// luaMaxLengthBuffer is intended to be enough bytes such that a given string
|
|
|
|
// no longer than models.LuaMaxLength is sure to fit within a database
|
|
|
|
// implementation's string type specified by the same.
|
2017-11-03 20:50:19 -04:00
|
|
|
const luaMaxLengthBuffer int = 4096
|
|
|
|
|
2017-12-09 06:06:20 -05:00
|
|
|
func getDbMap(db *sql.DB, dbtype config.DbType) (*gorp.DbMap, error) {
|
2017-10-04 19:35:59 -04:00
|
|
|
var dialect gorp.Dialect
|
2017-10-05 08:06:08 -04:00
|
|
|
if dbtype == config.SQLite {
|
2017-10-04 19:35:59 -04:00
|
|
|
dialect = gorp.SqliteDialect{}
|
2017-10-05 08:06:08 -04:00
|
|
|
} else if dbtype == config.MySQL {
|
2017-10-04 19:35:59 -04:00
|
|
|
dialect = gorp.MySQLDialect{
|
|
|
|
Engine: "InnoDB",
|
|
|
|
Encoding: "UTF8",
|
|
|
|
}
|
2017-10-05 08:06:08 -04:00
|
|
|
} else if dbtype == config.Postgres {
|
2017-11-17 21:01:06 -05:00
|
|
|
dialect = gorp.PostgresDialect{
|
|
|
|
LowercaseFields: true,
|
|
|
|
}
|
2017-10-04 19:35:59 -04:00
|
|
|
} else {
|
2017-10-05 08:06:08 -04:00
|
|
|
return nil, fmt.Errorf("Don't know gorp dialect to go with '%s' DB type", dbtype.String())
|
2017-10-04 19:35:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
dbmap := &gorp.DbMap{Db: db, Dialect: dialect}
|
2017-12-02 06:14:47 -05:00
|
|
|
dbmap.AddTableWithName(models.User{}, "users").SetKeys(true, "UserId")
|
2017-12-03 06:11:38 -05:00
|
|
|
dbmap.AddTableWithName(models.Session{}, "sessions").SetKeys(true, "SessionId")
|
2017-12-03 06:38:22 -05:00
|
|
|
dbmap.AddTableWithName(models.Security{}, "securities").SetKeys(true, "SecurityId")
|
2017-12-07 21:05:55 -05:00
|
|
|
dbmap.AddTableWithName(models.Price{}, "prices").SetKeys(true, "PriceId")
|
|
|
|
dbmap.AddTableWithName(models.Account{}, "accounts").SetKeys(true, "AccountId")
|
2017-12-04 05:55:25 -05:00
|
|
|
dbmap.AddTableWithName(models.Transaction{}, "transactions").SetKeys(true, "TransactionId")
|
|
|
|
dbmap.AddTableWithName(models.Split{}, "splits").SetKeys(true, "SplitId")
|
2017-12-05 05:58:36 -05:00
|
|
|
rtable := dbmap.AddTableWithName(models.Report{}, "reports").SetKeys(true, "ReportId")
|
|
|
|
rtable.ColMap("Lua").SetMaxSize(models.LuaMaxLength + luaMaxLengthBuffer)
|
2017-10-04 19:35:59 -04:00
|
|
|
|
|
|
|
err := dbmap.CreateTablesIfNotExists()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return dbmap, nil
|
|
|
|
}
|
2017-10-24 20:57:55 -04:00
|
|
|
|
2017-12-09 06:06:20 -05:00
|
|
|
func getDSN(dbtype config.DbType, dsn string) string {
|
2017-10-24 20:57:55 -04:00
|
|
|
if dbtype == config.MySQL && !strings.Contains(dsn, "parseTime=true") {
|
|
|
|
log.Fatalf("The DSN for MySQL MUST contain 'parseTime=True' but does not!")
|
|
|
|
}
|
|
|
|
return dsn
|
|
|
|
}
|
2017-12-06 21:09:47 -05:00
|
|
|
|
|
|
|
type DbStore struct {
|
2017-12-09 06:06:20 -05:00
|
|
|
dbMap *gorp.DbMap
|
|
|
|
}
|
|
|
|
|
|
|
|
func (db *DbStore) Empty() error {
|
|
|
|
return db.dbMap.TruncateTables()
|
2017-12-06 21:09:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func (db *DbStore) Begin() (store.Tx, error) {
|
2017-12-09 06:06:20 -05:00
|
|
|
tx, err := db.dbMap.Begin()
|
2017-12-06 21:09:47 -05:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-12-09 06:06:20 -05:00
|
|
|
return &Tx{db.dbMap.Dialect, tx}, nil
|
2017-12-06 21:09:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func (db *DbStore) Close() error {
|
2017-12-09 06:06:20 -05:00
|
|
|
err := db.dbMap.Db.Close()
|
|
|
|
db.dbMap = nil
|
2017-12-06 21:09:47 -05:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetStore(dbtype config.DbType, dsn string) (store *DbStore, err error) {
|
2017-12-09 06:06:20 -05:00
|
|
|
dsn = getDSN(dbtype, dsn)
|
2017-12-06 21:09:47 -05:00
|
|
|
database, err := sql.Open(dbtype.String(), dsn)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
|
|
|
database.Close()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2017-12-09 06:06:20 -05:00
|
|
|
dbmap, err := getDbMap(database, dbtype)
|
2017-12-06 21:09:47 -05:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &DbStore{dbmap}, nil
|
|
|
|
}
|