more on SQL templates - create table 'tracks', with DB-specific parameters

This commit is contained in:
Helmut Merz 2024-03-24 19:13:10 +01:00
parent 0202727990
commit 8d022e1930
5 changed files with 72 additions and 28 deletions

View file

@ -5,3 +5,8 @@ package pgsql
import ( import (
_ "github.com/lib/pq" _ "github.com/lib/pq"
) )
const (
IdType = "bigserial"
JsonType = "jsonb default '{}'::jsonb"
)

View file

@ -18,6 +18,8 @@ type Cfg struct {
type Storage struct { type Storage struct {
*sql.DB *sql.DB
*Cfg *Cfg
Schema string
Params map[string]string
Sql *template.Template Sql *template.Template
Errors []error Errors []error
} }
@ -46,7 +48,12 @@ func Open(cfg *Cfg) *Storage {
log.Error(err).Msg("sql.Open") log.Error(err).Msg("sql.Open")
return nil return nil
} }
storage := Storage{DB: db, Cfg: cfg} storage := Storage{
DB: db,
Cfg: cfg,
Schema: cfg.Schema,
Params: map[string]string{},
}
storage.Sql = storage.ParseTemplate(SqlSources) storage.Sql = storage.ParseTemplate(SqlSources)
return &storage return &storage
} }
@ -118,6 +125,9 @@ func (db *Storage) Exec(q string, args ...interface{}) (int64, error) {
} }
func (db *Storage) DropTable(tn string) error { func (db *Storage) DropTable(tn string) error {
//if db.Schema != "" {
// tn = fmt.Sprintf("%s.%s", db.Schema, tn)
//}
_, err := db.Exec(fmt.Sprintf(sql_drop, tn)) _, err := db.Exec(fmt.Sprintf(sql_drop, tn))
return err return err
} }

View file

@ -1,17 +1,36 @@
package tracking package tracking
const sql_table = ` const (
{{- $tablename := .tablename -}} sql_table = `
create table {{ $tablename }} ( {{- $tablename := or (and .schema (printf "%s.%s" .schema .tablename)) .tablename -}}
trackid {{ .idType }} primary key, {{- $json := or .jsonType "json" -}}
{{ range .headFields -}}{{ . }} text, create table if not exists {{ $tablename }} (
trackid {{ or .idType "integer" }} primary key,
{{ range .headFields -}}{{ ToLower . }} text default '',
{{ end -}} {{ end -}}
timestamp timestamptz default current_timestamp, timestamp timestamptz default current_timestamp,
data {{ .jsonType -}} data {{ $json }}
); );
{{- range $i, $cols := .indexes }} {{- range $i, $cols := .indexes }}
create index idx_{{ $i }} on {{ $tablename }} ({{ $cols }}); create index idx_{{ $.tablename }}_{{ Add1 $i }} on {{ $tablename }} (
{{- range $j, $c := $cols -}}
{{- if ne $j 0 -}}, {{ end }}{{ ToLower $c }}
{{- end -}}
);
{{- end }} {{- end }}
create index idx_timestamp on {{ .tablename }} (timestamp); create index idx_{{ $.tablename }}_ts on {{ $tablename }} (timestamp);
` `
sql_insert = `
{{- $tablename := or (and .schema (printf "%s.%s" .schema .tablename)) .tablename -}}
insert into {{ $tablename }} (
{{- range $j, $c := .columns -}}
{{- if ne $j 0 -}}, {{ end }}{{ ToLower $c }}
{{- end -}})
values (
{{- range $j, $c := .columns -}}
{{- if ne $j 0 -}}, {{ end }}${{ $j }}
{{- end -}})
`
)

View file

