Re-enable RDBMS table/column alter/drop operations
This commit is contained in:
@@ -29,27 +29,27 @@ type (
|
||||
|
||||
DropIndex struct {
|
||||
Dialect dialect
|
||||
Ident exp.IdentifierExpression
|
||||
TableIdent exp.IdentifierExpression
|
||||
Ident string
|
||||
TableIdent string
|
||||
}
|
||||
|
||||
AddColumn struct {
|
||||
Dialect dialect
|
||||
Table exp.IdentifierExpression
|
||||
Table string
|
||||
Column *Column
|
||||
}
|
||||
|
||||
DropColumn struct {
|
||||
Dialect dialect
|
||||
Table exp.IdentifierExpression
|
||||
Column exp.IdentifierExpression
|
||||
Table string
|
||||
Column string
|
||||
}
|
||||
|
||||
RenameColumn struct {
|
||||
Dialect dialect
|
||||
Table exp.IdentifierExpression
|
||||
Old exp.IdentifierExpression
|
||||
New exp.IdentifierExpression
|
||||
Table string
|
||||
Old string
|
||||
New string
|
||||
}
|
||||
)
|
||||
|
||||
@@ -238,30 +238,30 @@ func (t *CreateIndex) String() string {
|
||||
return sql
|
||||
}
|
||||
|
||||
//func (c *AddColumn) String() string {
|
||||
// sql := "ALTER TABLE" + " " + c.Table + " ADD COLUMN " + c.Column.Name + " " + c.Column.Type
|
||||
// if !c.Column.IsNull {
|
||||
// sql += " NOT NULL"
|
||||
// }
|
||||
//
|
||||
// if len(c.Column.DefaultValue) > 0 {
|
||||
// sql += " DEFAULT " + c.Column.DefaultValue
|
||||
// }
|
||||
//
|
||||
// return sql
|
||||
//}
|
||||
func (c *AddColumn) String() string {
|
||||
sql := "ALTER TABLE" + " " + c.Table + " ADD COLUMN " + c.Column.Ident + " " + c.Column.Type.Name
|
||||
if !c.Column.Type.Null {
|
||||
sql += " NOT NULL"
|
||||
}
|
||||
|
||||
//func (c *DropColumn) String() string {
|
||||
// return "ALTER TABLE" + " " + c.Table.Name + " DROP COLUMN " + c.Column
|
||||
//}
|
||||
if len(c.Column.Default) > 0 {
|
||||
sql += " DEFAULT " + c.Column.Default
|
||||
}
|
||||
|
||||
return sql
|
||||
}
|
||||
|
||||
func (c *DropColumn) String() string {
|
||||
return "ALTER TABLE" + " " + c.Table + " DROP COLUMN " + c.Column
|
||||
}
|
||||
|
||||
func (c *DropIndex) Express() exp.SQLExpression {
|
||||
return SQLExpression(exp.NewLiteralExpression("DROP INDEX ? ON ?", c.Ident, c.TableIdent))
|
||||
}
|
||||
|
||||
//func (c *RenameColumn) String() string {
|
||||
// return "ALTER TABLE" + " " + c.Table.Name + " RENAME COLUMN " + c.Old + " TO " + c.New
|
||||
//}
|
||||
func (c *RenameColumn) String() string {
|
||||
return "ALTER TABLE" + " " + c.Table + " RENAME COLUMN " + c.Old + " TO " + c.New
|
||||
}
|
||||
|
||||
// GetBool is a utility function to simplify getting a boolean value from a query result.
|
||||
func GetBool(ctx context.Context, db sqlx.QueryerContext, query exp.SQLExpression) (bool, error) {
|
||||
|
||||
@@ -19,6 +19,7 @@ type (
|
||||
// DataDefiner describes an interface for all DDL commands
|
||||
DataDefiner interface {
|
||||
ConvertModel(*dal.Model) (*Table, error)
|
||||
ConvertAttribute(attr *dal.Attribute) (*Column, error)
|
||||
|
||||
// Tables(ctx context.Context) ([]*Table, error)
|
||||
TableLookup(context.Context, string) (*Table, error)
|
||||
@@ -158,9 +159,8 @@ func ConvertModel(m *dal.Model, d driverDialect) (t *Table, err error) {
|
||||
}
|
||||
}
|
||||
|
||||
col, err = d.AttributeToColumn(a)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not convert attribute %q to column: %w", a.Ident, err)
|
||||
if col, err = ConvertAttribute(a, d); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
t.Columns = append(t.Columns, col)
|
||||
@@ -177,6 +177,15 @@ func ConvertModel(m *dal.Model, d driverDialect) (t *Table, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func ConvertAttribute(attr *dal.Attribute, d driverDialect) (col *Column, err error) {
|
||||
col, err = d.AttributeToColumn(attr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not convert attribute %q to column: %w", attr.Ident, err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ConvertIndex converts dal.Index to ddl.Index
|
||||
func ConvertIndex(i *dal.Index, aa dal.AttributeSet, table string, d driverDialect) (idx *Index, err error) {
|
||||
var (
|
||||
|
||||
@@ -3,8 +3,6 @@ package mysql
|
||||
import (
|
||||
"context"
|
||||
"github.com/cortezaproject/corteza-server/pkg/dal"
|
||||
"github.com/doug-martin/goqu/v9/exp"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
@@ -54,6 +52,10 @@ func (dd *dataDefiner) ConvertModel(m *dal.Model) (tbl *ddl.Table, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (dd *dataDefiner) ConvertAttribute(attr *dal.Attribute) (*ddl.Column, error) {
|
||||
return ddl.ConvertAttribute(attr, dd.d)
|
||||
}
|
||||
|
||||
func (dd *dataDefiner) TableCreate(ctx context.Context, t *ddl.Table) error {
|
||||
return ddl.Exec(ctx, dd.conn, &ddl.CreateTable{
|
||||
Table: t,
|
||||
@@ -68,23 +70,23 @@ func (dd *dataDefiner) TableLookup(ctx context.Context, t string) (*ddl.Table, e
|
||||
|
||||
func (dd *dataDefiner) ColumnAdd(ctx context.Context, t string, c *ddl.Column) error {
|
||||
return ddl.Exec(ctx, dd.conn, &ddl.AddColumn{
|
||||
Table: exp.NewIdentifierExpression("", t, ""),
|
||||
Table: dd.d.QuoteIdent(t),
|
||||
Column: c,
|
||||
})
|
||||
}
|
||||
|
||||
func (dd *dataDefiner) ColumnDrop(ctx context.Context, t, col string) error {
|
||||
return ddl.Exec(ctx, dd.conn, &ddl.DropColumn{
|
||||
Table: exp.NewIdentifierExpression("", t, ""),
|
||||
Column: exp.NewIdentifierExpression("", "", col),
|
||||
Table: dd.d.QuoteIdent(t),
|
||||
Column: dd.d.QuoteIdent(col),
|
||||
})
|
||||
}
|
||||
|
||||
func (dd *dataDefiner) ColumnRename(ctx context.Context, t string, o string, n string) error {
|
||||
return ddl.Exec(ctx, dd.conn, &ddl.RenameColumn{
|
||||
Table: exp.NewIdentifierExpression("", t, ""),
|
||||
Old: exp.NewIdentifierExpression("", "", o),
|
||||
New: exp.NewIdentifierExpression("", "", n),
|
||||
Table: dd.d.QuoteIdent(t),
|
||||
Old: dd.d.QuoteIdent(o),
|
||||
New: dd.d.QuoteIdent(n),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -106,7 +108,7 @@ func (dd *dataDefiner) IndexCreate(ctx context.Context, t string, i *ddl.Index)
|
||||
|
||||
func (dd *dataDefiner) IndexDrop(ctx context.Context, t, i string) error {
|
||||
return ddl.Exec(ctx, dd.conn, &ddl.DropIndex{
|
||||
Ident: exp.NewIdentifierExpression("", t, i),
|
||||
Ident: dd.d.QuoteIdent(i),
|
||||
Dialect: dd.d,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"github.com/cortezaproject/corteza-server/pkg/dal"
|
||||
"github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl"
|
||||
"github.com/doug-martin/goqu/v9/exp"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
@@ -35,6 +34,10 @@ func (dd *dataDefiner) ConvertModel(m *dal.Model) (*ddl.Table, error) {
|
||||
return ddl.ConvertModel(m, dd.d)
|
||||
}
|
||||
|
||||
func (dd *dataDefiner) ConvertAttribute(attr *dal.Attribute) (*ddl.Column, error) {
|
||||
return ddl.ConvertAttribute(attr, dd.d)
|
||||
}
|
||||
|
||||
func (dd *dataDefiner) TableCreate(ctx context.Context, t *ddl.Table) error {
|
||||
return ddl.Exec(ctx, dd.conn, &ddl.CreateTable{Table: t, Dialect: dd.d})
|
||||
}
|
||||
@@ -45,25 +48,23 @@ func (dd *dataDefiner) TableLookup(ctx context.Context, t string) (*ddl.Table, e
|
||||
|
||||
func (dd *dataDefiner) ColumnAdd(ctx context.Context, t string, c *ddl.Column) error {
|
||||
return ddl.Exec(ctx, dd.conn, &ddl.AddColumn{
|
||||
Table: exp.NewIdentifierExpression("", t, ""),
|
||||
Table: dd.d.QuoteIdent(t),
|
||||
Column: c,
|
||||
})
|
||||
}
|
||||
|
||||
func (dd *dataDefiner) ColumnDrop(ctx context.Context, t, col string) error {
|
||||
return ddl.Exec(ctx, dd.conn, &ddl.DropColumn{
|
||||
Dialect: dd.d,
|
||||
Table: exp.NewIdentifierExpression("", t, ""),
|
||||
Column: exp.NewIdentifierExpression("", "", col),
|
||||
Table: dd.d.QuoteIdent(t),
|
||||
Column: dd.d.QuoteIdent(col),
|
||||
})
|
||||
}
|
||||
|
||||
func (dd *dataDefiner) ColumnRename(ctx context.Context, t string, o string, n string) error {
|
||||
return ddl.Exec(ctx, dd.conn, &ddl.RenameColumn{
|
||||
Dialect: dd.d,
|
||||
Table: exp.NewIdentifierExpression("", t, ""),
|
||||
Old: exp.NewIdentifierExpression("", "", o),
|
||||
New: exp.NewIdentifierExpression("", "", n),
|
||||
Table: dd.d.QuoteIdent(t),
|
||||
Old: dd.d.QuoteIdent(o),
|
||||
New: dd.d.QuoteIdent(n),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -84,7 +85,7 @@ func (dd *dataDefiner) IndexCreate(ctx context.Context, t string, i *ddl.Index)
|
||||
|
||||
func (dd *dataDefiner) IndexDrop(ctx context.Context, t, i string) error {
|
||||
return ddl.Exec(ctx, dd.conn, &ddl.DropIndex{
|
||||
Ident: exp.NewIdentifierExpression("", t, i),
|
||||
Ident: dd.d.QuoteIdent(i),
|
||||
Dialect: dd.d,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"github.com/cortezaproject/corteza-server/pkg/dal"
|
||||
"github.com/cortezaproject/corteza-server/pkg/errors"
|
||||
"github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl"
|
||||
"github.com/doug-martin/goqu/v9/exp"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
@@ -36,6 +35,10 @@ func (dd *dataDefiner) ConvertModel(m *dal.Model) (*ddl.Table, error) {
|
||||
return ddl.ConvertModel(m, dd.d)
|
||||
}
|
||||
|
||||
func (dd *dataDefiner) ConvertAttribute(attr *dal.Attribute) (*ddl.Column, error) {
|
||||
return ddl.ConvertAttribute(attr, dd.d)
|
||||
}
|
||||
|
||||
func (dd *dataDefiner) TableCreate(ctx context.Context, t *ddl.Table) error {
|
||||
return ddl.Exec(ctx, dd.conn, &ddl.CreateTable{
|
||||
Table: t,
|
||||
@@ -50,23 +53,23 @@ func (dd *dataDefiner) TableLookup(ctx context.Context, t string) (*ddl.Table, e
|
||||
|
||||
func (dd *dataDefiner) ColumnAdd(ctx context.Context, t string, c *ddl.Column) error {
|
||||
return ddl.Exec(ctx, dd.conn, &ddl.AddColumn{
|
||||
Table: exp.NewIdentifierExpression("", t, ""),
|
||||
Table: dd.d.QuoteIdent(t),
|
||||
Column: c,
|
||||
})
|
||||
}
|
||||
|
||||
func (dd *dataDefiner) ColumnDrop(ctx context.Context, t, col string) error {
|
||||
return ddl.Exec(ctx, dd.conn, &ddl.DropColumn{
|
||||
Table: exp.NewIdentifierExpression("", t, ""),
|
||||
Column: exp.NewIdentifierExpression("", "", col),
|
||||
Table: dd.d.QuoteIdent(t),
|
||||
Column: dd.d.QuoteIdent(col),
|
||||
})
|
||||
}
|
||||
|
||||
func (dd *dataDefiner) ColumnRename(ctx context.Context, t string, o string, n string) error {
|
||||
return ddl.Exec(ctx, dd.conn, &ddl.RenameColumn{
|
||||
Table: exp.NewIdentifierExpression("", t, ""),
|
||||
Old: exp.NewIdentifierExpression("", "", o),
|
||||
New: exp.NewIdentifierExpression("", "", n),
|
||||
Table: dd.d.QuoteIdent(t),
|
||||
Old: dd.d.QuoteIdent(o),
|
||||
New: dd.d.QuoteIdent(n),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -87,7 +90,7 @@ func (dd *dataDefiner) IndexCreate(ctx context.Context, t string, i *ddl.Index)
|
||||
|
||||
func (dd *dataDefiner) IndexDrop(ctx context.Context, t, i string) error {
|
||||
return ddl.Exec(ctx, dd.conn, &ddl.DropIndex{
|
||||
Ident: exp.NewIdentifierExpression("", t, i),
|
||||
Ident: dd.d.QuoteIdent(i),
|
||||
Dialect: dd.d,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -29,40 +29,12 @@ func (s *Store) Upgrade(ctx context.Context) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
//var (
|
||||
// tableExists bool
|
||||
//)
|
||||
//
|
||||
//for _, t := range Tables() {
|
||||
// tableExists, err = s.SchemaAPI.TableExists(ctx, s.DB, t.Name)
|
||||
// if err != nil {
|
||||
// return fmt.Errorf("could not check table %q existance: %w", t.Name, err)
|
||||
// }
|
||||
//
|
||||
// if !tableExists {
|
||||
// s.log(ctx).Debug("creating table", zap.String("table", t.Name))
|
||||
// if err = s.SchemaAPI.CreateTable(ctx, s.DB, t); err != nil {
|
||||
// return fmt.Errorf("could not create table %q: %w", t.Name, err)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//fixes := []func(context.Context, *Store) error{
|
||||
// fix202209_extendComposeModuleForPrivacyAndDAL,
|
||||
// fix202209_extendComposeModuleFieldsForPrivacyAndDAL,
|
||||
// fix202209_dropObsoleteComposeModuleFields,
|
||||
// fix202209_composeRecordRevisions,
|
||||
// fix202209_extendDalConnectionsForMeta,
|
||||
// fix202209_renameModuleColOnComposeRecords,
|
||||
// fix202209_addMetaOnComposeRecords,
|
||||
//}
|
||||
//
|
||||
//for _, fix := range fixes {
|
||||
// if err = fix(ctx, s); err != nil {
|
||||
// return
|
||||
// }
|
||||
//}
|
||||
//
|
||||
for _, fix := range fixes {
|
||||
if err = fix(ctx, s); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -102,3 +74,67 @@ func createTablesFromModels(ctx context.Context, log *zap.Logger, dd ddl.DataDef
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func addColumn(ctx context.Context, s *Store, table string, attr *dal.Attribute) error {
|
||||
tbl, err := s.DataDefiner.TableLookup(ctx, table)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tbl.ColumnByIdent(attr.StoreIdent()) != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
s.log(ctx).Info(fmt.Sprintf("extending %q table with %q column", table, attr.StoreIdent()))
|
||||
|
||||
col, err := s.DataDefiner.ConvertAttribute(attr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.DataDefiner.ColumnAdd(ctx, table, col)
|
||||
}
|
||||
|
||||
func dropColumns(ctx context.Context, s *Store, table string, cc ...string) error {
|
||||
tbl, err := s.DataDefiner.TableLookup(ctx, table)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, c := range cc {
|
||||
if tbl.ColumnByIdent(c) == nil {
|
||||
// column does not exist, nothing to do
|
||||
continue
|
||||
}
|
||||
|
||||
s.log(ctx).Info(fmt.Sprintf("dropping %q column from %q", c, table))
|
||||
if err := s.DataDefiner.ColumnDrop(ctx, table, c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func renameColumn(ctx context.Context, s *Store, table string, from, to string) error {
|
||||
tbl, err := s.DataDefiner.TableLookup(ctx, table)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tbl.ColumnByIdent(from) == nil {
|
||||
// from column does not exist, nothing to do
|
||||
return nil
|
||||
}
|
||||
|
||||
if tbl.ColumnByIdent(to) != nil {
|
||||
// to column already exists, nothing to do
|
||||
return nil
|
||||
}
|
||||
|
||||
s.log(ctx).Info(fmt.Sprintf("renaming %q column on table %q to %q", from, table, to))
|
||||
if err := s.DataDefiner.ColumnRename(ctx, table, from, to); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,182 +1,114 @@
|
||||
package rdbms
|
||||
|
||||
//func fix202209_extendComposeModuleForPrivacyAndDAL(ctx context.Context, s *Store) (err error) {
|
||||
// s.log(ctx).Info("extending compose_module table with config column")
|
||||
// return s.SchemaAPI.AddColumn(
|
||||
// ctx, s.DB,
|
||||
// "compose_module",
|
||||
// &Column{Type: ColumnType{Type: ColumnTypeJson}, DefaultValue: "'{}'", Name: "config"},
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func fix202209_extendComposeModuleFieldsForPrivacyAndDAL(ctx context.Context, s *Store) (err error) {
|
||||
// s.log(ctx).Info("extending compose_module_field table with config column")
|
||||
// return s.SchemaAPI.AddColumn(
|
||||
// ctx, s.DB,
|
||||
// "compose_module_field",
|
||||
// &Column{Type: ColumnType{Type: ColumnTypeJson}, DefaultValue: "'{}'", Name: "config"},
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func fix202209_dropObsoleteComposeModuleFields(ctx context.Context, s *Store) (err error) {
|
||||
// s.log(ctx).Info("extending compose_module_field table with config column")
|
||||
// return s.SchemaAPI.DropColumn(
|
||||
// ctx, s.DB,
|
||||
// "compose_module_field",
|
||||
// "is_private",
|
||||
// "is_visible",
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func fix202209_composeRecordRevisions(ctx context.Context, s *Store) (err error) {
|
||||
// s.log(ctx).Info("extending compose_record table with revision column")
|
||||
// return s.SchemaAPI.AddColumn(
|
||||
// ctx, s.DB,
|
||||
// "compose_record",
|
||||
// &Column{Type: ColumnType{Type: ColumnTypeInteger}, DefaultValue: "1", Name: "revision"},
|
||||
// )
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/cortezaproject/corteza-server/pkg/dal"
|
||||
labelsType "github.com/cortezaproject/corteza-server/pkg/label/types"
|
||||
"github.com/cortezaproject/corteza-server/store"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
//return // will probably not need this...
|
||||
//var (
|
||||
// log = s.log(ctx)
|
||||
//)
|
||||
// RDBMS database fixes
|
||||
//
|
||||
//const (
|
||||
// envKeySkip = "UPGRADE_COMPOSE_RECORD_CHANGES_PREFILL_SKIP"
|
||||
// Schema changes that can not be automatically applied or complex changes
|
||||
// that require some logic to be applied are handled here.
|
||||
//
|
||||
// tblChanges = "compose_record_changes"
|
||||
// tblRecords = "compose_record"
|
||||
//)
|
||||
//
|
||||
//if _, set := os.LookupEnv(envKeySkip); set {
|
||||
// return
|
||||
//}
|
||||
//
|
||||
//var (
|
||||
// tblRecordColumns = []any{
|
||||
// // reusing record ID for ID of the (1st record)
|
||||
// // entry in the changes table
|
||||
// "id",
|
||||
// "id",
|
||||
// "rel_namespace", "module_id",
|
||||
// "values",
|
||||
// "owned_by",
|
||||
// "created_at", "created_by",
|
||||
// "updated_at", "updated_by",
|
||||
// "deleted_at", "deleted_by",
|
||||
// }
|
||||
//
|
||||
// tblChangesColumns = []any{
|
||||
// "id",
|
||||
// "rel_record",
|
||||
// "rel_namespace", "rel_module",
|
||||
// "values",
|
||||
// "owned_by",
|
||||
// "created_at", "created_by",
|
||||
// "updated_at", "updated_by",
|
||||
// "deleted_at", "deleted_by",
|
||||
// }
|
||||
//
|
||||
// d = s.Dialect
|
||||
// check = d.Select(exp.NewLiteralExpression("1")).From(tblChanges).Limit(1)
|
||||
// count int
|
||||
//
|
||||
// copyAll = d.
|
||||
// Insert(tblChanges).
|
||||
// Cols(tblChangesColumns...).
|
||||
// FromQuery(d.From(tblRecords).Select(tblRecordColumns...))
|
||||
//)
|
||||
//
|
||||
//if err = s.QueryOne(ctx, check, &count); err != nil {
|
||||
// // exit on error or when changes table is not empty
|
||||
// if !errors.IsNotFound(err) {
|
||||
// return fmt.Errorf("could not check if %q is empty: %w", tblChanges, err)
|
||||
// }
|
||||
//
|
||||
//} else if count > 0 {
|
||||
// return
|
||||
//}
|
||||
//
|
||||
//log.Warn(fmt.Sprintf("Empty %s table detected. "+
|
||||
// "Prefilling record changes table with current records, "+
|
||||
// "this might take a while, depending amount of records you have and how fast your database is. "+
|
||||
// "If you need to disable this, stop the server, set %s=1 "+
|
||||
// "and restart the server.",
|
||||
// tblChanges,
|
||||
// envKeySkip,
|
||||
//))
|
||||
//
|
||||
//spew.Dump(copyAll.ToSQL())
|
||||
//
|
||||
//// make a copy of records to changes table
|
||||
//return s.Exec(ctx, copyAll)
|
||||
//}
|
||||
//
|
||||
//func fix202209_extendDalConnectionsForMeta(ctx context.Context, s *Store) (err error) {
|
||||
// s.log(ctx).Info("extending dal_connections table with meta column")
|
||||
// return s.SchemaAPI.AddColumn(
|
||||
// ctx, s.DB,
|
||||
// &Table{Name: "dal_connections"},
|
||||
// &Column{Type: ColumnType{Type: ColumnTypeJson}, DefaultValue: "'{}'", Name: "meta"},
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func fix202209_renameModuleColOnComposeRecords(ctx context.Context, s *Store) (err error) {
|
||||
// s.log(ctx).Info("rename module_id column on compose_record table")
|
||||
// return s.SchemaAPI.RenameColumn(
|
||||
// ctx, s.DB, &Table{Name: "compose_record"}, "module_id", "rel_module",
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func fix202209_addMetaOnComposeRecords(ctx context.Context, s *Store) (err error) {
|
||||
// var (
|
||||
// log = s.log(ctx)
|
||||
//
|
||||
// groupedMeta = make(map[uint64]map[string]any)
|
||||
// packed []byte
|
||||
// )
|
||||
//
|
||||
// log.Info("add meta column on compose_record table")
|
||||
// err = s.SchemaAPI.AddColumn(
|
||||
// ctx, s.DB,
|
||||
// &Table{Name: "compose_record"},
|
||||
// &Column{Type: ColumnType{Type: ColumnTypeJson}, DefaultValue: "'{}'", Name: "meta"},
|
||||
// )
|
||||
//
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// return s.Tx(ctx, func(ctx context.Context, s store.Storer) (err error) {
|
||||
// log.Info("collecting record labels")
|
||||
// ll, _, err := store.SearchLabels(ctx, s, labelsType.LabelFilter{Kind: "compose:record"})
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// log.Info("grouping labels", zap.Int("count", len(ll)))
|
||||
// for _, l := range ll {
|
||||
// if _, has := groupedMeta[l.ResourceID]; !has {
|
||||
// groupedMeta[l.ResourceID] = make(map[string]any)
|
||||
// }
|
||||
//
|
||||
// groupedMeta[l.ResourceID][l.Name] = l.Value
|
||||
// if err = store.DeleteLabel(ctx, s, l); err != nil {
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// log.Info("updating records with meta", zap.Int("count", len(ll)))
|
||||
// for recordID, labels := range groupedMeta {
|
||||
// packed, err = json.Marshal(labels)
|
||||
// _, err = s.(*Store).DB.ExecContext(ctx, "UPDATE compose_record SET meta = $1 WHERE id = $2", packed, recordID)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return
|
||||
//
|
||||
// })
|
||||
//
|
||||
//}
|
||||
// Function names should start with "fix" and version.
|
||||
// This does not have any effect on how fixes are executed, only for organisation purposes.
|
||||
|
||||
var (
|
||||
// all enabled fix function need to be listed here
|
||||
fixes = []func(context.Context, *Store) error{
|
||||
fix_2022_09_00_extendComposeModuleForPrivacyAndDAL,
|
||||
fix_2022_09_00_extendComposeModuleFieldsForPrivacyAndDAL,
|
||||
fix_2022_09_00_dropObsoleteComposeModuleFields,
|
||||
fix_2022_09_00_extendDalConnectionsForMeta,
|
||||
fix_2022_09_00_renameModuleColOnComposeRecords,
|
||||
fix_2022_09_00_addMetaOnComposeRecords,
|
||||
}
|
||||
)
|
||||
|
||||
func fix_2022_09_00_extendComposeModuleForPrivacyAndDAL(ctx context.Context, s *Store) (err error) {
|
||||
return addColumn(ctx, s,
|
||||
"compose_module",
|
||||
&dal.Attribute{Ident: "config", Type: &dal.TypeJSON{DefaultValue: "'{}'"}},
|
||||
)
|
||||
}
|
||||
|
||||
func fix_2022_09_00_extendComposeModuleFieldsForPrivacyAndDAL(ctx context.Context, s *Store) (err error) {
|
||||
return addColumn(ctx, s,
|
||||
"compose_module",
|
||||
&dal.Attribute{Ident: "config", Type: &dal.TypeJSON{DefaultValue: "'{}'"}},
|
||||
)
|
||||
}
|
||||
|
||||
func fix_2022_09_00_dropObsoleteComposeModuleFields(ctx context.Context, s *Store) (err error) {
|
||||
return dropColumns(ctx, s,
|
||||
"compose_module_field",
|
||||
"is_private",
|
||||
"is_visible",
|
||||
)
|
||||
}
|
||||
|
||||
func fix_2022_09_00_extendDalConnectionsForMeta(ctx context.Context, s *Store) (err error) {
|
||||
return addColumn(ctx, s,
|
||||
"dal_connections",
|
||||
&dal.Attribute{Ident: "meta", Type: &dal.TypeJSON{DefaultValue: "'{}'"}},
|
||||
)
|
||||
}
|
||||
|
||||
func fix_2022_09_00_renameModuleColOnComposeRecords(ctx context.Context, s *Store) (err error) {
|
||||
return renameColumn(ctx, s, "compose_record", "module_id", "rel_module")
|
||||
}
|
||||
|
||||
func fix_2022_09_00_addMetaOnComposeRecords(ctx context.Context, s *Store) (err error) {
|
||||
var (
|
||||
log = s.log(ctx)
|
||||
|
||||
groupedMeta = make(map[uint64]map[string]any)
|
||||
packed []byte
|
||||
)
|
||||
|
||||
err = addColumn(ctx, s,
|
||||
"compose_record",
|
||||
&dal.Attribute{Ident: "meta", Type: &dal.TypeJSON{DefaultValue: "'{}'"}},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return s.Tx(ctx, func(ctx context.Context, s store.Storer) (err error) {
|
||||
log.Info("collecting record labels")
|
||||
ll, _, err := store.SearchLabels(ctx, s, labelsType.LabelFilter{Kind: "compose:record"})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
log.Info("grouping labels", zap.Int("count", len(ll)))
|
||||
for _, l := range ll {
|
||||
if _, has := groupedMeta[l.ResourceID]; !has {
|
||||
groupedMeta[l.ResourceID] = make(map[string]any)
|
||||
}
|
||||
|
||||
groupedMeta[l.ResourceID][l.Name] = l.Value
|
||||
if err = store.DeleteLabel(ctx, s, l); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("updating records with meta", zap.Int("count", len(ll)))
|
||||
for recordID, labels := range groupedMeta {
|
||||
packed, err = json.Marshal(labels)
|
||||
_, err = s.(*Store).DB.ExecContext(ctx, "UPDATE compose_record SET meta = $1 WHERE id = $2", packed, recordID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -1,765 +0,0 @@
|
||||
package rdbms
|
||||
|
||||
const (
|
||||
handleLength = 64
|
||||
resourceLength = 512
|
||||
|
||||
// https://www.rfc-editor.org/errata/eid1690
|
||||
emailLength = 254
|
||||
|
||||
// Enough for IPv6, ports, delimiters, IPv4-mapped IPV6 addresses...
|
||||
ipAddrLength = 64
|
||||
|
||||
// IETF language tag doesn't specify a hard limit (there can be a lot of modifiers)
|
||||
// so I can't put a strict limit.
|
||||
// Omiting the bits of the specs that don't have a limited length a size of 32 would suffice.
|
||||
// Going a bit extra for future proofing
|
||||
languageTagLength = 128
|
||||
|
||||
// Some keys may introduce generated identifiers which may cause the size
|
||||
// to inflate.
|
||||
languageKeyLength = 256
|
||||
|
||||
urlLength = 2048
|
||||
locationLength = 256
|
||||
)
|
||||
|
||||
// Tables fn holds a list of all tables that need to be created
|
||||
//func Tables() []*Table {
|
||||
// return []*Table{
|
||||
// tableUsers(),
|
||||
// tableDalConnections(),
|
||||
// tableDalSensitivityLevels(),
|
||||
// tableCredentials(),
|
||||
// tableAuthClients(),
|
||||
// tableAuthConfirmedClients(),
|
||||
// tableAuthSessions(),
|
||||
// tableAuthOA2Tokens(),
|
||||
// tableRoles(),
|
||||
// tableRoleMembers(),
|
||||
// tableApplications(),
|
||||
// tableReminders(),
|
||||
// tableAttachments(),
|
||||
// tableActionLog(),
|
||||
// tableRbacRules(),
|
||||
// tableSettings(),
|
||||
// tableLabels(),
|
||||
// tableFlags(),
|
||||
// tableTemplates(),
|
||||
// tableReports(),
|
||||
// tableResourceTranslations(),
|
||||
// tableComposeAttachment(),
|
||||
// tableComposeChart(),
|
||||
// tableComposeModule(),
|
||||
// tableComposeModuleField(),
|
||||
// tableComposeNamespace(),
|
||||
// tableComposePage(),
|
||||
// tableComposeRecord(),
|
||||
// tableComposeRecordRevisions(),
|
||||
// tableFederationModuleShared(),
|
||||
// tableFederationModuleExposed(),
|
||||
// tableFederationModuleMapping(),
|
||||
// tableFederationNodes(),
|
||||
// tableFederationNodesSync(),
|
||||
// tableAutomationWorkflows(),
|
||||
// tableAutomationTriggers(),
|
||||
// tableAutomationSessions(),
|
||||
// //tableAutomationState(),
|
||||
// tableMessagebusQueue(),
|
||||
// tableMessagebusQueuemessage(),
|
||||
// tableApigwRoute(),
|
||||
// tableApigwFilter(),
|
||||
// tableResourceActivityLog(),
|
||||
// tableDataPrivacyRequests(),
|
||||
// tableDataPrivacyRequestComments(),
|
||||
// }
|
||||
//}
|
||||
|
||||
//func tableUsers() *Table {
|
||||
// return TableDef("users",
|
||||
// ID,
|
||||
// ColumnDef("email", ColumnTypeVarchar, ColumnTypeLength(emailLength)),
|
||||
// ColumnDef("email_confirmed", ColumnTypeBoolean, DefaultValue("false")),
|
||||
// ColumnDef("username", ColumnTypeText),
|
||||
// ColumnDef("name", ColumnTypeText),
|
||||
// ColumnDef("handle", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("kind", ColumnTypeVarchar, ColumnTypeLength(8)),
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
// ColumnDef("suspended_at", ColumnTypeTimestamp, Null),
|
||||
// CUDTimestamps,
|
||||
//
|
||||
// AddIndex("unique_email", IExpr("LOWER(email)"), IWhere("LENGTH(email) > 0 AND deleted_at IS NULL AND suspended_at IS NULL")),
|
||||
// AddIndex("unique_username", IExpr("LOWER(username)"), IWhere("LENGTH(username) > 0 AND deleted_at IS NULL AND suspended_at IS NULL")),
|
||||
// AddIndex("unique_handle", IExpr("LOWER(handle)"), IWhere("LENGTH(handle) > 0 AND deleted_at IS NULL AND suspended_at IS NULL")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableDalConnections() *Table {
|
||||
// return TableDef("dal_connections",
|
||||
// ID,
|
||||
//
|
||||
// ColumnDef("handle", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("type", ColumnTypeText),
|
||||
//
|
||||
// ColumnDef("config", ColumnTypeJson),
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
//
|
||||
// CUDTimestamps,
|
||||
// CUDUsers,
|
||||
//
|
||||
// AddIndex("unique_handle", IExpr("LOWER(handle)"), IWhere("LENGTH(handle) > 0 AND deleted_at IS NULL")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableDalSensitivityLevels() *Table {
|
||||
// return TableDef("dal_sensitivity_levels",
|
||||
// ID,
|
||||
//
|
||||
// ColumnDef("handle", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("level", ColumnTypeInteger),
|
||||
//
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
//
|
||||
// CUDTimestamps,
|
||||
// CUDUsers,
|
||||
//
|
||||
// AddIndex("unique_handle", IExpr("LOWER(handle)"), IWhere("LENGTH(handle) > 0 AND deleted_at IS NULL")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableCredentials() *Table {
|
||||
// return TableDef(`credentials`,
|
||||
// ID,
|
||||
// ColumnDef("rel_owner", ColumnTypeIdentifier),
|
||||
// ColumnDef("label", ColumnTypeText),
|
||||
// ColumnDef("kind", ColumnTypeVarchar, ColumnTypeLength(128)),
|
||||
// ColumnDef("credentials", ColumnTypeText),
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
// ColumnDef("expires_at", ColumnTypeTimestamp, Null),
|
||||
// ColumnDef("last_used_at", ColumnTypeTimestamp, Null),
|
||||
// CUDTimestamps,
|
||||
//
|
||||
// AddIndex("owner_kind", IColumn("rel_owner", "kind"), IWhere("deleted_at IS NULL")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableAuthClients() *Table {
|
||||
// return TableDef(`auth_clients`,
|
||||
// ID,
|
||||
// ColumnDef("handle", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
// ColumnDef("secret", ColumnTypeVarchar, ColumnTypeLength(64)),
|
||||
// ColumnDef("scope", ColumnTypeVarchar, ColumnTypeLength(512)),
|
||||
// ColumnDef("valid_grant", ColumnTypeVarchar, ColumnTypeLength(32)),
|
||||
// ColumnDef("redirect_uri", ColumnTypeText),
|
||||
// ColumnDef("enabled", ColumnTypeBoolean),
|
||||
// ColumnDef("trusted", ColumnTypeBoolean),
|
||||
// ColumnDef("valid_from", ColumnTypeTimestamp, Null),
|
||||
// ColumnDef("expires_at", ColumnTypeTimestamp, Null),
|
||||
// ColumnDef("security", ColumnTypeJson),
|
||||
// ColumnDef("owned_by", ColumnTypeIdentifier),
|
||||
// CUDTimestamps,
|
||||
// CUDUsers,
|
||||
//
|
||||
// AddIndex("unique_handle", IExpr("LOWER(handle)"), IWhere("LENGTH(handle) > 0 AND deleted_at IS NULL")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableAuthConfirmedClients() *Table {
|
||||
// return TableDef(`auth_confirmed_clients`,
|
||||
// ColumnDef("rel_user", ColumnTypeIdentifier),
|
||||
// ColumnDef("rel_client", ColumnTypeIdentifier),
|
||||
// ColumnDef("confirmed_at", ColumnTypeTimestamp),
|
||||
//
|
||||
// PrimaryKey(IColumn("rel_user", "rel_client")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableAuthSessions() *Table {
|
||||
// return TableDef(`auth_sessions`,
|
||||
// ColumnDef("id", ColumnTypeVarchar, ColumnTypeLength(64)),
|
||||
// ColumnDef("data", ColumnTypeBinary),
|
||||
// ColumnDef("rel_user", ColumnTypeIdentifier),
|
||||
// ColumnDef("created_at", ColumnTypeTimestamp),
|
||||
// ColumnDef("expires_at", ColumnTypeTimestamp),
|
||||
// ColumnDef("remote_addr", ColumnTypeVarchar, ColumnTypeLength(ipAddrLength)),
|
||||
// ColumnDef("user_agent", ColumnTypeText),
|
||||
//
|
||||
// AddIndex("expires_at", IColumn("expires_at")),
|
||||
// AddIndex("user", IColumn("rel_user")),
|
||||
// PrimaryKey(IColumn("id")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableAuthOA2Tokens() *Table {
|
||||
// return TableDef(`auth_oa2tokens`,
|
||||
// ID,
|
||||
//
|
||||
// ColumnDef("code", ColumnTypeVarchar, ColumnTypeLength(48)),
|
||||
// ColumnDef("access", ColumnTypeVarchar, ColumnTypeLength(2048)),
|
||||
// ColumnDef("refresh", ColumnTypeVarchar, ColumnTypeLength(48)),
|
||||
// ColumnDef("data", ColumnTypeJson),
|
||||
// ColumnDef("remote_addr", ColumnTypeVarchar, ColumnTypeLength(ipAddrLength)),
|
||||
// ColumnDef("user_agent", ColumnTypeText),
|
||||
//
|
||||
// ColumnDef("rel_client", ColumnTypeIdentifier),
|
||||
// ColumnDef("rel_user", ColumnTypeIdentifier),
|
||||
// ColumnDef("created_at", ColumnTypeTimestamp),
|
||||
// ColumnDef("expires_at", ColumnTypeTimestamp),
|
||||
//
|
||||
// AddIndex("expires_at", IColumn("expires_at")),
|
||||
// AddIndex("code", IColumn("code")),
|
||||
// AddIndex("access", IColumn("access")),
|
||||
// AddIndex("refresh", IColumn("refresh")),
|
||||
// AddIndex("client", IColumn("rel_client")),
|
||||
// AddIndex("user", IColumn("rel_user")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableRoles() *Table {
|
||||
// return TableDef(`roles`,
|
||||
// ID,
|
||||
// ColumnDef("name", ColumnTypeText),
|
||||
// ColumnDef("handle", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
// ColumnDef("archived_at", ColumnTypeTimestamp, Null),
|
||||
// CUDTimestamps,
|
||||
//
|
||||
// AddIndex("unique_handle", IExpr("LOWER(handle)"), IWhere("LENGTH(handle) > 0 AND deleted_at IS NULL AND archived_at IS NULL")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableRoleMembers() *Table {
|
||||
// return TableDef(`role_members`,
|
||||
// ColumnDef("rel_role", ColumnTypeIdentifier),
|
||||
// ColumnDef("rel_user", ColumnTypeIdentifier),
|
||||
//
|
||||
// AddIndex("unique_membership", IColumn("rel_role", "rel_user")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableApplications() *Table {
|
||||
// return TableDef("applications",
|
||||
// ID,
|
||||
// ColumnDef("name", ColumnTypeText),
|
||||
// ColumnDef("enabled", ColumnTypeBoolean, DefaultValue("true")),
|
||||
// ColumnDef("weight", ColumnTypeInteger, DefaultValue("0")),
|
||||
// ColumnDef("unify", ColumnTypeJson),
|
||||
// ColumnDef("rel_owner", ColumnTypeIdentifier),
|
||||
// CUDTimestamps,
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableReminders() *Table {
|
||||
// return TableDef("reminders",
|
||||
// ID,
|
||||
// ColumnDef("resource", ColumnTypeVarchar, ColumnTypeLength(resourceLength)),
|
||||
// ColumnDef("payload", ColumnTypeJson),
|
||||
// ColumnDef("snooze_count", ColumnTypeInteger, DefaultValue("0")),
|
||||
// ColumnDef("assigned_to", ColumnTypeIdentifier, DefaultValue("0")),
|
||||
// ColumnDef("assigned_by", ColumnTypeIdentifier, DefaultValue("0")),
|
||||
// ColumnDef("assigned_at", ColumnTypeTimestamp),
|
||||
// ColumnDef("remind_at", ColumnTypeTimestamp, Null),
|
||||
// ColumnDef("dismissed_at", ColumnTypeTimestamp, Null),
|
||||
// ColumnDef("dismissed_by", ColumnTypeIdentifier, DefaultValue("0")),
|
||||
// CUDTimestamps,
|
||||
//
|
||||
// AddIndex("resource", IColumn("resource")),
|
||||
// AddIndex("assignee", IColumn("assigned_to")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableAttachments() *Table {
|
||||
// return TableDef("attachments",
|
||||
// ID,
|
||||
// ColumnDef("rel_owner", ColumnTypeIdentifier),
|
||||
// ColumnDef("kind", ColumnTypeText),
|
||||
// ColumnDef("url", ColumnTypeText),
|
||||
// ColumnDef("preview_url", ColumnTypeText),
|
||||
// ColumnDef("name", ColumnTypeText),
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
// CUDTimestamps,
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableActionLog() *Table {
|
||||
// return TableDef("actionlog",
|
||||
// ID,
|
||||
// ColumnDef("ts", ColumnTypeTimestamp),
|
||||
// ColumnDef("actor_ip_addr", ColumnTypeVarchar, ColumnTypeLength(ipAddrLength)),
|
||||
// ColumnDef("actor_id", ColumnTypeIdentifier),
|
||||
// ColumnDef("request_origin", ColumnTypeVarchar, ColumnTypeLength(32)),
|
||||
// ColumnDef("request_id", ColumnTypeVarchar, ColumnTypeLength(256)),
|
||||
// ColumnDef("resource", ColumnTypeVarchar, ColumnTypeLength(resourceLength)),
|
||||
// ColumnDef("action", ColumnTypeVarchar, ColumnTypeLength(64)),
|
||||
// ColumnDef("error", ColumnTypeText),
|
||||
// ColumnDef("severity", ColumnTypeInteger),
|
||||
// ColumnDef("description", ColumnTypeText),
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
//
|
||||
// AddIndex("ts", IColumn("ts")),
|
||||
// AddIndex("request_origin", IColumn("request_origin")),
|
||||
// AddIndex("actor_id", IColumn("actor_id")),
|
||||
// AddIndex("resource", IColumn("resource")),
|
||||
// AddIndex("action", IColumn("action")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableRbacRules() *Table {
|
||||
// return TableDef("rbac_rules",
|
||||
// ColumnDef("rel_role", ColumnTypeIdentifier),
|
||||
// ColumnDef("resource", ColumnTypeVarchar, ColumnTypeLength(resourceLength)),
|
||||
// ColumnDef("operation", ColumnTypeVarchar, ColumnTypeLength(50)),
|
||||
// ColumnDef("access", ColumnTypeInteger),
|
||||
//
|
||||
// PrimaryKey(IColumn("rel_role", "resource", "operation")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableSettings() *Table {
|
||||
// return TableDef("settings",
|
||||
// ColumnDef("rel_owner", ColumnTypeIdentifier),
|
||||
// ColumnDef("name", ColumnTypeVarchar, ColumnTypeLength(resourceLength)),
|
||||
// ColumnDef("value", ColumnTypeJson),
|
||||
// ColumnDef("updated_by", ColumnTypeIdentifier),
|
||||
// ColumnDef("updated_at", ColumnTypeTimestamp),
|
||||
//
|
||||
// AddIndex("unique_name", IExpr("LOWER(name)"), IColumn("rel_owner")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableLabels() *Table {
|
||||
// return TableDef("labels",
|
||||
// ColumnDef("kind", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("rel_resource", ColumnTypeIdentifier),
|
||||
// ColumnDef("name", ColumnTypeVarchar, ColumnTypeLength(resourceLength)),
|
||||
// ColumnDef("value", ColumnTypeText),
|
||||
//
|
||||
// AddIndex("unique_kind_res_name", IColumn("kind", "rel_resource"), IExpr("LOWER(name)")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableFlags() *Table {
|
||||
// return TableDef("flags",
|
||||
// ColumnDef("kind", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("rel_resource", ColumnTypeIdentifier),
|
||||
// ColumnDef("owned_by", ColumnTypeIdentifier),
|
||||
// ColumnDef("name", ColumnTypeVarchar, ColumnTypeLength(resourceLength)),
|
||||
// ColumnDef("active", ColumnTypeBoolean),
|
||||
//
|
||||
// AddIndex("unique_kind_res_owner_name", IColumn("kind", "rel_resource", "owned_by"), IExpr("LOWER(name)")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableTemplates() *Table {
|
||||
// return TableDef("templates",
|
||||
// ID,
|
||||
// ColumnDef("rel_owner", ColumnTypeIdentifier),
|
||||
// ColumnDef("handle", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("language", ColumnTypeText),
|
||||
// ColumnDef("type", ColumnTypeText),
|
||||
// ColumnDef("partial", ColumnTypeBoolean),
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
// ColumnDef("template", ColumnTypeText),
|
||||
// CUDTimestamps,
|
||||
// ColumnDef("last_used_at", ColumnTypeTimestamp, Null),
|
||||
//
|
||||
// AddIndex("unique_language_handle", IColumn("language"), IExpr("LOWER(handle)"), IWhere("LENGTH(handle) > 0 AND deleted_at IS NULL")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableReports() *Table {
|
||||
// return TableDef("reports",
|
||||
// ID,
|
||||
// ColumnDef("handle", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
// ColumnDef("scenarios", ColumnTypeJson),
|
||||
// ColumnDef("sources", ColumnTypeJson),
|
||||
// ColumnDef("blocks", ColumnTypeJson),
|
||||
//
|
||||
// ColumnDef("owned_by", ColumnTypeIdentifier),
|
||||
// CUDTimestamps,
|
||||
// CUDUsers,
|
||||
//
|
||||
// AddIndex("unique_handle", IExpr("LOWER(handle)"), IWhere("LENGTH(handle) > 0 AND deleted_at IS NULL")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableResourceTranslations() *Table {
|
||||
// return TableDef("resource_translations",
|
||||
// ID,
|
||||
//
|
||||
// ColumnDef("lang", ColumnTypeVarchar, ColumnTypeLength(languageTagLength)),
|
||||
// ColumnDef("resource", ColumnTypeVarchar, ColumnTypeLength(resourceLength)),
|
||||
// ColumnDef("k", ColumnTypeVarchar, ColumnTypeLength(languageKeyLength)),
|
||||
// ColumnDef("message", ColumnTypeText),
|
||||
//
|
||||
// CUDTimestamps,
|
||||
// ColumnDef("owned_by", ColumnTypeIdentifier),
|
||||
// CUDUsers,
|
||||
//
|
||||
// AddIndex("unique_translation", IExpr("LOWER(lang)"), IExpr("LOWER(resource)"), IExpr("LOWER(k)")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableComposeAttachment() *Table {
|
||||
// // @todo merge with general attachment table
|
||||
//
|
||||
// return TableDef("compose_attachment",
|
||||
// ID,
|
||||
// ColumnDef("rel_namespace", ColumnTypeIdentifier),
|
||||
// ColumnDef("rel_owner", ColumnTypeIdentifier),
|
||||
// ColumnDef("kind", ColumnTypeText),
|
||||
// ColumnDef("url", ColumnTypeText),
|
||||
// ColumnDef("preview_url", ColumnTypeText),
|
||||
// ColumnDef("name", ColumnTypeText),
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
// CUDTimestamps,
|
||||
//
|
||||
// AddIndex("namespace", IColumn("rel_namespace")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableComposeChart() *Table {
|
||||
// return TableDef("compose_chart",
|
||||
// ID,
|
||||
// ColumnDef("handle", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("rel_namespace", ColumnTypeIdentifier),
|
||||
// ColumnDef("name", ColumnTypeText),
|
||||
// ColumnDef("config", ColumnTypeJson),
|
||||
// CUDTimestamps,
|
||||
//
|
||||
// AddIndex("namespace", IColumn("rel_namespace")),
|
||||
// AddIndex("unique_handle", IColumn("rel_namespace"), IExpr("LOWER(handle)"), IWhere("LENGTH(handle) > 0 AND deleted_at IS NULL")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableComposeModule() *Table {
|
||||
// return TableDef("compose_module",
|
||||
// ID,
|
||||
// ColumnDef("rel_namespace", ColumnTypeIdentifier),
|
||||
// ColumnDef("handle", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("name", ColumnTypeText),
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
// ColumnDef("config", ColumnTypeJson),
|
||||
// CUDTimestamps,
|
||||
//
|
||||
// AddIndex("namespace", IColumn("rel_namespace")),
|
||||
// AddIndex("unique_handle", IColumn("rel_namespace"), IExpr("LOWER(handle)"), IWhere("LENGTH(handle) > 0 AND deleted_at IS NULL")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableComposeModuleField() *Table {
|
||||
// return TableDef("compose_module_field",
|
||||
// ID,
|
||||
//
|
||||
// ColumnDef("rel_module", ColumnTypeIdentifier),
|
||||
// ColumnDef("place", ColumnTypeInteger),
|
||||
// ColumnDef("kind", ColumnTypeText),
|
||||
// ColumnDef("options", ColumnTypeJson),
|
||||
// ColumnDef("config", ColumnTypeJson),
|
||||
// ColumnDef("default_value", ColumnTypeJson),
|
||||
// ColumnDef("expressions", ColumnTypeJson),
|
||||
// ColumnDef("name", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("label", ColumnTypeText),
|
||||
// ColumnDef("is_required", ColumnTypeBoolean),
|
||||
// ColumnDef("is_multi", ColumnTypeBoolean),
|
||||
//
|
||||
// CUDTimestamps,
|
||||
//
|
||||
// AddIndex("unique_name", IColumn("rel_module"), IExpr("LOWER(name)"), IWhere("LENGTH(name) > 0 AND deleted_at IS NULL")),
|
||||
// AddIndex("module", IColumn("rel_module")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableComposeNamespace() *Table {
|
||||
// return TableDef("compose_namespace",
|
||||
// ID,
|
||||
// ColumnDef("name", ColumnTypeText),
|
||||
// ColumnDef("slug", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("enabled", ColumnTypeBoolean),
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
// CUDTimestamps,
|
||||
//
|
||||
// AddIndex("unique_slug", IExpr("LOWER(slug)"), IWhere("LENGTH(slug) > 0 AND deleted_at IS NULL")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableComposePage() *Table {
|
||||
// return TableDef("compose_page",
|
||||
// ID,
|
||||
// ColumnDef("title", ColumnTypeText),
|
||||
// ColumnDef("handle", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("description", ColumnTypeText),
|
||||
// ColumnDef("rel_namespace", ColumnTypeIdentifier),
|
||||
// ColumnDef("rel_module", ColumnTypeIdentifier),
|
||||
// ColumnDef("self_id", ColumnTypeIdentifier),
|
||||
// ColumnDef("config", ColumnTypeJson),
|
||||
// ColumnDef("blocks", ColumnTypeJson),
|
||||
// ColumnDef("visible", ColumnTypeBoolean),
|
||||
// ColumnDef("weight", ColumnTypeInteger),
|
||||
// CUDTimestamps,
|
||||
//
|
||||
// AddIndex("self", IColumn("self_id")),
|
||||
// AddIndex("namespace", IColumn("rel_namespace")),
|
||||
// AddIndex("module", IColumn("rel_module")),
|
||||
// AddIndex("unique_handle", IColumn("rel_namespace"), IExpr("LOWER(handle)"), IWhere("LENGTH(handle) > 0 AND deleted_at IS NULL")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableComposeRecord() *Table {
|
||||
// return TableDef("compose_record",
|
||||
// ID,
|
||||
// ColumnDef("rel_namespace", ColumnTypeIdentifier),
|
||||
// ColumnDef("rel_module", ColumnTypeIdentifier),
|
||||
// ColumnDef("revision", ColumnTypeInteger),
|
||||
// ColumnDef("values", ColumnTypeJson),
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
// ColumnDef("owned_by", ColumnTypeIdentifier),
|
||||
// CUDTimestamps,
|
||||
// CUDUsers,
|
||||
//
|
||||
// AddIndex("namespace", IColumn("rel_namespace")),
|
||||
// AddIndex("module", IColumn("rel_module")),
|
||||
// AddIndex("owner", IColumn("owned_by")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableComposeRecordRevisions() *Table {
|
||||
// return TableDef("compose_record_revisions",
|
||||
// ID,
|
||||
// ColumnDef("ts", ColumnTypeTimestamp),
|
||||
// ColumnDef("rel_resource", ColumnTypeIdentifier),
|
||||
// ColumnDef("revision", ColumnTypeInteger),
|
||||
// ColumnDef("operation", ColumnTypeText),
|
||||
// ColumnDef("rel_user", ColumnTypeIdentifier),
|
||||
// ColumnDef("delta", ColumnTypeJson),
|
||||
// ColumnDef("comment", ColumnTypeText),
|
||||
//
|
||||
// AddIndex("record", IColumn("rel_resource")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableFederationModuleShared() *Table {
|
||||
// return TableDef("federation_module_shared",
|
||||
// ID,
|
||||
// ColumnDef("handle", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("name", ColumnTypeText),
|
||||
// ColumnDef("rel_node", ColumnTypeIdentifier),
|
||||
// ColumnDef("xref_module", ColumnTypeIdentifier),
|
||||
// ColumnDef("fields", ColumnTypeJson),
|
||||
// CUDTimestamps,
|
||||
// CUDUsers,
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableFederationModuleExposed() *Table {
|
||||
// return TableDef("federation_module_exposed",
|
||||
// ID,
|
||||
// ColumnDef("handle", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("name", ColumnTypeText),
|
||||
// ColumnDef("rel_node", ColumnTypeIdentifier),
|
||||
// ColumnDef("rel_compose_module", ColumnTypeIdentifier),
|
||||
// ColumnDef("rel_compose_namespace", ColumnTypeIdentifier),
|
||||
// ColumnDef("fields", ColumnTypeJson),
|
||||
// CUDTimestamps,
|
||||
// CUDUsers,
|
||||
//
|
||||
// AddIndex("unique_node_compose_module", IColumn("rel_node", "rel_compose_module", "rel_compose_namespace")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableFederationModuleMapping() *Table {
|
||||
// return TableDef("federation_module_mapping",
|
||||
// ColumnDef("rel_federation_module", ColumnTypeIdentifier),
|
||||
// ColumnDef("rel_compose_module", ColumnTypeIdentifier),
|
||||
// ColumnDef("rel_compose_namespace", ColumnTypeIdentifier),
|
||||
// ColumnDef("field_mapping", ColumnTypeJson),
|
||||
//
|
||||
// AddIndex("unique_module_compose_module", IColumn("rel_federation_module", "rel_compose_module", "rel_compose_namespace")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableFederationNodes() *Table {
|
||||
// return TableDef("federation_nodes",
|
||||
// ID,
|
||||
// ColumnDef("shared_node_id", ColumnTypeIdentifier),
|
||||
// ColumnDef("name", ColumnTypeText),
|
||||
// ColumnDef("base_url", ColumnTypeText),
|
||||
// ColumnDef("status", ColumnTypeText),
|
||||
// ColumnDef("contact", ColumnTypeVarchar, ColumnTypeLength(emailLength)),
|
||||
// ColumnDef("pair_token", ColumnTypeText),
|
||||
// ColumnDef("auth_token", ColumnTypeText),
|
||||
//
|
||||
// CUDTimestamps,
|
||||
// CUDUsers,
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableFederationNodesSync() *Table {
|
||||
// return TableDef("federation_nodes_sync",
|
||||
// ColumnDef("rel_node", ColumnTypeIdentifier),
|
||||
// ColumnDef("rel_module", ColumnTypeIdentifier),
|
||||
// ColumnDef("sync_type", ColumnTypeText),
|
||||
// ColumnDef("sync_status", ColumnTypeText),
|
||||
// ColumnDef("time_action", ColumnTypeTimestamp),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableAutomationWorkflows() *Table {
|
||||
// return TableDef("automation_workflows",
|
||||
// ID,
|
||||
// ColumnDef("handle", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
// ColumnDef("enabled", ColumnTypeBoolean),
|
||||
// ColumnDef("trace", ColumnTypeBoolean),
|
||||
// ColumnDef("keep_sessions", ColumnTypeInteger),
|
||||
// ColumnDef("scope", ColumnTypeJson),
|
||||
// ColumnDef("steps", ColumnTypeJson),
|
||||
// ColumnDef("paths", ColumnTypeJson),
|
||||
// ColumnDef("issues", ColumnTypeJson),
|
||||
// ColumnDef("run_as", ColumnTypeIdentifier),
|
||||
// ColumnDef("owned_by", ColumnTypeIdentifier),
|
||||
// CUDTimestamps,
|
||||
// CUDUsers,
|
||||
//
|
||||
// AddIndex("unique_handle", IExpr("LOWER(handle)"), IWhere("LENGTH(handle) > 0 AND deleted_at IS NULL")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableAutomationSessions() *Table {
|
||||
// return TableDef("automation_sessions",
|
||||
// ID,
|
||||
// ColumnDef("rel_workflow", ColumnTypeIdentifier),
|
||||
// ColumnDef("status", ColumnTypeInteger),
|
||||
// ColumnDef("event_type", ColumnTypeText, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("resource_type", ColumnTypeText, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("input", ColumnTypeJson),
|
||||
// ColumnDef("output", ColumnTypeJson),
|
||||
// ColumnDef("stacktrace", ColumnTypeJson),
|
||||
// ColumnDef("created_by", ColumnTypeIdentifier),
|
||||
// ColumnDef("created_at", ColumnTypeTimestamp),
|
||||
// ColumnDef("purge_at", ColumnTypeTimestamp, Null),
|
||||
// ColumnDef("suspended_at", ColumnTypeTimestamp, Null),
|
||||
// ColumnDef("completed_at", ColumnTypeTimestamp, Null),
|
||||
// ColumnDef("error", ColumnTypeText),
|
||||
//
|
||||
// AddIndex("workflow", IColumn("rel_workflow")),
|
||||
// AddIndex("event_type", IFieldFull(&IField{Field: "event_type", Length: handleLength})),
|
||||
// AddIndex("resource_type", IFieldFull(&IField{Field: "resource_type", Length: handleLength})),
|
||||
// AddIndex("status", IColumn("status")),
|
||||
// AddIndex("created_at", IColumn("created_at")),
|
||||
// AddIndex("completed_at", IColumn("completed_at")),
|
||||
// AddIndex("suspended_at", IColumn("suspended_at")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableAutomationTriggers() *Table {
|
||||
// return TableDef("automation_triggers",
|
||||
// ID,
|
||||
// ColumnDef("rel_workflow", ColumnTypeIdentifier),
|
||||
// ColumnDef("rel_step", ColumnTypeIdentifier),
|
||||
// ColumnDef("enabled", ColumnTypeBoolean),
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
// ColumnDef("resource_type", ColumnTypeText, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("event_type", ColumnTypeText, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("constraints", ColumnTypeJson),
|
||||
// ColumnDef("input", ColumnTypeJson),
|
||||
// ColumnDef("owned_by", ColumnTypeIdentifier),
|
||||
// CUDTimestamps,
|
||||
// CUDUsers,
|
||||
//
|
||||
// AddIndex("workflow", IColumn("rel_workflow")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableMessagebusQueuemessage() *Table {
|
||||
// return TableDef("queue_messages",
|
||||
// ID,
|
||||
// ColumnDef("queue", ColumnTypeText, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("payload", ColumnTypeBinary),
|
||||
// ColumnDef("created", ColumnTypeTimestamp),
|
||||
// ColumnDef("processed", ColumnTypeTimestamp, Null),
|
||||
//
|
||||
// // AddIndex("processed", IColumn("processed")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableMessagebusQueue() *Table {
|
||||
// return TableDef("queue_settings",
|
||||
// ID,
|
||||
// ColumnDef("consumer", ColumnTypeText, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("queue", ColumnTypeText, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
// CUDTimestamps,
|
||||
// CUDUsers,
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableApigwRoute() *Table {
|
||||
// return TableDef("apigw_routes",
|
||||
// ID,
|
||||
// ColumnDef("endpoint", ColumnTypeText, ColumnTypeLength(resourceLength)),
|
||||
// ColumnDef("method", ColumnTypeText, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("enabled", ColumnTypeBoolean),
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
// ColumnDef("rel_group", ColumnTypeIdentifier),
|
||||
// CUDTimestamps,
|
||||
// CUDUsers,
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableApigwFilter() *Table {
|
||||
// return TableDef("apigw_filters",
|
||||
// ID,
|
||||
// ColumnDef("rel_route", ColumnTypeIdentifier),
|
||||
// ColumnDef("weight", ColumnTypeInteger),
|
||||
// ColumnDef("kind", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("ref", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("enabled", ColumnTypeBoolean),
|
||||
// ColumnDef("params", ColumnTypeJson),
|
||||
// CUDTimestamps,
|
||||
// CUDUsers,
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableResourceActivityLog() *Table {
|
||||
// return TableDef("resource_activity_log",
|
||||
// ID,
|
||||
// ColumnDef("rel_resource", ColumnTypeIdentifier),
|
||||
// ColumnDef("resource_type", ColumnTypeText, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("resource_action", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("ts", ColumnTypeTimestamp),
|
||||
// ColumnDef("meta", ColumnTypeJson),
|
||||
//
|
||||
// AddIndex("rel_resource", IColumn("rel_resource")),
|
||||
// AddIndex("ts", IColumn("ts")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableDataPrivacyRequests() *Table {
|
||||
// return TableDef("data_privacy_requests",
|
||||
// ID,
|
||||
// ColumnDef("kind", ColumnTypeText, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("status", ColumnTypeVarchar, ColumnTypeLength(handleLength)),
|
||||
// ColumnDef("payload", ColumnTypeJson),
|
||||
// ColumnDef("requested_at", ColumnTypeTimestamp),
|
||||
// ColumnDef("requested_by", ColumnTypeIdentifier),
|
||||
// ColumnDef("completed_at", ColumnTypeTimestamp, Null),
|
||||
// ColumnDef("completed_by", ColumnTypeIdentifier, DefaultValue("0")),
|
||||
// CUDTimestamps,
|
||||
// CUDUsers,
|
||||
//
|
||||
// AddIndex("status", IColumn("status")),
|
||||
// )
|
||||
//}
|
||||
//
|
||||
//func tableDataPrivacyRequestComments() *Table {
|
||||
// return TableDef("data_privacy_request_comments",
|
||||
// ID,
|
||||
// ColumnDef("rel_request", ColumnTypeIdentifier),
|
||||
// ColumnDef("comment", ColumnTypeText),
|
||||
// CUDTimestamps,
|
||||
// CUDUsers,
|
||||
// )
|
||||
//}
|
||||
Reference in New Issue
Block a user