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 { type sqlStore struct {
db *sqlx.DB db *sqlx.DB
insertAppQuery string
// TODO we should prepare all of the statements, rebind them updateAppQuery string
// and store them all here. 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 // 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) { 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.ExecContext(ctx, ds.insertAppQuery, app.Name, string(cbyte))
_, err = ds.db.Exec(query, app.Name, string(cbyte))
if err != nil { if err != nil {
switch err := err.(type) { switch err := err.(type) {
case *mysql.MySQLError: 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) { func (ds *sqlStore) UpdateApp(ctx context.Context, newapp *models.App) (*models.App, error) {
app := &models.App{Name: newapp.Name} app := &models.App{Name: newapp.Name}
err := ds.Tx(func(tx *sqlx.Tx) error { err := ds.Tx(func(tx *sqlx.Tx) error {
query := tx.Rebind(`SELECT config FROM apps WHERE name=?`) row := tx.QueryRowContext(ctx, ds.selectAppConfigQuery, app.Name)
row := tx.QueryRow(query, app.Name)
var config string var config string
if err := row.Scan(&config); err != nil { if err := row.Scan(&config); err != nil {
@@ -197,8 +257,7 @@ func (ds *sqlStore) UpdateApp(ctx context.Context, newapp *models.App) (*models.
return err return err
} }
query = tx.Rebind(`UPDATE apps SET config=? WHERE name=?`) res, err := tx.ExecContext(ctx, ds.updateAppQuery, string(cbyte), app.Name)
res, err := tx.Exec(query, string(cbyte), app.Name)
if err != nil { if err != nil {
return err 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 { func (ds *sqlStore) RemoveApp(ctx context.Context, appName string) error {
query := ds.db.Rebind(`DELETE FROM apps WHERE name = ?`) _, err := ds.db.ExecContext(ctx, ds.removeAppQuery, appName)
_, err := ds.db.Exec(query, appName)
return err return err
} }
func (ds *sqlStore) GetApp(ctx context.Context, name string) (*models.App, error) { 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.QueryRowContext(ctx, ds.getAppQuery, name)
row := ds.db.QueryRow(query, name)
var resName, config string var resName, config string
err := row.Scan(&resName, &config) err := row.Scan(&resName, &config)
@@ -257,7 +314,7 @@ func (ds *sqlStore) GetApps(ctx context.Context, filter *models.AppFilter) ([]*m
res := []*models.App{} res := []*models.App{}
query, args := buildFilterAppQuery(filter) query, args := buildFilterAppQuery(filter)
query = ds.db.Rebind(fmt.Sprintf("SELECT DISTINCT name, config FROM apps %s", query)) 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 { if err != nil {
return nil, err 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 { err = ds.Tx(func(tx *sqlx.Tx) error {
query := tx.Rebind(`SELECT 1 FROM apps WHERE name=?`) r := tx.QueryRowContext(ctx, ds.checkRouteAppQuery, route.AppName)
r := tx.QueryRow(query, route.AppName)
if err := r.Scan(new(int)); err != nil { if err := r.Scan(new(int)); err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return models.ErrAppsNotFound return models.ErrAppsNotFound
} }
} }
query = tx.Rebind(`SELECT 1 FROM routes WHERE app_name=? AND path=?`) same, err := tx.QueryContext(ctx, ds.checkRouteQuery, route.AppName, route.Path)
same, err := tx.Query(query, route.AppName, route.Path)
if err != nil { if err != nil {
return err return err
} }
@@ -311,21 +366,7 @@ func (ds *sqlStore) InsertRoute(ctx context.Context, route *models.Route) (*mode
return models.ErrRoutesAlreadyExists return models.ErrRoutesAlreadyExists
} }
query = tx.Rebind(`INSERT INTO routes ( _, err = tx.ExecContext(ctx, ds.insertRouteQuery,
app_name,
path,
image,
format,
memory,
type,
timeout,
idle_timeout,
headers,
config
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`)
_, err = tx.Exec(query,
route.AppName, route.AppName,
route.Path, route.Path,
route.Image, 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) { func (ds *sqlStore) UpdateRoute(ctx context.Context, newroute *models.Route) (*models.Route, error) {
var route models.Route var route models.Route
err := ds.Tx(func(tx *sqlx.Tx) error { err := ds.Tx(func(tx *sqlx.Tx) error {
query := tx.Rebind(fmt.Sprintf("%s WHERE app_name=? AND path=?", routeSelector)) row := tx.QueryRowContext(ctx, ds.getRouteQuery, newroute.AppName, newroute.Path)
row := tx.QueryRow(query, newroute.AppName, newroute.Path)
if err := scanRoute(row, &route); err == sql.ErrNoRows { if err := scanRoute(row, &route); err == sql.ErrNoRows {
return models.ErrRoutesNotFound return models.ErrRoutesNotFound
} else if err != nil { } else if err != nil {
@@ -367,18 +407,7 @@ func (ds *sqlStore) UpdateRoute(ctx context.Context, newroute *models.Route) (*m
return err return err
} }
query = tx.Rebind(`UPDATE routes SET res, err := tx.ExecContext(ctx, ds.updateAppQuery,
image = ?,
format = ?,
memory = ?,
type = ?,
timeout = ?,
idle_timeout = ?,
headers = ?,
config = ?
WHERE app_name=? AND path=?;`)
res, err := tx.Exec(query,
route.Image, route.Image,
route.Format, route.Format,
route.Memory, 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 { 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.ExecContext(ctx, ds.removeRouteQuery, routePath, appName)
res, err := ds.db.Exec(query, routePath, appName)
if err != nil { if err != nil {
return err 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) { func (ds *sqlStore) GetRoute(ctx context.Context, appName, routePath string) (*models.Route, error) {
rSelectCondition := "%s WHERE app_name=? AND path=?" row := ds.db.QueryRowContext(ctx, ds.getRouteQuery, appName, routePath)
query := ds.db.Rebind(fmt.Sprintf(rSelectCondition, routeSelector))
row := ds.db.QueryRow(query, appName, routePath)
var route models.Route var route models.Route
err := scanRoute(row, &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) { func (ds *sqlStore) GetRoutes(ctx context.Context, filter *models.RouteFilter) ([]*models.Route, error) {
res := []*models.Route{} res := []*models.Route{}
query, args := buildFilterRouteQuery(filter) query, args := buildFilterRouteQuery(filter)
query = fmt.Sprintf("%s %s", routeSelector, query) query = ds.db.Rebind(fmt.Sprintf("%s %s", routeSelector, query))
query = ds.db.Rebind(query) rows, err := ds.db.QueryContext(ctx, query, args...)
rows, err := ds.db.Query(query, args...)
// todo: check for no rows so we don't respond with a sql 500 err // todo: check for no rows so we don't respond with a sql 500 err
if err != nil { if err != nil {
return nil, err 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 := fmt.Sprintf("%s %s", routeSelector, filterQuery)
query = ds.db.Rebind(query) 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 // todo: check for no rows so we don't respond with a sql 500 err
if err != nil { if err != nil {
return nil, err 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 { func (ds *sqlStore) InsertCall(ctx context.Context, call *models.Call) error {
query := ds.db.Rebind(`INSERT INTO calls ( _, err := ds.db.ExecContext(ctx, ds.insertCallQuery, call.ID, call.CreatedAt.String(),
id,
created_at,
started_at,
completed_at,
status,
app_name,
path
)
VALUES (?, ?, ?, ?, ?, ?, ?);`)
_, err := ds.db.Exec(query, call.ID, call.CreatedAt.String(),
call.StartedAt.String(), call.CompletedAt.String(), call.StartedAt.String(), call.CompletedAt.String(),
call.Status, call.AppName, call.Path) call.Status, call.AppName, call.Path)
if err != nil { 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 // 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. // 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) { func (ds *sqlStore) GetCall(ctx context.Context, appName, callID string) (*models.Call, error) {
query := fmt.Sprintf(`%s WHERE id=? AND app_name=?`, callSelector) row := ds.db.QueryRowContext(ctx, ds.getCallQuery, callID, appName)
query = ds.db.Rebind(query)
row := ds.db.QueryRow(query, callID, appName)
var call models.Call var call models.Call
err := scanCall(row, &call) err := scanCall(row, &call)
@@ -569,7 +581,7 @@ func (ds *sqlStore) GetCalls(ctx context.Context, filter *models.CallFilter) ([]
query, args := buildFilterCallQuery(filter) query, args := buildFilterCallQuery(filter)
query = fmt.Sprintf("%s %s", callSelector, query) query = fmt.Sprintf("%s %s", callSelector, query)
query = ds.db.Rebind(query) query = ds.db.Rebind(query)
rows, err := ds.db.Query(query, args...) rows, err := ds.db.QueryContext(ctx, query, args...)
if err != nil { if err != nil {
return nil, err 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 { func (ds *sqlStore) InsertLog(ctx context.Context, callID, callLog string) error {
query := ds.db.Rebind(`INSERT INTO logs (id, log) VALUES (?, ?);`) _, err := ds.db.ExecContext(ctx, ds.insertLogQuery, callID, callLog)
_, err := ds.db.Exec(query, callID, callLog)
return err return err
} }
func (ds *sqlStore) GetLog(ctx context.Context, callID string) (*models.CallLog, error) { 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.QueryRowContext(ctx, ds.getLogQuery, callID)
row := ds.db.QueryRow(query, callID)
var log string var log string
err := row.Scan(&log) 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 { func (ds *sqlStore) DeleteLog(ctx context.Context, callID string) error {
query := ds.db.Rebind(`DELETE FROM logs WHERE id=?`) _, err := ds.db.ExecContext(ctx, ds.deleteLogQuery, callID)
_, err := ds.db.Exec(query, callID)
return err return err
} }