mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
Timestamps on apps / routes (#614)
* route updated_at * add app created at, fix some route updated_at bugs * add app updated_at TODO need to add tests through front end TODO for validation we don't really want to use the validate wrapper since it's a programmer error and not a user error, hopefully tests block this. * add tests for timestamps to exist / change on apps&routes * route equals at done, fix tests wit dis * fix up the equals sugar * add swagger * fix rebase * precisely allocate maps in clone * vetted * meh * fix api tests
This commit is contained in:
@@ -0,0 +1 @@
|
||||
ALTER TABLE routes DROP COLUMN updated_at;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE routes ADD updated_at varchar(256);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE apps DROP COLUMN created_at;
|
||||
1
api/datastore/sql/migrations/5_add_app_created_at.up.sql
Normal file
1
api/datastore/sql/migrations/5_add_app_created_at.up.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE apps ADD created_at varchar(256);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE apps DROP COLUMN updated_at;
|
||||
1
api/datastore/sql/migrations/6_add_app_updated_at.up.sql
Normal file
1
api/datastore/sql/migrations/6_add_app_updated_at.up.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE apps ADD updated_at varchar(256);
|
||||
@@ -6,6 +6,12 @@
|
||||
// 2_add_call_stats.up.sql
|
||||
// 3_add_call_error.down.sql
|
||||
// 3_add_call_error.up.sql
|
||||
// 4_add_route_updated_at.down.sql
|
||||
// 4_add_route_updated_at.up.sql
|
||||
// 5_add_app_created_at.down.sql
|
||||
// 5_add_app_created_at.up.sql
|
||||
// 6_add_app_updated_at.down.sql
|
||||
// 6_add_app_updated_at.up.sql
|
||||
// DO NOT EDIT!
|
||||
|
||||
package migrations
|
||||
@@ -108,7 +114,7 @@ func _1_add_route_created_atUpSql() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "1_add_route_created_at.up.sql", size: 40, mode: os.FileMode(420), modTime: time.Unix(1511259011, 0)}
|
||||
info := bindataFileInfo{name: "1_add_route_created_at.up.sql", size: 40, mode: os.FileMode(420), modTime: time.Unix(1511919777, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -168,7 +174,7 @@ func _3_add_call_errorDownSql() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "3_add_call_error.down.sql", size: 37, mode: os.FileMode(420), modTime: time.Unix(1511265731, 0)}
|
||||
info := bindataFileInfo{name: "3_add_call_error.down.sql", size: 37, mode: os.FileMode(420), modTime: time.Unix(1511301534, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -188,7 +194,127 @@ func _3_add_call_errorUpSql() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "3_add_call_error.up.sql", size: 34, mode: os.FileMode(420), modTime: time.Unix(1511265909, 0)}
|
||||
info := bindataFileInfo{name: "3_add_call_error.up.sql", size: 34, mode: os.FileMode(420), modTime: time.Unix(1511301534, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var __4_add_route_updated_atDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x28\xca\x2f\x2d\x49\x2d\x56\x70\x09\xf2\x0f\x50\x70\xf6\xf7\x09\xf5\xf5\x53\x28\x2d\x48\x49\x2c\x49\x4d\x89\x4f\x2c\xb1\xe6\x02\x04\x00\x00\xff\xff\xa4\x67\xb0\xea\x2b\x00\x00\x00")
|
||||
|
||||
func _4_add_route_updated_atDownSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__4_add_route_updated_atDownSql,
|
||||
"4_add_route_updated_at.down.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _4_add_route_updated_atDownSql() (*asset, error) {
|
||||
bytes, err := _4_add_route_updated_atDownSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "4_add_route_updated_at.down.sql", size: 43, mode: os.FileMode(420), modTime: time.Unix(1513728957, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var __4_add_route_updated_atUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x28\xca\x2f\x2d\x49\x2d\x56\x70\x74\x71\x51\x28\x2d\x48\x49\x2c\x49\x4d\x89\x4f\x2c\x51\x28\x4b\x2c\x4a\xce\x48\x2c\xd2\x30\x32\x35\xd3\xb4\xe6\x02\x04\x00\x00\xff\xff\x54\xf7\xac\x11\x30\x00\x00\x00")
|
||||
|
||||
func _4_add_route_updated_atUpSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__4_add_route_updated_atUpSql,
|
||||
"4_add_route_updated_at.up.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _4_add_route_updated_atUpSql() (*asset, error) {
|
||||
bytes, err := _4_add_route_updated_atUpSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "4_add_route_updated_at.up.sql", size: 48, mode: os.FileMode(420), modTime: time.Unix(1513730369, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var __5_add_app_created_atDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\x2c\x28\x28\x56\x70\x09\xf2\x0f\x50\x70\xf6\xf7\x09\xf5\xf5\x53\x48\x2e\x4a\x4d\x2c\x49\x4d\x89\x4f\x2c\xb1\xe6\x02\x04\x00\x00\xff\xff\xd2\xde\x5c\x98\x29\x00\x00\x00")
|
||||
|
||||
func _5_add_app_created_atDownSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__5_add_app_created_atDownSql,
|
||||
"5_add_app_created_at.down.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _5_add_app_created_atDownSql() (*asset, error) {
|
||||
bytes, err := _5_add_app_created_atDownSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "5_add_app_created_at.down.sql", size: 41, mode: os.FileMode(420), modTime: time.Unix(1513730497, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var __5_add_app_created_atUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\x2c\x28\x28\x56\x70\x74\x71\x51\x48\x2e\x4a\x4d\x2c\x49\x4d\x89\x4f\x2c\x51\x28\x4b\x2c\x4a\xce\x48\x2c\xd2\x30\x32\x35\xd3\xb4\xe6\x02\x04\x00\x00\xff\xff\x76\x6c\x0f\x45\x2e\x00\x00\x00")
|
||||
|
||||
func _5_add_app_created_atUpSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__5_add_app_created_atUpSql,
|
||||
"5_add_app_created_at.up.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _5_add_app_created_atUpSql() (*asset, error) {
|
||||
bytes, err := _5_add_app_created_atUpSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "5_add_app_created_at.up.sql", size: 46, mode: os.FileMode(420), modTime: time.Unix(1513730527, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var __6_add_app_updated_atDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\x2c\x28\x28\x56\x70\x09\xf2\x0f\x50\x70\xf6\xf7\x09\xf5\xf5\x53\x28\x2d\x48\x49\x2c\x49\x4d\x89\x4f\x2c\xb1\xe6\x02\x04\x00\x00\xff\xff\x31\x44\xd7\xcc\x29\x00\x00\x00")
|
||||
|
||||
func _6_add_app_updated_atDownSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__6_add_app_updated_atDownSql,
|
||||
"6_add_app_updated_at.down.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _6_add_app_updated_atDownSql() (*asset, error) {
|
||||
bytes, err := _6_add_app_updated_atDownSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "6_add_app_updated_at.down.sql", size: 41, mode: os.FileMode(420), modTime: time.Unix(1513733616, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var __6_add_app_updated_atUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\xf4\x09\x71\x0d\x52\x08\x71\x74\xf2\x71\x55\x48\x2c\x28\x28\x56\x70\x74\x71\x51\x28\x2d\x48\x49\x2c\x49\x4d\x89\x4f\x2c\x51\x28\x4b\x2c\x4a\xce\x48\x2c\xd2\x30\x32\x35\xd3\xb4\xe6\x02\x04\x00\x00\xff\xff\x65\x01\x8b\x34\x2e\x00\x00\x00")
|
||||
|
||||
func _6_add_app_updated_atUpSqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
__6_add_app_updated_atUpSql,
|
||||
"6_add_app_updated_at.up.sql",
|
||||
)
|
||||
}
|
||||
|
||||
func _6_add_app_updated_atUpSql() (*asset, error) {
|
||||
bytes, err := _6_add_app_updated_atUpSqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "6_add_app_updated_at.up.sql", size: 46, mode: os.FileMode(420), modTime: time.Unix(1513733621, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@@ -251,6 +377,12 @@ var _bindata = map[string]func() (*asset, error){
|
||||
"2_add_call_stats.up.sql": _2_add_call_statsUpSql,
|
||||
"3_add_call_error.down.sql": _3_add_call_errorDownSql,
|
||||
"3_add_call_error.up.sql": _3_add_call_errorUpSql,
|
||||
"4_add_route_updated_at.down.sql": _4_add_route_updated_atDownSql,
|
||||
"4_add_route_updated_at.up.sql": _4_add_route_updated_atUpSql,
|
||||
"5_add_app_created_at.down.sql": _5_add_app_created_atDownSql,
|
||||
"5_add_app_created_at.up.sql": _5_add_app_created_atUpSql,
|
||||
"6_add_app_updated_at.down.sql": _6_add_app_updated_atDownSql,
|
||||
"6_add_app_updated_at.up.sql": _6_add_app_updated_atUpSql,
|
||||
}
|
||||
|
||||
// AssetDir returns the file names below a certain
|
||||
@@ -300,6 +432,12 @@ var _bintree = &bintree{nil, map[string]*bintree{
|
||||
"2_add_call_stats.up.sql": &bintree{_2_add_call_statsUpSql, map[string]*bintree{}},
|
||||
"3_add_call_error.down.sql": &bintree{_3_add_call_errorDownSql, map[string]*bintree{}},
|
||||
"3_add_call_error.up.sql": &bintree{_3_add_call_errorUpSql, map[string]*bintree{}},
|
||||
"4_add_route_updated_at.down.sql": &bintree{_4_add_route_updated_atDownSql, map[string]*bintree{}},
|
||||
"4_add_route_updated_at.up.sql": &bintree{_4_add_route_updated_atUpSql, map[string]*bintree{}},
|
||||
"5_add_app_created_at.down.sql": &bintree{_5_add_app_created_atDownSql, map[string]*bintree{}},
|
||||
"5_add_app_created_at.up.sql": &bintree{_5_add_app_created_atUpSql, map[string]*bintree{}},
|
||||
"6_add_app_updated_at.down.sql": &bintree{_6_add_app_updated_atDownSql, map[string]*bintree{}},
|
||||
"6_add_app_updated_at.up.sql": &bintree{_6_add_app_updated_atUpSql, map[string]*bintree{}},
|
||||
}}
|
||||
|
||||
// RestoreAsset restores an asset under the given directory
|
||||
|
||||
@@ -37,6 +37,11 @@ import (
|
||||
//
|
||||
// currently tested and working are postgres, mysql and sqlite3.
|
||||
|
||||
// TODO routes.created_at should be varchar(256), mysql will store 'text'
|
||||
// fields not contiguous with other fields and this field is a fixed size,
|
||||
// we'll get better locality with varchar. it's not terribly easy to do this
|
||||
// with migrations (sadly, need complex transaction)
|
||||
|
||||
var tables = [...]string{`CREATE TABLE IF NOT EXISTS routes (
|
||||
app_name varchar(256) NOT NULL,
|
||||
path varchar(256) NOT NULL,
|
||||
@@ -49,12 +54,15 @@ var tables = [...]string{`CREATE TABLE IF NOT EXISTS routes (
|
||||
headers text NOT NULL,
|
||||
config text NOT NULL,
|
||||
created_at text,
|
||||
updated_at varchar(256),
|
||||
PRIMARY KEY (app_name, path)
|
||||
);`,
|
||||
|
||||
`CREATE TABLE IF NOT EXISTS apps (
|
||||
name varchar(256) NOT NULL PRIMARY KEY,
|
||||
config text NOT NULL
|
||||
config text NOT NULL,
|
||||
created_at varchar(256),
|
||||
updated_at varchar(256)
|
||||
);`,
|
||||
|
||||
`CREATE TABLE IF NOT EXISTS calls (
|
||||
@@ -78,7 +86,7 @@ var tables = [...]string{`CREATE TABLE IF NOT EXISTS routes (
|
||||
}
|
||||
|
||||
const (
|
||||
routeSelector = `SELECT app_name, path, image, format, memory, type, timeout, idle_timeout, headers, config, created_at FROM routes`
|
||||
routeSelector = `SELECT app_name, path, image, format, memory, type, timeout, idle_timeout, headers, config, created_at, updated_at FROM routes`
|
||||
callSelector = `SELECT id, created_at, started_at, completed_at, status, app_name, path, stats, error FROM calls`
|
||||
)
|
||||
|
||||
@@ -255,7 +263,18 @@ func (ds *sqlStore) clear() error {
|
||||
}
|
||||
|
||||
func (ds *sqlStore) InsertApp(ctx context.Context, app *models.App) (*models.App, error) {
|
||||
query := ds.db.Rebind("INSERT INTO apps (name, config) VALUES (:name, :config);")
|
||||
query := ds.db.Rebind(`INSERT INTO apps (
|
||||
name,
|
||||
config,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
VALUES (
|
||||
:name,
|
||||
:config,
|
||||
:created_at,
|
||||
:updated_at
|
||||
);`)
|
||||
_, err := ds.db.NamedExecContext(ctx, query, app)
|
||||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
@@ -281,7 +300,9 @@ 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=?`)
|
||||
// NOTE: must query whole object since we're returning app, Update logic
|
||||
// must only modify modifiable fields (as seen here). need to fix brittle..
|
||||
query := tx.Rebind(`SELECT name, config, created_at, updated_at FROM apps WHERE name=?`)
|
||||
row := tx.QueryRowxContext(ctx, query, app.Name)
|
||||
|
||||
err := row.StructScan(app)
|
||||
@@ -291,9 +312,9 @@ func (ds *sqlStore) UpdateApp(ctx context.Context, newapp *models.App) (*models.
|
||||
return err
|
||||
}
|
||||
|
||||
app.UpdateConfig(newapp.Config)
|
||||
app.Update(newapp)
|
||||
|
||||
query = tx.Rebind(`UPDATE apps SET config=:config WHERE name=:name`)
|
||||
query = tx.Rebind(`UPDATE apps SET config=:config, updated_at=:updated_at WHERE name=:name`)
|
||||
res, err := tx.NamedExecContext(ctx, query, app)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -346,7 +367,7 @@ func (ds *sqlStore) RemoveApp(ctx context.Context, appName string) error {
|
||||
}
|
||||
|
||||
func (ds *sqlStore) GetApp(ctx context.Context, name string) (*models.App, error) {
|
||||
query := ds.db.Rebind(`SELECT name, config FROM apps WHERE name=?`)
|
||||
query := ds.db.Rebind(`SELECT name, config, created_at, updated_at FROM apps WHERE name=?`)
|
||||
row := ds.db.QueryRowxContext(ctx, query, name)
|
||||
|
||||
var res models.App
|
||||
@@ -369,10 +390,7 @@ func (ds *sqlStore) GetApps(ctx context.Context, filter *models.AppFilter) ([]*m
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// fmt.Printf("QUERY: %v\n", query)
|
||||
// fmt.Printf("ARGS: %v\n", args)
|
||||
// hmm, should this have DISTINCT in it? shouldn't be possible to have two apps with same name
|
||||
query = ds.db.Rebind(fmt.Sprintf("SELECT DISTINCT name, config FROM apps %s", query))
|
||||
query = ds.db.Rebind(fmt.Sprintf("SELECT DISTINCT name, config, created_at, updated_at FROM apps %s", query))
|
||||
rows, err := ds.db.QueryxContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -427,7 +445,8 @@ func (ds *sqlStore) InsertRoute(ctx context.Context, route *models.Route) (*mode
|
||||
idle_timeout,
|
||||
headers,
|
||||
config,
|
||||
created_at
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
VALUES (
|
||||
:app_name,
|
||||
@@ -440,7 +459,8 @@ func (ds *sqlStore) InsertRoute(ctx context.Context, route *models.Route) (*mode
|
||||
:idle_timeout,
|
||||
:headers,
|
||||
:config,
|
||||
:created_at
|
||||
:created_at,
|
||||
:updated_at
|
||||
);`)
|
||||
|
||||
_, err = tx.NamedExecContext(ctx, query, route)
|
||||
@@ -479,7 +499,7 @@ func (ds *sqlStore) UpdateRoute(ctx context.Context, newroute *models.Route) (*m
|
||||
idle_timeout = :idle_timeout,
|
||||
headers = :headers,
|
||||
config = :config,
|
||||
created_at = :created_at
|
||||
updated_at = :updated_at
|
||||
WHERE app_name=:app_name AND path=:path;`)
|
||||
|
||||
res, err := tx.NamedExecContext(ctx, query, &route)
|
||||
|
||||
Reference in New Issue
Block a user