From 8d022e1930a3c233771f1e9f606504a0b37edd97 Mon Sep 17 00:00:00 2001 From: Helmut Merz Date: Sun, 24 Mar 2024 19:13:10 +0100 Subject: [PATCH] more on SQL templates - create table 'tracks', with DB-specific parameters --- storage/db/pgsql/pgsql.go | 5 +++++ storage/storage.go | 12 +++++++++++- storage/tracking/sql_code.go | 35 +++++++++++++++++++++++++++-------- storage/tracking/tracking.go | 34 +++++++++++++++++++++------------- tests/storage_test.go | 14 ++++++++------ 5 files changed, 72 insertions(+), 28 deletions(-) diff --git a/storage/db/pgsql/pgsql.go b/storage/db/pgsql/pgsql.go index 614841c..3d503f7 100644 --- a/storage/db/pgsql/pgsql.go +++ b/storage/db/pgsql/pgsql.go @@ -5,3 +5,8 @@ package pgsql import ( _ "github.com/lib/pq" ) + +const ( + IdType = "bigserial" + JsonType = "jsonb default '{}'::jsonb" +) diff --git a/storage/storage.go b/storage/storage.go index 55bb939..7d4ad6b 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -18,6 +18,8 @@ type Cfg struct { type Storage struct { *sql.DB *Cfg + Schema string + Params map[string]string Sql *template.Template Errors []error } @@ -46,7 +48,12 @@ func Open(cfg *Cfg) *Storage { log.Error(err).Msg("sql.Open") 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) return &storage } @@ -118,6 +125,9 @@ func (db *Storage) Exec(q string, args ...interface{}) (int64, 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)) return err } diff --git a/storage/tracking/sql_code.go b/storage/tracking/sql_code.go index d2a4bbc..dbdf1de 100644 --- a/storage/tracking/sql_code.go +++ b/storage/tracking/sql_code.go @@ -1,17 +1,36 @@ package tracking -const sql_table = ` -{{- $tablename := .tablename -}} -create table {{ $tablename }} ( - trackid {{ .idType }} primary key, - {{ range .headFields -}}{{ . }} text, +const ( + sql_table = ` +{{- $tablename := or (and .schema (printf "%s.%s" .schema .tablename)) .tablename -}} +{{- $json := or .jsonType "json" -}} +create table if not exists {{ $tablename }} ( + trackid {{ or .idType "integer" }} primary key, + {{ range .headFields -}}{{ ToLower . }} text default '', {{ end -}} timestamp timestamptz default current_timestamp, - data {{ .jsonType -}} + data {{ $json }} ); {{- 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 }} -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 -}}) +` +) diff --git a/storage/tracking/tracking.go b/storage/tracking/tracking.go index 926b1e8..cdc8b9a 100644 --- a/storage/tracking/tracking.go +++ b/storage/tracking/tracking.go @@ -5,6 +5,7 @@ package tracking import ( "fmt" "strings" + "text/template" "time" lib "git.sr.ht/~cco/go-scopes" @@ -21,31 +22,40 @@ type track struct { type container struct { headFields []string - indexes []string + indexes [][]string storage *sql.Storage } func Container(db *sql.Storage) *container { return &container{ headFields: []string{"taskId", "userName"}, - //indexes: [][]string{[]string{"taskId", "userName"}, []string{"userName"}}, - indexes: []string{"taskid, username", "username"}, - storage: db, + indexes: [][]string{[]string{"taskId", "userName"}, []string{"userName"}}, + storage: db, } } func Create(cont *container) *container { 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 data := map[string]interface{}{ + "schema": db.Schema, "tablename": "tracks", "headFields": cont.headFields, "indexes": cont.indexes, - "idType": "integer", - "jsonType": "json", + "idType": db.Params["idType"], + "jsonType": db.Params["jsonType"], } - err := t.Execute(&out, data) + err = t.Execute(&out, data) if err != nil { db.LogErr(err, "storage.tracking.Create", fmt.Sprintf("%+v", t)) return nil @@ -53,10 +63,8 @@ func Create(cont *container) *container { sql := out.String() println(sql) _, err = db.Exec(sql) - if err != nil { - println(err) - db.LogErr(err, "storage.tracking.Create", fmt.Sprintf("%+v", t)) - return nil + if err == nil { + return cont } - return cont + return nil } diff --git a/tests/storage_test.go b/tests/storage_test.go index 6e420d1..0921695 100644 --- a/tests/storage_test.go +++ b/tests/storage_test.go @@ -6,7 +6,7 @@ import ( "git.sr.ht/~cco/go-scopes/common/testing" "git.sr.ht/~cco/go-scopes/core/message" 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" msgstore "git.sr.ht/~cco/go-scopes/storage/message" "git.sr.ht/~cco/go-scopes/storage/tracking" @@ -25,6 +25,8 @@ func TestPgsql(tb *tbase.T) { t := testing.SetUp(tb) cfg := etc.ConfigPgsql() db := sql.Open(cfg) + db.Params["idType"] = pgsql.IdType + db.Params["jsonType"] = pgsql.JsonType resetPgsql(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") } -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) { cont := tracking.Container(db) 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) { db.DropTable("test") db.DropTable("tracks")