@ -5,6 +5,7 @@ package tracking
import ( import (
"fmt" "fmt"
"strings" "strings"
"text/template"
"time" "time"
lib "git.sr.ht/~cco/go-scopes" lib "git.sr.ht/~cco/go-scopes"
@ -21,31 +22,40 @@ type track struct {
type container struct { type container struct {
headFields []string headFields []string
indexes []string indexes [][]string
storage *sql.Storage storage *sql.Storage
} }
func Container(db *sql.Storage) *container { func Container(db *sql.Storage) *container {
return &container{ return &container{
headFields: []string{"taskId", "userName"}, headFields: []string{"taskId", "userName"},
//indexes: [][]string{[]string{"taskId", "userName"}, []string{"userName"}}, indexes: [][]string{[]string{"taskId", "userName"}, []string{"userName"}},
indexes: []string{"taskid, username", "username"}, storage: db,
storage: db,
} }
} }
func Create(cont *container) *container { func Create(cont *container) *container {
db := cont.storage db := cont.storage
t := db.ParseTemplate(sql_table) t := template.New("create_table")
t = t.Funcs(map[string]any{
"ToLower": strings.ToLower,
"Add1": func(i int) int { return i + 1 },
})
t, err := t.Parse(sql_table)
if err != nil {
db.LogErr(err, "storage.tracking.Create", fmt.Sprintf("%+v", t))
return nil
}
var out strings.Builder var out strings.Builder
data := map[string]interface{}{ data := map[string]interface{}{
"schema": db.Schema,
"tablename": "tracks", "tablename": "tracks",
"headFields": cont.headFields, "headFields": cont.headFields,
"indexes": cont.indexes, "indexes": cont.indexes,
"idType": "integer", "idType": db.Params["idType"],
"jsonType": "json", "jsonType": db.Params["jsonType"],
} }
err := t.Execute(&out, data) err = t.Execute(&out, data)
if err != nil { if err != nil {
db.LogErr(err, "storage.tracking.Create", fmt.Sprintf("%+v", t)) db.LogErr(err, "storage.tracking.Create", fmt.Sprintf("%+v", t))
return nil return nil
@ -53,10 +63,8 @@ func Create(cont *container) *container {
sql := out.String() sql := out.String()
println(sql) println(sql)
_, err = db.Exec(sql) _, err = db.Exec(sql)
if err != nil { if err == nil {
println(err) return cont
db.LogErr(err, "storage.tracking.Create", fmt.Sprintf("%+v", t))
return nil
} }
return cont return nil
} }

View file

@ -6,7 +6,7 @@ import (
"git.sr.ht/~cco/go-scopes/common/testing" "git.sr.ht/~cco/go-scopes/common/testing"
"git.sr.ht/~cco/go-scopes/core/message" "git.sr.ht/~cco/go-scopes/core/message"
sql "git.sr.ht/~cco/go-scopes/storage" sql "git.sr.ht/~cco/go-scopes/storage"
_ "git.sr.ht/~cco/go-scopes/storage/db/pgsql" "git.sr.ht/~cco/go-scopes/storage/db/pgsql"
_ "git.sr.ht/~cco/go-scopes/storage/db/sqlite" _ "git.sr.ht/~cco/go-scopes/storage/db/sqlite"
msgstore "git.sr.ht/~cco/go-scopes/storage/message" msgstore "git.sr.ht/~cco/go-scopes/storage/message"
"git.sr.ht/~cco/go-scopes/storage/tracking" "git.sr.ht/~cco/go-scopes/storage/tracking"
@ -25,6 +25,8 @@ func TestPgsql(tb *tbase.T) {
t := testing.SetUp(tb) t := testing.SetUp(tb)
cfg := etc.ConfigPgsql() cfg := etc.ConfigPgsql()
db := sql.Open(cfg) db := sql.Open(cfg)
db.Params["idType"] = pgsql.IdType
db.Params["jsonType"] = pgsql.JsonType
resetPgsql(db) resetPgsql(db)
DoTests(t, cfg, db) DoTests(t, cfg, db)
} }
@ -62,16 +64,16 @@ func BaseTest(t *testing.T, cfg *sql.Cfg, db *sql.Storage) {
t.AssertEqual(data[1].label, "Good Afternoon") t.AssertEqual(data[1].label, "Good Afternoon")
} }
func MessageTest(t *testing.T, cfg *sql.Cfg, db *sql.Storage) {
msg := message.SimpleMessage("data")
msgstore.StoreDB(db, msg)
}
func TrackingTest(t *testing.T, cfg *sql.Cfg, db *sql.Storage) { func TrackingTest(t *testing.T, cfg *sql.Cfg, db *sql.Storage) {
cont := tracking.Container(db) cont := tracking.Container(db)
tracking.Create(cont) tracking.Create(cont)
} }
func MessageTest(t *testing.T, cfg *sql.Cfg, db *sql.Storage) {
msg := message.SimpleMessage("data")
msgstore.StoreDB(db, msg)
}
func resetSqlite(db *sql.Storage) { func resetSqlite(db *sql.Storage) {
db.DropTable("test") db.DropTable("test")
db.DropTable("tracks") db.DropTable("tracks")