Use context-bound SQL methods

Changes:
   Exec     -> ExecContext
   Query    -> QueryContext
   QueryRow -> QueryRowContext

   Rebind and store all possible queries before using them

Closes: #276
This commit is contained in:
Denis Makogon
2017-09-05 23:08:36 +03:00
parent da74f538c0
commit 9066dca750

View File

@@ -72,9 +72,22 @@ const (
type sqlStore struct {
db *sqlx.DB
// TODO we should prepare all of the statements, rebind them
// and store them all here.
insertAppQuery string
updateAppQuery string
getAppQuery string
selectAppConfigQuery string
removeAppQuery string
insertRouteQuery string
updateRouteQuery string
checkRouteAppQuery string
checkRouteQuery string
getRouteQuery string
removeRouteQuery string
insertCallQuery string
getCallQuery string
insertLogQuery string
getLogQuery string
deleteLogQuery string
}
// New will open the db specified by url, create any tables necessary
@@ -133,7 +146,56 @@ func New(url *url.URL) (models.Datastore, error) {
}
}
return &sqlStore{db: db}, nil
dstore := &sqlStore{
db: db,
insertAppQuery: db.Rebind("INSERT INTO apps (name, config) VALUES (?, ?);"),
selectAppConfigQuery: db.Rebind(`SELECT config FROM apps WHERE name=?`),
updateAppQuery: db.Rebind(`UPDATE apps SET config=? WHERE name=?`),
removeAppQuery: db.Rebind(`DELETE FROM apps WHERE name = ?`),
getAppQuery: db.Rebind(`SELECT name, config FROM apps WHERE name=?`),
checkRouteAppQuery: db.Rebind(`SELECT 1 FROM apps WHERE name=?`),
checkRouteQuery: db.Rebind(`SELECT 1 FROM routes WHERE app_name=? AND path=?`),
insertRouteQuery: db.Rebind(`INSERT INTO routes (
app_name,
path,
image,
format,
memory,
type,
timeout,
idle_timeout,
headers,
config
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`),
getRouteQuery: db.Rebind(fmt.Sprintf("%s WHERE app_name=? AND path=?", routeSelector)),
updateRouteQuery: db.Rebind(`UPDATE routes SET
image = ?,
format = ?,
memory = ?,
type = ?,
timeout = ?,
idle_timeout = ?,
headers = ?,
config = ?
WHERE app_name=? AND path=?;`),
removeRouteQuery: db.Rebind(`DELETE FROM routes WHERE path = ? AND app_name = ?`),
insertCallQuery: db.Rebind(`INSERT INTO calls (
id,
created_at,
started_at,
completed_at,
status,
app_name,
path
)
VALUES (?, ?, ?, ?, ?, ?, ?);`),
getCallQuery: db.Rebind(fmt.Sprintf(`%s WHERE id=? AND app_name=?`, callSelector)),
insertLogQuery: db.Rebind(`INSERT INTO logs (id, log) VALUES (?, ?);`),
getLogQuery: db.Rebind(`SELECT log FROM logs WHERE id=?`),
deleteLogQuery: db.Rebind(`DELETE FROM logs WHERE id=?`),
}
return dstore, nil
}
func (ds *sqlStore) InsertApp(ctx context.Context, app *models.App) (*models.App, error) {
@@ -146,8 +208,7 @@ func (ds *sqlStore) InsertApp(ctx context.Context, app *models.App) (*models.App
}
}
query := ds.db.Rebind("INSERT INTO apps (name, config) VALUES (?, ?);")
_, err = ds.db.Exec(query, app.Name, string(cbyte))
_, err = ds.db.ExecContext(ctx, ds.insertAppQuery, app.Name, string(cbyte))
if err != nil {
switch err := err.(type) {
case *mysql.MySQLError:
@@ -172,8 +233,7 @@ func (ds *sqlStore) InsertApp(ctx context.Context, app *models.App) (*models.App
func (ds *sqlStore) UpdateApp(ctx context.Context, newapp *models.App) (*models.App, error) {
app := &models.App{Name: newapp.Name}
err := ds.Tx(func(tx *sqlx.Tx) error {
query := tx.Rebind(`SELECT config FROM apps WHERE name=?`)
row := tx.QueryRow(query, app.Name)
row := tx.QueryRowContext(ctx, ds.selectAppConfigQuery, app.Name)
var config string
if err := row.Scan(&config); err != nil {
@@ -197,8 +257,7 @@ func (ds *sqlStore) UpdateApp(ctx context.Context, newapp *models.App) (*models.
return err
}
query = tx.Rebind(`UPDATE apps SET config=? WHERE name=?`)
res, err := tx.Exec(query, string(cbyte), app.Name)
res, err := tx.ExecContext(ctx, ds.updateAppQuery, string(cbyte), app.Name)
if err != nil {
return err
}
@@ -220,14 +279,12 @@ func (ds *sqlStore) UpdateApp(ctx context.Context, newapp *models.App) (*models.
}
func (ds *sqlStore) RemoveApp(ctx context.Context, appName string) error {
query := ds.db.Rebind(`DELETE FROM apps WHERE name = ?`)
_, err := ds.db.Exec(query, appName)
_, err := ds.db.ExecContext(ctx, ds.removeAppQuery, appName)
return err
}
func (ds *sqlStore) GetApp(ctx context.Context, name string) (*models.App, error) {
query := ds.db.Rebind(`SELECT name, config FROM apps WHERE name=?`)
row := ds.db.QueryRow(query, name)
row := ds.db.QueryRowContext(ctx, ds.getAppQuery, name)
var resName, config string
err := row.Scan(&resName, &config)
@@ -257,7 +314,7 @@ func (ds *sqlStore) GetApps(ctx context.Context, filter *models.AppFilter) ([]*m
res := []*models.App{}
query, args := buildFilterAppQuery(filter)
query = ds.db.Rebind(fmt.Sprintf("SELECT DISTINCT name, config FROM apps %s", query))
rows, err := ds.db.Query(query, args...)
rows, err := ds.db.QueryContext(ctx, query, args...)
if err != nil {
return nil, err
}
@@ -294,15 +351,13 @@ func (ds *sqlStore) InsertRoute(ctx context.Context, route *models.Route) (*mode
}
err = ds.Tx(func(tx *sqlx.Tx) error {
query := tx.Rebind(`SELECT 1 FROM apps WHERE name=?`)
r := tx.QueryRow(query, route.AppName)
r := tx.QueryRowContext(ctx, ds.checkRouteAppQuery, route.AppName)
if err := r.Scan(new(int)); err != nil {
if err == sql.ErrNoRows {
return models.ErrAppsNotFound
}
}
query = tx.Rebind(`SELECT 1 FROM routes WHERE app_name=? AND path=?`)
same, err := tx.Query(query, route.AppName, route.Path)
same, err := tx.QueryContext(ctx, ds.checkRouteQuery, route.AppName, route.Path)
if err != nil {
return err
}
@@ -311,21 +366,7 @@ func (ds *sqlStore) InsertRoute(ctx context.Context, route *models.Route) (*mode
return models.ErrRoutesAlreadyExists
}
query = tx.Rebind(`INSERT INTO routes (
app_name,
path,
image,
format,
memory,
type,
timeout,
idle_timeout,
headers,
config
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`)
_, err = tx.Exec(query,
_, err = tx.ExecContext(ctx, ds.insertRouteQuery,
route.AppName,
route.Path,
route.Image,
@@ -347,8 +388,7 @@ func (ds *sqlStore) InsertRoute(ctx context.Context, route *models.Route) (*mode
func (ds *sqlStore) UpdateRoute(ctx context.Context, newroute *models.Route) (*models.Route, error) {
var route models.Route
err := ds.Tx(func(tx *sqlx.Tx) error {
query := tx.Rebind(fmt.Sprintf("%s WHERE app_name=? AND path=?", routeSelector))
row := tx.QueryRow(query, newroute.AppName, newroute.Path)
row := tx.QueryRowContext(ctx, ds.getRouteQuery, newroute.AppName, newroute.Path)
if err := scanRoute(row, &route); err == sql.ErrNoRows {
return models.ErrRoutesNotFound
} else if err != nil {
@@ -367,18 +407,7 @@ func (ds *sqlStore) UpdateRoute(ctx context.Context, newroute *models.Route) (*m
return err
}
query = tx.Rebind(`UPDATE routes SET
image = ?,
format = ?,
memory = ?,
type = ?,
timeout = ?,
idle_timeout = ?,
headers = ?,
config = ?
WHERE app_name=? AND path=?;`)
res, err := tx.Exec(query,
res, err := tx.ExecContext(ctx, ds.updateAppQuery,
route.Image,
route.Format,
route.Memory,
@@ -412,8 +441,7 @@ func (ds *sqlStore) UpdateRoute(ctx context.Context, newroute *models.Route) (*m
}
func (ds *sqlStore) RemoveRoute(ctx context.Context, appName, routePath string) error {
query := ds.db.Rebind(`DELETE FROM routes WHERE path = ? AND app_name = ?`)
res, err := ds.db.Exec(query, routePath, appName)
res, err := ds.db.ExecContext(ctx, ds.removeRouteQuery, routePath, appName)
if err != nil {
return err
}
@@ -431,9 +459,7 @@ func (ds *sqlStore) RemoveRoute(ctx context.Context, appName, routePath string)
}
func (ds *sqlStore) GetRoute(ctx context.Context, appName, routePath string) (*models.Route, error) {
rSelectCondition := "%s WHERE app_name=? AND path=?"
query := ds.db.Rebind(fmt.Sprintf(rSelectCondition, routeSelector))
row := ds.db.QueryRow(query, appName, routePath)
row := ds.db.QueryRowContext(ctx, ds.getRouteQuery, appName, routePath)
var route models.Route
err := scanRoute(row, &route)
@@ -449,9 +475,8 @@ func (ds *sqlStore) GetRoute(ctx context.Context, appName, routePath string) (*m
func (ds *sqlStore) GetRoutes(ctx context.Context, filter *models.RouteFilter) ([]*models.Route, error) {
res := []*models.Route{}
query, args := buildFilterRouteQuery(filter)
query = fmt.Sprintf("%s %s", routeSelector, query)
query = ds.db.Rebind(query)
rows, err := ds.db.Query(query, args...)
query = ds.db.Rebind(fmt.Sprintf("%s %s", routeSelector, query))
rows, err := ds.db.QueryContext(ctx, query, args...)
// todo: check for no rows so we don't respond with a sql 500 err
if err != nil {
return nil, err
@@ -490,7 +515,7 @@ func (ds *sqlStore) GetRoutesByApp(ctx context.Context, appName string, filter *
query := fmt.Sprintf("%s %s", routeSelector, filterQuery)
query = ds.db.Rebind(query)
rows, err := ds.db.Query(query, args...)
rows, err := ds.db.QueryContext(ctx, query, args...)
// todo: check for no rows so we don't respond with a sql 500 err
if err != nil {
return nil, err
@@ -527,18 +552,7 @@ func (ds *sqlStore) Tx(f func(*sqlx.Tx) error) error {
}
func (ds *sqlStore) InsertCall(ctx context.Context, call *models.Call) error {
query := ds.db.Rebind(`INSERT INTO calls (
id,
created_at,
started_at,
completed_at,
status,
app_name,
path
)
VALUES (?, ?, ?, ?, ?, ?, ?);`)
_, err := ds.db.Exec(query, call.ID, call.CreatedAt.String(),
_, err := ds.db.ExecContext(ctx, ds.insertCallQuery, call.ID, call.CreatedAt.String(),
call.StartedAt.String(), call.CompletedAt.String(),
call.Status, call.AppName, call.Path)
if err != nil {
@@ -552,9 +566,7 @@ func (ds *sqlStore) InsertCall(ctx context.Context, call *models.Call) error {
// if we store the whole thing then it adds a lot of disk space and then we can
// make async only queue hints instead of entire calls (mq a lot smaller space wise). pick.
func (ds *sqlStore) GetCall(ctx context.Context, appName, callID string) (*models.Call, error) {
query := fmt.Sprintf(`%s WHERE id=? AND app_name=?`, callSelector)
query = ds.db.Rebind(query)
row := ds.db.QueryRow(query, callID, appName)
row := ds.db.QueryRowContext(ctx, ds.getCallQuery, callID, appName)
var call models.Call
err := scanCall(row, &call)
@@ -569,7 +581,7 @@ func (ds *sqlStore) GetCalls(ctx context.Context, filter *models.CallFilter) ([]
query, args := buildFilterCallQuery(filter)
query = fmt.Sprintf("%s %s", callSelector, query)
query = ds.db.Rebind(query)
rows, err := ds.db.Query(query, args...)
rows, err := ds.db.QueryContext(ctx, query, args...)
if err != nil {
return nil, err
}
@@ -590,14 +602,12 @@ func (ds *sqlStore) GetCalls(ctx context.Context, filter *models.CallFilter) ([]
}
func (ds *sqlStore) InsertLog(ctx context.Context, callID, callLog string) error {
query := ds.db.Rebind(`INSERT INTO logs (id, log) VALUES (?, ?);`)
_, err := ds.db.Exec(query, callID, callLog)
_, err := ds.db.ExecContext(ctx, ds.insertLogQuery, callID, callLog)
return err
}
func (ds *sqlStore) GetLog(ctx context.Context, callID string) (*models.CallLog, error) {
query := ds.db.Rebind(`SELECT log FROM logs WHERE id=?`)
row := ds.db.QueryRow(query, callID)
row := ds.db.QueryRowContext(ctx, ds.getLogQuery, callID)
var log string
err := row.Scan(&log)
@@ -615,8 +625,7 @@ func (ds *sqlStore) GetLog(ctx context.Context, callID string) (*models.CallLog,
}
func (ds *sqlStore) DeleteLog(ctx context.Context, callID string) error {
query := ds.db.Rebind(`DELETE FROM logs WHERE id=?`)
_, err := ds.db.Exec(query, callID)
_, err := ds.db.ExecContext(ctx, ds.deleteLogQuery, callID)
return err
}