diff --git a/store/mysql/upgrade.go b/store/mysql/upgrade.go index 47fdc9b8c..39d3ac529 100644 --- a/store/mysql/upgrade.go +++ b/store/mysql/upgrade.go @@ -7,6 +7,7 @@ import ( "context" "database/sql" "fmt" + "github.com/cortezaproject/corteza-server/store/rdbms" "github.com/cortezaproject/corteza-server/store/rdbms/ddl" _ "github.com/go-sql-driver/mysql" @@ -38,6 +39,17 @@ func NewUpgrader(log *zap.Logger, store *Store) *upgrader { `{{ if not .Condition }}CREATE {{ if .Unique }}UNIQUE {{ end }}INDEX {{ template "index-name" . }} ON {{ .Table }} {{ template "index-fields" .Fields }}{{ else }}SELECT 1 -- dummy sql, just to prevent "empty query" errors...{{ end }}`, ) + u.ddl.AddTemplate("index-fields", ` +({{ range $n, $f := . -}} + {{ if $n }}, {{ end }} + {{- if .Expr}}({{ end }} + {{- .Field }} + {{- if .Length}}({{ .Length }}){{ end }} + {{- if .Expr}}){{ end }} + {{- if .Desc }} DESC{{ end }} +{{- end }}) +`) + // Cover mysql exceptions u.ddl.AddTemplateFunc("columnType", func(ct *ddl.ColumnType) string { switch ct.Type { @@ -306,6 +318,26 @@ func (u upgrader) AddPrimaryKey(ctx context.Context, table string, ind *ddl.Inde return true, nil } +func (u upgrader) CreateIndex(ctx context.Context, ind *ddl.Index) (added bool, err error) { + if added, err = u.hasIndex(ctx, ind.Table, ind.Name); added || err != nil { + return + } + + if err = u.Exec(ctx, u.ddl.CreateIndex(ind)); err != nil { + return false, fmt.Errorf("could not create index on table %s: %w", ind.Table, err) + } + + return true, nil +} + +func (u upgrader) hasIndex(ctx context.Context, table, name string) (has bool, err error) { + var ( + lookup = "SELECT COUNT(*) > 0 FROM information_schema.statistics where table_schema = ? AND table_name = ? AND index_name = ?" + ) + + return has, u.s.DB().GetContext(ctx, &has, lookup, u.s.Config().DBName, table, table+"_"+name) +} + // loads and returns all tables columns func (u upgrader) getColumns(ctx context.Context, table string) (out ddl.Columns, err error) { type ( diff --git a/store/postgres/upgrade.go b/store/postgres/upgrade.go index a39a60efe..0e804b491 100644 --- a/store/postgres/upgrade.go +++ b/store/postgres/upgrade.go @@ -6,6 +6,7 @@ package postgres import ( "context" "fmt" + "github.com/cortezaproject/corteza-server/store/rdbms" "github.com/cortezaproject/corteza-server/store/rdbms/ddl" "go.uber.org/zap" @@ -27,7 +28,6 @@ func NewUpgrader(log *zap.Logger, store *Store) *upgrader { // to properly support PostgreSQL dialect g.ddl.AddTemplate("create-table-suffix", "WITHOUT OIDS") - return g } @@ -216,6 +216,26 @@ func (u upgrader) AddPrimaryKey(ctx context.Context, table string, ind *ddl.Inde return true, nil } +func (u upgrader) CreateIndex(ctx context.Context, ind *ddl.Index) (added bool, err error) { + if added, err = u.hasIndex(ctx, ind.Table, ind.Name); added || err != nil { + return + } + + if err = u.Exec(ctx, u.ddl.CreateIndex(ind)); err != nil { + return false, fmt.Errorf("could not create index on table %s: %w", ind.Table, err) + } + + return true, nil +} + +func (u upgrader) hasIndex(ctx context.Context, table, name string) (has bool, err error) { + var ( + lookup = "SELECT COUNT(*) > 0 FROM pg_indexes WHERE tablename = $1 AND indexname = $2" + ) + + return has, u.s.DB().GetContext(ctx, &has, lookup, table, table+"_"+name) +} + // loads and returns all tables columns func (u upgrader) getColumns(ctx context.Context, table string) (out ddl.Columns, err error) { type ( diff --git a/store/rdbms/ddl/def.go b/store/rdbms/ddl/def.go index 336f811ac..56f0f26bd 100644 --- a/store/rdbms/ddl/def.go +++ b/store/rdbms/ddl/def.go @@ -31,6 +31,8 @@ type ( // Expression or a single column Field string + Length int + // Wrap part in parenthesis Expr bool @@ -206,6 +208,15 @@ func IColumn(cc ...string) indexManipulator { } } +// IColumn adds one or more keys as columns +func IFieldFull(ff ...*IField) indexManipulator { + return func(i *Index) { + for _, f := range ff { + i.Fields = append(i.Fields, f) + } + } +} + // IExpr adds one or more keys as expressions func IExpr(ee ...string) indexManipulator { return func(i *Index) { diff --git a/store/rdbms/ddl/gen.go b/store/rdbms/ddl/gen.go index 38aef5924..7b1b62700 100644 --- a/store/rdbms/ddl/gen.go +++ b/store/rdbms/ddl/gen.go @@ -3,10 +3,11 @@ package ddl import ( "bytes" "fmt" - "go.uber.org/zap" "regexp" "strings" "text/template" + + "go.uber.org/zap" ) type ( diff --git a/store/sqlite3/upgrade.go b/store/sqlite3/upgrade.go index 8b659b307..a6e7e89b9 100644 --- a/store/sqlite3/upgrade.go +++ b/store/sqlite3/upgrade.go @@ -7,6 +7,7 @@ import ( "context" "database/sql" "fmt" + "github.com/cortezaproject/corteza-server/store/rdbms" "github.com/cortezaproject/corteza-server/store/rdbms/ddl" "go.uber.org/zap" @@ -222,6 +223,14 @@ func (u upgrader) AddPrimaryKey(ctx context.Context, table string, ind *ddl.Inde return false, fmt.Errorf("adding primary keys on sqlite tables is not implemented") } +func (u upgrader) CreateIndex(ctx context.Context, ind *ddl.Index) (added bool, err error) { + if err = u.Exec(ctx, u.ddl.CreateIndex(ind)); err != nil { + return false, fmt.Errorf("could not create index on table %s: %w", ind.Table, err) + } + + return true, nil +} + // loads and returns all tables columns func (u upgrader) getColumns(ctx context.Context, table string) (out ddl.Columns, err error) { type (