Db service fixes and improvements: dot access, truncate table etc (#157)

This commit is contained in:
Janos Dobronszki
2021-06-14 12:32:38 +01:00
committed by GitHub
parent 917d4f2d3f
commit e4be18434c
6 changed files with 324 additions and 70 deletions

View File

@@ -22,6 +22,7 @@ import (
const idKey = "id"
const stmt = "create table if not exists %v(id text not null, data jsonb, primary key(id)); alter table %v add created_at timestamptz; alter table %v add updated_at timestamptz"
const truncateStmt = `truncate table "%v"`
var re = regexp.MustCompile("^[a-zA-Z0-9_]*$")
var c = cache.New(5*time.Minute, 10*time.Minute)
@@ -39,6 +40,23 @@ type Db struct {
gorm2.Helper
}
func correctFieldName(s string) string {
switch s {
// top level fields can stay top level
case "id": // "created_at", "updated_at", <-- these are not special fields for now
return s
}
if !strings.Contains(s, ".") {
return fmt.Sprintf("data ->> '%v'", s)
}
paths := strings.Split(s, ".")
ret := "data"
for _, path := range paths {
ret += fmt.Sprintf(" ->> '%v'", path)
}
return ret
}
// Call is a single request handler called via client.Call or the generated client code
func (e *Db) Create(ctx context.Context, req *db.CreateRequest, rsp *db.CreateResponse) error {
if len(req.Record.AsMap()) == 0 {
@@ -208,13 +226,28 @@ func (e *Db) Read(ctx context.Context, req *db.ReadRequest, rsp *db.ReadResponse
case itemNotEquals:
op = "!="
}
db = db.Where(fmt.Sprintf("(data ->> '%v')::%v %v ?", query.Field, typ, op), query.Value)
queryField := correctFieldName(query.Field)
db = db.Where(fmt.Sprintf("(%v)::%v %v ?", queryField, typ, op), query.Value)
}
orderField := "created_at DESC"
orderField := "created_at"
if req.OrderBy != "" {
orderField = req.OrderBy + " " + req.Order
orderField = req.OrderBy
}
db = db.Order(orderField).Offset(int(req.Offset)).Limit(int(req.Limit))
orderField = correctFieldName(orderField)
ordering := "asc"
if req.Order != "" {
switch strings.ToLower(req.Order) {
case "asc":
ordering = "asc"
case "", "desc":
ordering = "desc"
default:
return errors.BadRequest("db.read", "invalid ordering: "+req.Order)
}
}
db = db.Order(orderField + " " + ordering).Offset(int(req.Offset)).Limit(int(req.Limit))
err = db.Find(&recs).Error
if err != nil {
return err
@@ -269,3 +302,25 @@ func (e *Db) Delete(ctx context.Context, req *db.DeleteRequest, rsp *db.DeleteRe
ID: req.Id,
}).Error
}
func (e *Db) Truncate(ctx context.Context, req *db.TruncateRequest, rsp *db.TruncateResponse) error {
tenantId, ok := tenant.FromContext(ctx)
if !ok {
tenantId = "micro"
}
if req.Table == "" {
req.Table = "default"
}
tenantId = strings.Replace(strings.Replace(tenantId, "/", "_", -1), "-", "_", -1)
tableName := tenantId + "_" + req.Table
if !re.Match([]byte(tableName)) {
return errors.BadRequest("db.create", fmt.Sprintf("table name %v is invalid", req.Table))
}
logger.Infof("Truncating table '%v'", tableName)
db, err := e.GetDBConn(ctx)
if err != nil {
return err
}
return db.Exec(fmt.Sprintf(truncateStmt, tableName)).Error
}