diff --git a/app/boot_dal.go b/app/boot_dal.go index 7ef7bbd7b..692f225de 100644 --- a/app/boot_dal.go +++ b/app/boot_dal.go @@ -31,36 +31,20 @@ func (app *CortezaApp) initDAL(ctx context.Context, log *zap.Logger) (err error) // load/create primary connection if conn, err = provisionPrimaryDalConnection(ctx, app.Store); err != nil { - return + return fmt.Errorf("could not provision primary connection: %w", err) } // Convert connection to dal.ConnectionWrap if cw, err = service.MakeDalConnection(conn, app.Store.ToDalConn()); err != nil { - return + return fmt.Errorf("could not convert connection: %w", err) } // Init DAL and prepare default connection dal.SetGlobal(dal.New(log.Named("dal"), app.Opt.Environment.IsDevelopment())) if err = dal.Service().ReplaceConnection(ctx, cw, true); err != nil { - return err + return fmt.Errorf("could not set primary connection: %w", err) } - // disabled for now until we have a real need (RDBMS table gen for example) for it - // - //// Register all models - //if err = atmModels.Register(ctx, dal.Service()); err != nil { - // return - //} - //if err = sysModels.Register(ctx, dal.Service()); err != nil { - // return - //} - //if err = cmpModels.Register(ctx, dal.Service()); err != nil { - // return - //} - //if err = fdrModels.Register(ctx, dal.Service()); err != nil { - // return - //} - return } diff --git a/automation/model/models.gen.go b/automation/model/models.gen.go index 456a14477..e6a9f12c7 100644 --- a/automation/model/models.gen.go +++ b/automation/model/models.gen.go @@ -24,186 +24,155 @@ var ( ResourceType: types.WorkflowResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ Ident: "Handle", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "handle"}, }, &dal.Attribute{ Ident: "Meta", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "meta"}, }, &dal.Attribute{ - Ident: "Enabled", - + Ident: "Enabled", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "enabled"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "enabled"}, }, &dal.Attribute{ Ident: "Trace", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "trace"}, }, &dal.Attribute{ Ident: "KeepSessions", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "keep_sessions"}, }, &dal.Attribute{ Ident: "Scope", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "scope"}, }, &dal.Attribute{ Ident: "Steps", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "steps"}, }, &dal.Attribute{ Ident: "Paths", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "paths"}, }, &dal.Attribute{ Ident: "Issues", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "issues"}, }, &dal.Attribute{ Ident: "RunAs", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "run_as"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ Ident: "OwnedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "owned_by"}, }, &dal.Attribute{ Ident: "CreatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "created_by"}, }, &dal.Attribute{ Ident: "UpdatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "updated_by"}, }, &dal.Attribute{ Ident: "DeletedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "deleted_by"}, }, }, @@ -214,140 +183,104 @@ var ( ResourceType: types.SessionResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ - Ident: "WorkflowID", - + Ident: "WorkflowID", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "rel_workflow"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "rel_workflow"}, }, &dal.Attribute{ - Ident: "EventType", - + Ident: "EventType", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "event_type"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "event_type"}, }, &dal.Attribute{ - Ident: "ResourceType", - + Ident: "ResourceType", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "resource_type"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "resource_type"}, }, &dal.Attribute{ - Ident: "Status", - + Ident: "Status", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "status"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "status"}, }, &dal.Attribute{ Ident: "Input", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "input"}, }, &dal.Attribute{ Ident: "Output", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "output"}, }, &dal.Attribute{ Ident: "Stacktrace", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "stacktrace"}, }, &dal.Attribute{ Ident: "CreatedBy", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "created_by"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "PurgeAt", - + Ident: "PurgeAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "purge_at"}, }, &dal.Attribute{ - Ident: "CompletedAt", - + Ident: "CompletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "completed_at"}, }, &dal.Attribute{ - Ident: "SuspendedAt", - + Ident: "SuspendedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "suspended_at"}, }, &dal.Attribute{ Ident: "Error", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "error"}, }, }, @@ -358,182 +291,155 @@ var ( ResourceType: types.TriggerResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ - Ident: "WorkflowID", - + Ident: "WorkflowID", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "rel_workflow"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "rel_workflow"}, }, &dal.Attribute{ Ident: "StepID", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "rel_step"}, }, &dal.Attribute{ - Ident: "Enabled", - + Ident: "Enabled", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "enabled"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "enabled"}, }, &dal.Attribute{ - Ident: "ResourceType", - + Ident: "ResourceType", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "resource_type"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "resource_type"}, }, &dal.Attribute{ - Ident: "EventType", - + Ident: "EventType", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "event_type"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "event_type"}, }, &dal.Attribute{ Ident: "Meta", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "meta"}, }, &dal.Attribute{ Ident: "Constraints", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "constraints"}, }, &dal.Attribute{ Ident: "Input", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "input"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ Ident: "OwnedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "owned_by"}, }, &dal.Attribute{ Ident: "CreatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "created_by"}, }, &dal.Attribute{ Ident: "UpdatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "updated_by"}, }, &dal.Attribute{ Ident: "DeletedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "deleted_by"}, }, }, } ) +func All() dal.ModelSet { + return dal.ModelSet{ + Workflow, + Session, + Trigger, + } +} + func Register(ctx context.Context, mr modelReplacer) (err error) { if err = mr.ReplaceModel(ctx, Workflow); err != nil { return diff --git a/codegen/assets/templates/gocode/dal/$component_model.go.tpl b/codegen/assets/templates/gocode/dal/$component_model.go.tpl index ee57ccb49..77e0fbd98 100644 --- a/codegen/assets/templates/gocode/dal/$component_model.go.tpl +++ b/codegen/assets/templates/gocode/dal/$component_model.go.tpl @@ -23,27 +23,22 @@ var ( ResourceType: {{ .resType }}, Attributes: dal.AttributeSet{ - {{ range .attributes }} + {{- range .attributes }} &dal.Attribute{ Ident: {{ printf "%q" .expIdent }}, - {{ if .primaryKey }}PrimaryKey: true, {{ end -}} {{ if .sortable }}Sortable: true, {{ end -}} {{ if .filterable }}Filterable: true, {{ end }} - - Type: {{ .dal.fqType }}{ + Type: &{{ .dal.fqType }}{ {{ if .dal.nullable }}Nullable: true,{{ end -}} {{ if eq .dal.type "Ref" }} RefAttribute: {{ printf "%q" .dal.attribute }}, RefModel: &dal.ModelRef{ ResourceType: {{ printf "%q" .dal.refModelResType }}, }, - {{ end }} + {{ end -}} }, - - {{ if .store }} Store: &dal.CodecAlias{Ident: {{ printf "%q" .storeIdent }}}, - {{ end }} }, {{ end -}} }, @@ -51,6 +46,15 @@ var ( {{ end }} ) +func All() dal.ModelSet { + return dal.ModelSet{ + {{- range .models }} + {{ .var }}, + {{- end }} + } +} + + func Register(ctx context.Context, mr modelReplacer) (err error) { {{- range .models }} if err = mr.ReplaceModel(ctx, {{ .var }}); err != nil { diff --git a/codegen/schema/model.cue b/codegen/schema/model.cue index 4b29d3edd..9b1e3d883 100644 --- a/codegen/schema/model.cue +++ b/codegen/schema/model.cue @@ -40,7 +40,12 @@ import ( expIdent: #expIdent | *strings.ToTitle(ident) // store identifier + // @todo this should be moved to dal.ident storeIdent: #ident | *name + + // enable or disable store for this attribute + // @todo we should use dal prop for this, and extend it to support bool "false" + // so that it can be disabled store: bool | *true unique: bool | *false @@ -60,6 +65,8 @@ import ( nullable: bool | *false + default?: string + if type == "ID" { generatedByStore: bool | *false } diff --git a/compose/model/models.gen.go b/compose/model/models.gen.go index 59e7be506..2104eca14 100644 --- a/compose/model/models.gen.go +++ b/compose/model/models.gen.go @@ -24,122 +24,94 @@ var ( ResourceType: types.AttachmentResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ - Ident: "OwnerID", - + Ident: "OwnerID", Sortable: true, - - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "rel_owner"}, }, &dal.Attribute{ Ident: "NamespaceID", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::compose:namespace", }, }, - Store: &dal.CodecAlias{Ident: "rel_namespace"}, }, &dal.Attribute{ - Ident: "Kind", - + Ident: "Kind", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "kind"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "kind"}, }, &dal.Attribute{ Ident: "Url", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "url"}, }, &dal.Attribute{ Ident: "PreviewUrl", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "preview_url"}, }, &dal.Attribute{ - Ident: "Name", - + Ident: "Name", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "name"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "name"}, }, &dal.Attribute{ Ident: "Meta", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "meta"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, }, @@ -150,88 +122,67 @@ var ( ResourceType: types.ChartResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ Ident: "Handle", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "handle"}, }, &dal.Attribute{ - Ident: "Name", - + Ident: "Name", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "name"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "name"}, }, &dal.Attribute{ Ident: "Config", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "config"}, }, &dal.Attribute{ Ident: "NamespaceID", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::compose:namespace", }, }, - Store: &dal.CodecAlias{Ident: "rel_namespace"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, }, @@ -242,102 +193,81 @@ var ( ResourceType: types.ModuleResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ Ident: "Handle", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "handle"}, }, &dal.Attribute{ Ident: "Meta", - Type: dal.TypeText{}, - + Type: &dal.TypeJSON{}, Store: &dal.CodecAlias{Ident: "meta"}, }, &dal.Attribute{ Ident: "Config", - Type: dal.TypeText{}, - + Type: &dal.TypeJSON{}, Store: &dal.CodecAlias{Ident: "config"}, }, &dal.Attribute{ Ident: "Fields", - Type: dal.TypeText{}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "fields"}, }, &dal.Attribute{ Ident: "NamespaceID", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::compose:namespace", }, }, - Store: &dal.CodecAlias{Ident: "rel_namespace"}, }, &dal.Attribute{ - Ident: "Name", - + Ident: "Name", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "name"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "name"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, }, @@ -348,146 +278,121 @@ var ( ResourceType: types.ModuleFieldResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ Ident: "ModuleID", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::compose:module", }, }, - Store: &dal.CodecAlias{Ident: "rel_module"}, }, &dal.Attribute{ Ident: "NamespaceID", - Type: dal.TypeText{}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "rel_namespace"}, }, &dal.Attribute{ - Ident: "Place", - + Ident: "Place", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "place"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "place"}, }, &dal.Attribute{ - Ident: "Kind", - + Ident: "Kind", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "kind"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "kind"}, }, &dal.Attribute{ - Ident: "Name", - + Ident: "Name", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "name"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "name"}, }, &dal.Attribute{ - Ident: "Label", - + Ident: "Label", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "label"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "label"}, }, &dal.Attribute{ Ident: "Options", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "options"}, }, &dal.Attribute{ Ident: "Config", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "config"}, }, &dal.Attribute{ Ident: "Required", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "is_required"}, }, &dal.Attribute{ Ident: "Multi", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "is_multi"}, }, &dal.Attribute{ Ident: "DefaultValue", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "default_value"}, }, &dal.Attribute{ Ident: "Expressions", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "expressions"}, }, &dal.Attribute{ Ident: "CreatedAt", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ Ident: "UpdatedAt", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ Ident: "DeletedAt", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, }, @@ -498,84 +403,61 @@ var ( ResourceType: types.NamespaceResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ - Ident: "Slug", - + Ident: "Slug", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "slug"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "slug"}, }, &dal.Attribute{ Ident: "Enabled", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "enabled"}, }, &dal.Attribute{ Ident: "Meta", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "meta"}, }, &dal.Attribute{ - Ident: "Name", - + Ident: "Name", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "name"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "name"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, }, @@ -586,158 +468,128 @@ var ( ResourceType: types.PageResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ - Ident: "SelfID", - + Ident: "SelfID", Sortable: true, - - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::compose:page", }, }, - Store: &dal.CodecAlias{Ident: "self_id"}, }, &dal.Attribute{ Ident: "ModuleID", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::compose:module", }, }, - Store: &dal.CodecAlias{Ident: "rel_module"}, }, &dal.Attribute{ Ident: "NamespaceID", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::compose:namespace", }, }, - Store: &dal.CodecAlias{Ident: "rel_namespace"}, }, &dal.Attribute{ Ident: "Handle", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "handle"}, }, &dal.Attribute{ Ident: "Config", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "config"}, }, &dal.Attribute{ Ident: "Blocks", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "blocks"}, }, &dal.Attribute{ Ident: "Children", - Type: dal.TypeText{}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "children"}, }, &dal.Attribute{ Ident: "Visible", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "visible"}, }, &dal.Attribute{ - Ident: "Weight", - + Ident: "Weight", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "weight"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "weight"}, }, &dal.Attribute{ - Ident: "Title", - + Ident: "Title", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "title"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "title"}, }, &dal.Attribute{ Ident: "Description", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "description"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, }, @@ -748,138 +600,131 @@ var ( ResourceType: types.RecordResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ Ident: "ModuleID", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "rel_module"}, }, &dal.Attribute{ Ident: "Module", - Type: dal.TypeText{}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "module"}, }, &dal.Attribute{ Ident: "Values", - Type: dal.TypeText{}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "values"}, }, &dal.Attribute{ Ident: "NamespaceID", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "rel_namespace"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ Ident: "OwnedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "owned_by"}, }, &dal.Attribute{ Ident: "CreatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "created_by"}, }, &dal.Attribute{ Ident: "UpdatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "updated_by"}, }, &dal.Attribute{ Ident: "DeletedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "deleted_by"}, }, }, } ) +func All() dal.ModelSet { + return dal.ModelSet{ + Attachment, + Chart, + Module, + ModuleField, + Namespace, + Page, + Record, + } +} + func Register(ctx context.Context, mr modelReplacer) (err error) { if err = mr.ReplaceModel(ctx, Attachment); err != nil { return diff --git a/compose/module.cue b/compose/module.cue index 9500d00b0..e0e4e0300 100644 --- a/compose/module.cue +++ b/compose/module.cue @@ -15,9 +15,18 @@ module: { attributes: { id: schema.IdField handle: schema.HandleField - meta: { goType: "rawJson" } - config: { goType: "types.ModuleConfig" } - fields: { goType: "types.ModuleFieldSet", store: false } + meta: { + goType: "rawJson" + dal: { type: "JSON" } + } + config: { + goType: "types.ModuleConfig" + dal: { type: "JSON" } + } + fields: { + goType: "types.ModuleFieldSet", + store: false + } namespace_id: { ident: "namespaceID", goType: "uint64", @@ -30,6 +39,16 @@ module: { updated_at: schema.SortableTimestampNilField deleted_at: schema.SortableTimestampNilField } + + indexes: { + "primary": "id" + "namespace": "namespace_id", + "unique_handle": { + unique: true + attributes: ["handle", "namespace_id"] + predicate: "handle <> '' AND deleted_at IS NULL" + } + } } filter: { diff --git a/federation/model/models.gen.go b/federation/model/models.gen.go index 3f183fada..a5e0a9e7d 100644 --- a/federation/model/models.gen.go +++ b/federation/model/models.gen.go @@ -24,138 +24,103 @@ var ( ResourceType: types.NodeResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ - Ident: "Name", - + Ident: "Name", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "name"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "name"}, }, &dal.Attribute{ - Ident: "SharedNodeID", - + Ident: "SharedNodeID", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "shared_node_id"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "shared_node_id"}, }, &dal.Attribute{ - Ident: "BaseURL", - + Ident: "BaseURL", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "base_url"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "base_url"}, }, &dal.Attribute{ - Ident: "Status", - + Ident: "Status", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "status"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "status"}, }, &dal.Attribute{ - Ident: "Contact", - + Ident: "Contact", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "contact"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "contact"}, }, &dal.Attribute{ Ident: "PairToken", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "pair_token"}, }, &dal.Attribute{ Ident: "AuthToken", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "auth_token"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ Ident: "CreatedBy", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "created_by"}, }, &dal.Attribute{ Ident: "UpdatedBy", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "updated_by"}, }, &dal.Attribute{ Ident: "DeletedBy", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "deleted_by"}, }, }, @@ -166,55 +131,39 @@ var ( ResourceType: types.NodeSyncResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "NodeID", - + Ident: "NodeID", PrimaryKey: true, Sortable: true, - - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "node_id"}, }, &dal.Attribute{ - Ident: "ModuleID", - + Ident: "ModuleID", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "module_id"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "module_id"}, }, &dal.Attribute{ - Ident: "SyncType", - + Ident: "SyncType", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "sync_type"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "sync_type"}, }, &dal.Attribute{ - Ident: "SyncStatus", - + Ident: "SyncStatus", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "sync_status"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "sync_status"}, }, &dal.Attribute{ - Ident: "TimeOfAction", - + Ident: "TimeOfAction", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "time_of_action"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "time_of_action"}, }, }, } @@ -224,142 +173,114 @@ var ( ResourceType: types.ExposedModuleResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ Ident: "Handle", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "handle"}, }, &dal.Attribute{ - Ident: "Name", - + Ident: "Name", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "name"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "name"}, }, &dal.Attribute{ - Ident: "NodeID", - + Ident: "NodeID", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "rel_node"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "rel_node"}, }, &dal.Attribute{ Ident: "ComposeModuleID", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "rel_compose_module"}, }, &dal.Attribute{ Ident: "ComposeNamespaceID", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "rel_compose_namespace"}, }, &dal.Attribute{ Ident: "Fields", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "fields"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ Ident: "CreatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "created_by"}, }, &dal.Attribute{ Ident: "UpdatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "updated_by"}, }, &dal.Attribute{ Ident: "DeletedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "deleted_by"}, }, }, @@ -370,136 +291,107 @@ var ( ResourceType: types.SharedModuleResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ Ident: "Handle", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "handle"}, }, &dal.Attribute{ - Ident: "NodeID", - + Ident: "NodeID", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "rel_node"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "rel_node"}, }, &dal.Attribute{ - Ident: "Name", - + Ident: "Name", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "name"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "name"}, }, &dal.Attribute{ - Ident: "ExternalFederationModuleID", - + Ident: "ExternalFederationModuleID", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "xref_module"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "xref_module"}, }, &dal.Attribute{ Ident: "Fields", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "fields"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ Ident: "CreatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "created_by"}, }, &dal.Attribute{ Ident: "UpdatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "updated_by"}, }, &dal.Attribute{ Ident: "DeletedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "deleted_by"}, }, }, @@ -510,58 +402,54 @@ var ( ResourceType: types.ModuleMappingResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "NodeID", - + Ident: "NodeID", PrimaryKey: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "node_id"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "node_id"}, }, &dal.Attribute{ - Ident: "FederationModuleID", - + Ident: "FederationModuleID", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "federation_module_id"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "federation_module_id"}, }, &dal.Attribute{ - Ident: "ComposeModuleID", - + Ident: "ComposeModuleID", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "compose_module_id"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "compose_module_id"}, }, &dal.Attribute{ - Ident: "ComposeNamespaceID", - + Ident: "ComposeNamespaceID", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "compose_namespace_id"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "compose_namespace_id"}, }, &dal.Attribute{ Ident: "FieldMapping", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "field_mapping"}, }, }, } ) +func All() dal.ModelSet { + return dal.ModelSet{ + Node, + NodeSync, + ExposedModule, + SharedModule, + ModuleMapping, + } +} + func Register(ctx context.Context, mr modelReplacer) (err error) { if err = mr.ReplaceModel(ctx, Node); err != nil { return diff --git a/pkg/dal/attribute_types.go b/pkg/dal/attribute_types.go index 92a6a4d09..12b2b05c9 100644 --- a/pkg/dal/attribute_types.go +++ b/pkg/dal/attribute_types.go @@ -14,9 +14,9 @@ type ( // Encoding/decoding might be different depending on // 1) underlying store (and dialect) // 2) value codec (raw, json ...) + // + // It is always Corteza ID TypeID struct { - // @todo need to figure out how to support when IDs - // generated/provided by store (SERIAL/AUTOINCREMENT) GeneratedByStore bool Nullable bool } diff --git a/pkg/dal/model.go b/pkg/dal/model.go index 7b74b315d..4f2c2a7ee 100644 --- a/pkg/dal/model.go +++ b/pkg/dal/model.go @@ -42,7 +42,9 @@ type ( Operations OperationSet Constraints map[string][]any + Indexes IndexSet } + ModelSet []*Model // Attribute describes a specific value of the dataset @@ -77,6 +79,14 @@ type ( } AttributeSet []*Attribute + + Index struct { + Ident string + Expressions []string + Predicate string + } + + IndexSet []*Index ) func PrimaryAttribute(ident string, codec Codec) *Attribute { @@ -107,6 +117,20 @@ func (a *Attribute) WithMultiValue() *Attribute { return a } +func (a *Attribute) StoreIdent() string { + switch s := a.Store.(type) { + case *CodecRecordValueSetJSON: + return s.Ident + + case *CodecAlias: + return s.Ident + + default: + return a.Ident + + } +} + func (mm ModelSet) FindByResourceID(resourceID uint64) *Model { for _, m := range mm { if m.ResourceID == resourceID { diff --git a/store/adapters/rdbms/dal/connection.go b/store/adapters/rdbms/dal/connection.go index 8e35e4f68..c9b3d8a78 100644 --- a/store/adapters/rdbms/dal/connection.go +++ b/store/adapters/rdbms/dal/connection.go @@ -3,6 +3,8 @@ package dal import ( "context" "fmt" + "github.com/cortezaproject/corteza-server/pkg/errors" + "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" "sync" "github.com/cortezaproject/corteza-server/pkg/dal" @@ -22,6 +24,8 @@ type ( db sqlx.ExtContext dialect drivers.Dialect + + dataDefiner ddl.DataDefiner } ) @@ -33,12 +37,13 @@ func init() { }) } -func Connection(db sqlx.ExtContext, dialect drivers.Dialect, cc ...dal.Operation) *connection { +func Connection(db sqlx.ExtContext, dialect drivers.Dialect, dd ddl.DataDefiner, cc ...dal.Operation) *connection { return &connection{ - db: db, - dialect: dialect, - models: make(map[string]*model), - operations: cc, + db: db, + dialect: dialect, + dataDefiner: dd, + models: make(map[string]*model), + operations: cc, } } @@ -117,36 +122,44 @@ func (c *connection) Models(ctx context.Context) (dal.ModelSet, error) { // CreateModel checks/creates db tables in the database and catches the processed model // // @todo DDL operations -func (c *connection) CreateModel(ctx context.Context, mm ...*dal.Model) error { +func (c *connection) CreateModel(ctx context.Context, mm ...*dal.Model) (err error) { c.mux.Lock() defer c.mux.Unlock() for _, m := range mm { - // @todo check if table exists and if the structure matches the model - // @todo check if table's columns are compatible with model's attributes - // @todo if table does not exist, create it + err = ddl.UpdateModel(ctx, c.dataDefiner, m) + if err == nil || !errors.IsNotFound(err) { + return + } + + if err = ddl.CreateModel(ctx, c.dataDefiner, m); err != nil { + return + } // cache the model c.models[cacheKey(m)] = Model(m, c.db, c.dialect) } - return nil + return } // DeleteModel removes db tables from the database and removes the processed model from cache // // @todo DDL operations // @todo some tables should not be removed (like compose_record on primary connection) -func (c *connection) DeleteModel(ctx context.Context, mm ...*dal.Model) error { +func (c *connection) DeleteModel(ctx context.Context, mm ...*dal.Model) (err error) { c.mux.Lock() defer c.mux.Unlock() for _, m := range mm { // @todo check if table exists and if it can be removed + if err = c.DeleteModel(ctx, m); err != nil { + return + } // remove from cache delete(c.models, cacheKey(m)) } - return nil + return } // UpdateModel alters db tables from the database and refreshes the processed model in the cache diff --git a/store/adapters/rdbms/ddl/commands.go b/store/adapters/rdbms/ddl/commands.go index f637bc899..2b387ad15 100644 --- a/store/adapters/rdbms/ddl/commands.go +++ b/store/adapters/rdbms/ddl/commands.go @@ -3,25 +3,18 @@ package ddl import ( "context" "fmt" - "github.com/doug-martin/goqu/v9" "github.com/doug-martin/goqu/v9/exp" "github.com/jmoiron/sqlx" ) type ( - trColTypeFn func(ColumnType) string - dialect interface { // GOQU returns goqu's dialect wrapper struct GOQU() goqu.DialectWrapper - - NativeColumnType(columnType ColumnType) string } CreateTable struct { - Dialect dialect - Table *Table OmitIfNotExistsClause bool @@ -29,29 +22,30 @@ type ( } CreateIndex struct { - Dialect dialect Index *Index OmitIfNotExistsClause bool OmitFieldLength bool } + DropIndex struct { + Ident exp.IdentifierExpression + TableIdent exp.IdentifierExpression + } + AddColumn struct { - Dialect dialect - Table *Table - Column *Column + Table exp.IdentifierExpression + Column *Column } DropColumn struct { - Dialect dialect - Table *Table - Column string + Table exp.IdentifierExpression + Column exp.IdentifierExpression } RenameColumn struct { - Dialect dialect - Table *Table - Old string - New string + Table exp.IdentifierExpression + Old exp.IdentifierExpression + New exp.IdentifierExpression } ) @@ -105,73 +99,6 @@ func Exec(ctx context.Context, db sqlx.ExtContext, ss ...any) (err error) { return } -func TableExists(ctx context.Context, db sqlx.QueryerContext, d dialect, table, schema string) (bool, error) { - return GetBool(ctx, db, GenTableCheck(d, table, schema)) -} - -func ColumnExists(ctx context.Context, db sqlx.QueryerContext, d dialect, column, table, schema string) (bool, error) { - return GetBool(ctx, db, GenColumnCheck(d, column, table, schema)) -} - -func GenTableCheck(d dialect, table, schema string) *goqu.SelectDataset { - return d.GOQU().Select(goqu.COUNT(goqu.Star()).Gt(0)). - From("information_schema.tables"). - Where( - exp.ParseIdentifier("table_name").Eq(table), - exp.ParseIdentifier("table_schema").Eq(schema), - ) -} - -func GenColumnCheck(d dialect, column, table, schema string) *goqu.SelectDataset { - return d.GOQU().Select(goqu.COUNT(goqu.Star()).Gt(0)). - From("information_schema.columns"). - Where( - exp.ParseIdentifier("table_name").Eq(table), - exp.ParseIdentifier("table_schema").Eq(schema), - exp.ParseIdentifier("column_name").Eq(column), - ) -} - -// -//func GenAddColumn(ctx context.Context, dialect dialect, db sqlx.ExtContext, t *Table, cc ...*Column) (err error) { -// var ( -// aux []any -// exists bool -// ) -// -// for _, c := range cc { -// // check column existence -// if exists, err = ColumnExists(ctx, db, dialect, c.Name, t.Name, "public"); err != nil { -// return -// } else if exists { -// // column exists -// continue -// } -// -// aux = append(aux, &AddColumn{ -// Dialect: dialect, -// Table: t, -// Column: c, -// }) -// } -// -// return Exec(ctx, db, aux...) -//} - -func IndexExists(ctx context.Context, db sqlx.QueryerContext, d dialect, index, table, schema string) (bool, error) { - return GetBool(ctx, db, GenIndexCheck(d, index, table, schema)) -} - -func GenIndexCheck(d dialect, index, table, schema string) *goqu.SelectDataset { - return d.GOQU().Select(goqu.COUNT(goqu.Star()).Gt(0)). - From("information_schema.statistics"). - Where( - exp.ParseIdentifier("index_name").Eq(index), - exp.ParseIdentifier("table_name").Eq(table), - exp.ParseIdentifier("table_schema").Eq(schema), - ) -} - func (t *CreateTable) String() string { sql := "CREATE TABLE " @@ -179,15 +106,15 @@ func (t *CreateTable) String() string { sql += "IF NOT EXISTS " } - sql += "\"" + t.Table.Name + "\" (\n" - sql += GenCreateTableBody(t.Table, t.Dialect.NativeColumnType) + sql += "\"" + t.Table.Ident + "\" (\n" + sql += GenCreateTableBody(t.Table) sql += "\n)" sql += t.SuffixClause return sql } -func GenCreateTableBody(t *Table, trColType trColTypeFn) string { +func GenCreateTableBody(t *Table) string { sql := "" for c, col := range t.Columns { @@ -197,23 +124,31 @@ func GenCreateTableBody(t *Table, trColType trColTypeFn) string { sql += ", " } - sql += GenTableColumn(col, trColType) + sql += GenTableColumn(col) sql += "\n" } - if t.PrimaryKey != nil { - sql += "\n, " + GenPrimaryKey(t.PrimaryKey) + // check if any of the indexes is a primary key + for _, pk := range t.Indexes { + if pk.Ident != PRIMARY_KEY { + continue + } + + sql += ", " + GenPrimaryKey(pk) + "\n" + break } return sql } -func GenTableColumn(col *Column, trType trColTypeFn) string { - sql := "\"" + col.Name + "\" " + trType(col.Type) +func GenTableColumn(col *Column) string { + sql := `"` + col.Ident + `"` + col.Type.Name + ` ` - if !col.IsNull { - sql += " NOT NULL" + if col.Type.Null { + sql += " NULL" + } else { + sql += "NOT NULL" } if col.DefaultValue > "" { @@ -229,7 +164,7 @@ func GenPrimaryKey(pk *Index) string { if f > 0 { sql += ", " } - sql += field.Field + sql += field.Column } sql += ")" @@ -249,61 +184,73 @@ func (t *CreateIndex) String() string { sql += "IF NOT EXISTS " } - sql += "\"" + t.Index.Name + "\" ON \"" + t.Index.Table + "\" (" + sql += "\"" + t.Index.Ident + "\" ON \"" + t.Index.TableIdent + "\" (" for f, field := range t.Index.Fields { + isExpr := len(field.Expression) > 0 + if f > 0 { sql += ", " } - if field.Expr { + if isExpr { sql += "(" + sql += field.Expression + } else { + sql += field.Column + } - sql += field.Field - - if field.Desc { + switch field.Sorted { + case IndexFieldSortDesc: sql += " DESC" + case IndexFieldSortAsc: + sql += " ASC" } if field.Length > 0 && !t.OmitFieldLength { sql += fmt.Sprintf("(%d)", field.Length) } - if field.Expr { + if isExpr { sql += ")" } } sql += ")" - if t.Index.Condition != "" { - sql += " WHERE " + t.Index.Condition + if t.Index.Predicate != "" { + sql += " WHERE " + t.Index.Predicate } return sql } -func (c *AddColumn) String() string { - sql := "ALTER TABLE" + " " + c.Table.Name + " ADD COLUMN " + c.Column.Name + " " + c.Dialect.NativeColumnType(c.Column.Type) - if !c.Column.IsNull { - sql += " NOT NULL" - } +//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 +//} - if len(c.Column.DefaultValue) > 0 { - sql += " DEFAULT " + c.Column.DefaultValue - } +//func (c *DropColumn) String() string { +// return "ALTER TABLE" + " " + c.Table.Name + " DROP COLUMN " + c.Column +//} - return sql +func (c *DropIndex) Express() exp.SQLExpression { + return SQLExpression(exp.NewLiteralExpression("DROP INDEX ? ON ?", c.Ident, c.TableIdent)) } -func (c *DropColumn) String() string { - return "ALTER TABLE" + " " + c.Table.Name + " DROP COLUMN " + c.Column -} - -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.Name + " 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) { var ( exists bool @@ -311,7 +258,7 @@ func GetBool(ctx context.Context, db sqlx.QueryerContext, query exp.SQLExpressio ) if err != nil { - return false, fmt.Errorf("could not generate SQLk") + return false, fmt.Errorf("could not generate SQL: %v", err) } if err = sqlx.GetContext(ctx, db, &exists, sql, args...); err != nil { @@ -321,38 +268,15 @@ func GetBool(ctx context.Context, db sqlx.QueryerContext, query exp.SQLExpressio return exists, nil } -// ColumnTypeTranslator is the most generic translator of "corteza types" -// to db-native column types. -// -// @todo it might be smart to merge this with data.AttributeType (part of CRS feature) -func ColumnTypeTranslator(ct ColumnType) string { - switch ct.Type { - case ColumnTypeIdentifier: - return "BIGINT" - case ColumnTypeVarchar: - if ct.Length > 0 { - // VARCHAR(0) is useless - return fmt.Sprintf("VARCHAR(%d)", ct.Length) - } - return "VARCHAR" - case ColumnTypeText: - return "TEXT" - case ColumnTypeJson: - return "JSON" - case ColumnTypeBinary: - return "BYTEA" - case ColumnTypeTimestamp: - if ct.Length > -1 { - // TIMESTAMPTZ(0) strips out milliseconds - return fmt.Sprintf("TIMESTAMPTZ(%d)", ct.Length) - } +// Structs is a utility function to simplify selecting data into slice of structs +func Structs(ctx context.Context, db sqlx.QueryerContext, query exp.SQLExpression, t any) error { + var ( + sql, args, err = query.ToSQL() + ) - return "TIMESTAMPTZ" - case ColumnTypeInteger: - return "INTEGER" - case ColumnTypeBoolean: - return "BOOLEAN" - default: - panic(fmt.Sprintf("unhandled column type: %d ", ct.Type)) + if err != nil { + return fmt.Errorf("could not generate SQL: %v", err) } + + return sqlx.SelectContext(ctx, db, t, sql, args...) } diff --git a/store/adapters/rdbms/ddl/dal_model.go b/store/adapters/rdbms/ddl/dal_model.go new file mode 100644 index 000000000..ec142d1a0 --- /dev/null +++ b/store/adapters/rdbms/ddl/dal_model.go @@ -0,0 +1,67 @@ +package ddl + +import ( + "context" + "fmt" + "github.com/cortezaproject/corteza-server/pkg/dal" +) + +// CreateModel creates table with columns and indexes that match Model definition +func CreateModel(ctx context.Context, dd DataDefiner, m *dal.Model) (err error) { + var ( + t *Table + ) + + if t, err = dd.ConvertModel(m); err != nil { + return err + } + + if err = dd.TableCreate(ctx, t); err != nil { + return err + } + + if err = EnsureIndexes(ctx, dd, m.Indexes...); err != nil { + return + } + + return +} + +func DeleteModel(ctx context.Context, dd DataDefiner, m *dal.Model) (err error) { + return fmt.Errorf("not implemented") +} + +// UpdateModel alters existing table's columns and indexes to match Model definition +func UpdateModel(ctx context.Context, dd DataDefiner, m *dal.Model) (err error) { + var ( + t *Table + ) + + if t, err = dd.TableLookup(ctx, m.Ident); err != nil { + return err + } + + // @todo check model against table structure + for _, attr := range m.Attributes { + // iterate over attributes and check if they exist in the table + col := t.ColumnByIdent(attr.Ident) + if col != nil { + // @todo check if column type matches + // @todo check if column is nullable + break + } + + // @todo add column to table + return fmt.Errorf("column %q on table %q not found; adding columns is not jet supported", attr.Ident, m.Ident) + } + + if err = EnsureIndexes(ctx, dd, m.Indexes...); err != nil { + return + } + + return +} + +func EnsureIndexes(ctx context.Context, dd DataDefiner, ii ...*dal.Index) (err error) { + return nil +} diff --git a/store/adapters/rdbms/ddl/data_definer.go b/store/adapters/rdbms/ddl/data_definer.go new file mode 100644 index 000000000..970a65b44 --- /dev/null +++ b/store/adapters/rdbms/ddl/data_definer.go @@ -0,0 +1,153 @@ +package ddl + +import ( + "context" + "fmt" + "github.com/cortezaproject/corteza-server/pkg/dal" +) + +type ( + driverDialect interface { + // NativeColumnType converts column type to type that can be used in the underlying rdbms + NativeColumnType(columnType dal.Type) (*ColumnType, error) + } + + // DataDefiner describes an interface for all DDL commands + DataDefiner interface { + ConvertModel(*dal.Model) (*Table, error) + + // Tables(ctx context.Context) ([]*Table, error) + TableLookup(context.Context, string) (*Table, error) + TableCreate(context.Context, *Table) error + + ColumnAdd(context.Context, string, *Column) error + ColumnDrop(context.Context, string, string) error + ColumnRename(context.Context, string, string, string) error + + IndexLookup(context.Context, string, string) (*Index, error) + IndexCreate(context.Context, string, *Index) error + IndexDrop(context.Context, string, string) error + } + + // Table describes structure of the SQL table + Table struct { + Ident string + Columns []*Column + Indexes []*Index + Comment string + + // implementation variations + Meta map[string]interface{} + } + + Column struct { + Ident string + Type *ColumnType + DefaultValue string + + // implementation variations + Meta map[string]interface{} + + Comment string + } + + ColumnType struct { + Name string + + // additional params for type + Parameters []any + + Null bool + + // implementation variations + Meta map[string]interface{} + } + + // Index describes structure of the SQL index + Index struct { + TableIdent string + Ident string + Type string + Fields []*IndexField + Unique bool + Predicate string + Comment string + + // implementation variations + Meta map[string]interface{} + } + + IndexFieldSorted int + + // IndexField describes a single field (column or expression) of the SQL index + IndexField struct { + // Expression or a single column + Column string + + Length int + + // Wrap part in parentheses + Expression string + + // Ascending or descending + Sorted IndexFieldSorted + + Statistics *IndexFieldStatistics + + // implementation variations + Meta map[string]interface{} + } + + IndexFieldStatistics struct { + // Cardinality is an indicator that refers to the uniqueness + // of all values in a column. Low cardinality means a lot + // of duplicate values in that column. For example, a column + // that stores the gender values has low cardinality. + // In contrast, high cardinality means that there are many distinct values. + Cardinality int64 + } +) + +const ( + PRIMARY_KEY = "PRIMARY" + + IndexFieldSortDesc = -1 + IndexFieldUnsorted = 0 + IndexFieldSortAsc = 1 +) + +func (t *Table) ColumnByIdent(i string) *Column { + for _, c := range t.Columns { + if c.Ident == i { + return c + } + } + + return nil +} + +// ConvertModel is generic model converter +func ConvertModel(m *dal.Model, d driverDialect) (t *Table, err error) { + t = &Table{Ident: m.Ident} + for _, a := range m.Attributes { + if a.Type == nil { + continue + } + + col := &Column{ + Ident: a.StoreIdent(), + Comment: a.Label, + } + + col.Type, err = d.NativeColumnType(a.Type) + if err != nil { + return nil, fmt.Errorf("could not convert attribute %q to column: %w", a.Ident, err) + } + + t.Columns = append(t.Columns, col) + } + + // @todo indexes + + return +} diff --git a/store/adapters/rdbms/ddl/data_definer_test.go b/store/adapters/rdbms/ddl/data_definer_test.go new file mode 100644 index 000000000..1baf55db6 --- /dev/null +++ b/store/adapters/rdbms/ddl/data_definer_test.go @@ -0,0 +1,68 @@ +package ddl + +import ( + "github.com/cortezaproject/corteza-server/pkg/dal" + "github.com/stretchr/testify/require" + "strings" + "testing" +) + +type ( + mockDriver struct{} +) + +func (mockDriver) NativeColumnType(ct dal.Type) (*ColumnType, error) { + col := &ColumnType{ + Name: string(ct.Type()), + Null: ct.IsNullable(), + } + + switch ct.(type) { + case *dal.TypeID: + col.Name = "INT" + } + + return col, nil +} + +func TestModelToTable(t *testing.T) { + + tests := []struct { + name string + m *dal.Model + d driverDialect + sql string + }{ + { + name: "simple", + d: mockDriver{}, + m: &dal.Model{ + Ident: "simple", + Attributes: dal.AttributeSet{ + &dal.Attribute{ + Ident: "null_ID", + Type: &dal.TypeID{ + Nullable: true, + }, + }, + }, + }, + + sql: ` +CREATE TABLE IF NOT EXISTS "simple" ( + "null_ID" INT NULL + +)`, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var req = require.New(t) + + tbl, err := ConvertModel(tt.m, tt.d) + req.NoError(err) + + req.Equal(strings.TrimSpace(tt.sql), strings.TrimSpace((&CreateTable{Table: tbl}).String())) + }) + } +} diff --git a/store/adapters/rdbms/ddl/def.go b/store/adapters/rdbms/ddl/def.go index 0d03111f9..fa81584e6 100644 --- a/store/adapters/rdbms/ddl/def.go +++ b/store/adapters/rdbms/ddl/def.go @@ -1,243 +1,249 @@ package ddl -import ( - "fmt" - "strings" -) - -type ( - tableManipulator func(*Table) - indexManipulator func(*Index) - columnManipulator func(*Column) - - Table struct { - Name string - Columns []*Column - Indexes []*Index - PrimaryKey *Index - } - - Index struct { - Name string - Table string - Fields []*IField - Unique bool - Condition string - - // someday maybe index type - } - - IField struct { - // Expression or a single column - Field string - - Length int - - // Wrap part in parenthesis - Expr bool - - // Ascending or descending - Desc bool - } - - columnType uint - ColumnType struct { - Type columnType - Length int - - // implementation variations - Flags map[string]interface{} - } - - Column struct { - Name string - Type ColumnType - IsNull bool - DefaultValue string - Comment string - } - - Columns []*Column -) - -const ( - // Subset of SQL types - // - // Just the ones we use in Corteza - // Each type should have its own formatter inside - - ColumnTypeIdentifier columnType = iota - ColumnTypeVarchar - ColumnTypeText - ColumnTypeBinary - ColumnTypeTimestamp - ColumnTypeInteger - ColumnTypeJson - ColumnTypeBoolean -) - -func TableDef(name string, mm ...tableManipulator) *Table { - var t = &Table{Name: name} - return t.Apply(mm...) -} - -func (t *Table) Apply(mm ...tableManipulator) *Table { - for _, m := range mm { - m(t) - } - - return t -} - -// Adds ID column and sets primary key -func ID(t *Table) { - t.Columns = append(t.Columns, &Column{ - Name: "id", - Type: ColumnType{Type: ColumnTypeIdentifier}, - Comment: fmt.Sprintf("Unique ID for %s", t.Name), - }) - - PrimaryKey(IColumn("id"))(t) -} - -// Adds created_at/updated_at/deleted-at columns -func CUDTimestamps(t *Table) { - t.Apply( - ColumnDef("created_at", ColumnTypeTimestamp), - ColumnDef("updated_at", ColumnTypeTimestamp, Null), - ColumnDef("deleted_at", ColumnTypeTimestamp, Null), - ) -} - -// Adds created_at/updated_at/deleted-by columns -func CUDUsers(t *Table) { - t.Apply( - ColumnDef("created_by", ColumnTypeIdentifier), - ColumnDef("updated_by", ColumnTypeIdentifier, DefaultValue("0")), - ColumnDef("deleted_by", ColumnTypeIdentifier, DefaultValue("0")), - ) -} - -func ColumnDef(name string, cType columnType, mm ...columnManipulator) tableManipulator { - return func(t *Table) { - typ := ColumnType{ - Type: cType, - Flags: make(map[string]interface{}), - - // Setting length to -1 - // - // This way we'll know if it was actually set to 0 - Length: -1, - } - col := &Column{Name: name, Type: typ} - - for _, m := range mm { - m(col) - } - - t.Columns = append(t.Columns, col) - } -} - -// AddIndex adds index to table -// If name has unique_ prefix it unique flag to true -func AddIndex(name string, mm ...indexManipulator) tableManipulator { - return func(t *Table) { - i := &Index{ - Name: name, - Table: t.Name, - Unique: strings.HasPrefix(name, "unique_"), - } - - for _, m := range mm { - m(i) - } - - t.Indexes = append(t.Indexes, i) - } -} - -func Null(c *Column) { - c.IsNull = true -} - -func ColumnTypeLength(l int) columnManipulator { - return func(c *Column) { - c.Type.Length = l - } -} - -func ColumnTypeFlag(n string, v interface{}) columnManipulator { - return func(c *Column) { - c.Type.Flags[n] = v - } -} - -// DefaultValue sets default value on column +//import ( +// "fmt" +// "strings" +//) // -// Note: avoid using NOW(), CURRENT_TIMESTAMP or other (volatile) function -// service layer should take care of this -func DefaultValue(v string) columnManipulator { - return func(c *Column) { - c.DefaultValue = v - } -} - -func PrimaryKey(mm ...indexManipulator) tableManipulator { - return func(t *Table) { - if t.PrimaryKey == nil { - t.PrimaryKey = &Index{} - } - - for _, m := range mm { - m(t.PrimaryKey) - } - } -} - -func Unique(i *Index) { - i.Unique = true -} - -// IColumn adds one or more keys as columns -func IColumn(cc ...string) indexManipulator { - return func(i *Index) { - for _, c := range cc { - i.Fields = append(i.Fields, &IField{Field: c}) - } - } -} - -// 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) { - for _, e := range ee { - i.Fields = append(i.Fields, &IField{Field: e, Expr: true}) - } - } -} - -func IWhere(cnd string) indexManipulator { - return func(i *Index) { - i.Condition = cnd - } -} - -func (cc Columns) Get(name string) *Column { - for c := range cc { - if cc[c].Name == name { - return cc[c] - } - } - - return nil -} +//type ( +// tableManipulator func(*Table) +// indexManipulator func(*Index) +// columnManipulator func(*Column) +// +// //Table struct { +// // Name string +// // Columns []*Column +// // Indexes []*Index +// // PrimaryKey *Index +// //} +// // +// //Index struct { +// // Name string +// // Table string +// // Fields []*IField +// // Unique bool +// // Condition string +// // +// // // someday maybe index type +// //} +// // +// //IField struct { +// // // Expression or a single column +// // Field string +// // +// // Length int +// // +// // // Wrap part in parentheses +// // Expr bool +// // +// // // Ascending or descending +// // Desc bool +// //} +// // +// //columnType uint +// //ColumnType struct { +// // Type columnType +// // Length int +// // +// // // implementation variations +// // Flags map[string]interface{} +// //} +// // +// //Column struct { +// // Name string +// // Type string +// // IsNull bool +// // DefaultValue string +// // Comment string +// //} +// // +// //Columns []*Column +//) +// +////const ( +//// // Subset of SQL types +//// // +//// // Just the ones we use in Corteza +//// // Each type should have its own formatter inside +//// +//// ColumnTypeIdentifier columnType = iota +//// ColumnTypeVarchar +//// ColumnTypeText +//// ColumnTypeBinary +//// ColumnTypeTimestamp +//// ColumnTypeInteger +//// ColumnTypeJson +//// ColumnTypeBoolean +////) +//// +//func TableDef(name string, mm ...tableManipulator) *Table { +// var t = &Table{Ident: name} +// return t.Apply(mm...) +//} +// +//func (t *Table) Apply(mm ...tableManipulator) *Table { +// for _, m := range mm { +// m(t) +// } +// +// return t +//} +// +//// Adds ID column and sets primary key +//func ID(t *Table) { +// panic("obsolete") +// t.Columns = append(t.Columns, &Column{ +// Name: "id", +// // Type: ColumnType{Type: ColumnTypeIdentifier}, +// Comment: fmt.Sprintf("Unique ID for %s", t.Name), +// }) +// +// PrimaryKey(IColumn("id"))(t) +//} +// +//// Adds created_at/updated_at/deleted-at columns +//func CUDTimestamps(t *Table) { +// panic("obsolete") +// t.Apply( +// ColumnDef("created_at", ColumnTypeTimestamp), +// ColumnDef("updated_at", ColumnTypeTimestamp, Null), +// ColumnDef("deleted_at", ColumnTypeTimestamp, Null), +// ) +//} +// +//// Adds created_at/updated_at/deleted-by columns +//func CUDUsers(t *Table) { +// panic("obsolete") +// t.Apply( +// ColumnDef("created_by", ColumnTypeIdentifier), +// ColumnDef("updated_by", ColumnTypeIdentifier, DefaultValue("0")), +// ColumnDef("deleted_by", ColumnTypeIdentifier, DefaultValue("0")), +// ) +//} +// +//func ColumnDef(name string, cType columnType, mm ...columnManipulator) tableManipulator { +// return func(t *Table) { +// typ := ColumnType{ +// Type: cType, +// Flags: make(map[string]interface{}), +// +// // Setting length to -1 +// // +// // This way we'll know if it was actually set to 0 +// Length: -1, +// } +// col := &Column{Name: name, Type: typ} +// +// for _, m := range mm { +// m(col) +// } +// +// t.Columns = append(t.Columns, col) +// } +//} +// +//// AddIndex adds index to table +//// If name has unique_ prefix it unique flag to true +//func AddIndex(name string, mm ...indexManipulator) tableManipulator { +// return func(t *Table) { +// i := &Index{ +// Name: name, +// Table: t.Name, +// Unique: strings.HasPrefix(name, "unique_"), +// } +// +// for _, m := range mm { +// m(i) +// } +// +// t.Indexes = append(t.Indexes, i) +// } +//} +// +//func Null(c *Column) { +// c.IsNull = true +//} +// +//func ColumnTypeLength(l int) columnManipulator { +// panic("obsolete") +// +// return func(c *Column) { +// //c.Type.Length = l +// } +//} +// +//func ColumnTypeFlag(n string, v interface{}) columnManipulator { +// panic("obsolete") +// return func(c *Column) { +// //c.Type.Flags[n] = v +// } +//} +// +//// DefaultValue sets default value on column +//// +//// Note: avoid using NOW(), CURRENT_TIMESTAMP or other (volatile) function +//// service layer should take care of this +//func DefaultValue(v string) columnManipulator { +// return func(c *Column) { +// c.DefaultValue = v +// } +//} +// +//func PrimaryKey(mm ...indexManipulator) tableManipulator { +// return func(t *Table) { +// if t.PrimaryKey == nil { +// t.PrimaryKey = &Index{} +// } +// +// for _, m := range mm { +// m(t.PrimaryKey) +// } +// } +//} +// +//func Unique(i *Index) { +// i.Unique = true +//} +// +//// IColumn adds one or more keys as columns +//func IColumn(cc ...string) indexManipulator { +// return func(i *Index) { +// for _, c := range cc { +// i.Fields = append(i.Fields, &IField{Field: c}) +// } +// } +//} +// +//// 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) { +// for _, e := range ee { +// i.Fields = append(i.Fields, &IField{Field: e, Expr: true}) +// } +// } +//} +// +//func IWhere(cnd string) indexManipulator { +// return func(i *Index) { +// i.Condition = cnd +// } +//} +// +//func (cc Columns) Get(name string) *Column { +// for c := range cc { +// if cc[c].Name == name { +// return cc[c] +// } +// } +// +// return nil +//} diff --git a/store/adapters/rdbms/ddl/goqu.go b/store/adapters/rdbms/ddl/goqu.go new file mode 100644 index 000000000..7d8f00c8d --- /dev/null +++ b/store/adapters/rdbms/ddl/goqu.go @@ -0,0 +1,23 @@ +package ddl + +import "github.com/doug-martin/goqu/v9/exp" + +// goqu's little helpers + +type ( + // literalExpression is a wrapper around goqu's LiteralExpression + sqlExpression struct { + exp.LiteralExpression + } +) + +func SQLExpression(e exp.LiteralExpression) exp.SQLExpression { + return &sqlExpression{e} +} + +func (e *sqlExpression) ToSQL() (string, []any, error) { return e.Literal(), e.Args(), nil } +func (e *sqlExpression) IsPrepared() bool { return e.IsPrepared() } + +var ( + _ exp.SQLExpression = &sqlExpression{} +) diff --git a/store/adapters/rdbms/drivers/dialect.go b/store/adapters/rdbms/drivers/dialect.go index 5367d9acf..f05f16580 100644 --- a/store/adapters/rdbms/drivers/dialect.go +++ b/store/adapters/rdbms/drivers/dialect.go @@ -34,7 +34,7 @@ type ( TypeWrap(dal.Type) Type // NativeColumnType converts column type to type that can be used in the underlying rdbms - NativeColumnType(columnType ddl.ColumnType) string + NativeColumnType(columnType dal.Type) (*ddl.ColumnType, error) // ExprHandler returns driver specific expression handling ExprHandler(*ql.ASTNode, ...exp.Expression) (exp.Expression, error) diff --git a/store/adapters/rdbms/drivers/mysql/connect.go b/store/adapters/rdbms/drivers/mysql/connect.go index dbc11e50c..d85c6899d 100644 --- a/store/adapters/rdbms/drivers/mysql/connect.go +++ b/store/adapters/rdbms/drivers/mysql/connect.go @@ -4,11 +4,10 @@ import ( "context" "database/sql" "fmt" + "github.com/cortezaproject/corteza-server/store/adapters/rdbms/dal" "strings" pkgdal "github.com/cortezaproject/corteza-server/pkg/dal" - "github.com/cortezaproject/corteza-server/store/adapters/rdbms/dal" - "github.com/cortezaproject/corteza-server/pkg/errors" "github.com/cortezaproject/corteza-server/pkg/logger" "github.com/cortezaproject/corteza-server/store" @@ -46,13 +45,13 @@ func Connect(ctx context.Context, dsn string) (_ store.Storer, err error) { s := &rdbms.Store{ DB: db, - DAL: dal.Connection(db, Dialect(), pkgdal.FullOperations()...), + DAL: dal.Connection(db, Dialect(), DataDefiner(cfg.DBName, db), pkgdal.FullOperations()...), Dialect: goquDialectWrapper, TxRetryErrHandler: txRetryErrHandler, ErrorHandler: errorHandler, - SchemaAPI: &schema{dbName: cfg.DBName}, + DataDefiner: DataDefiner(cfg.DBName, db), } s.SetDefaults() diff --git a/store/adapters/rdbms/drivers/mysql/dal.go b/store/adapters/rdbms/drivers/mysql/dal.go index 6ba98f058..8e341bbed 100644 --- a/store/adapters/rdbms/drivers/mysql/dal.go +++ b/store/adapters/rdbms/drivers/mysql/dal.go @@ -27,5 +27,5 @@ func dalConnector(ctx context.Context, dsn string, cc ...dal.Operation) (_ dal.C if err != nil { return } - return rdbmsdal.Connection(db, Dialect(), cc...), nil + return rdbmsdal.Connection(db, Dialect(), DataDefiner(cfg.DBName, db), cc...), nil } diff --git a/store/adapters/rdbms/drivers/mysql/data_definer.go b/store/adapters/rdbms/drivers/mysql/data_definer.go new file mode 100644 index 000000000..6adb13e58 --- /dev/null +++ b/store/adapters/rdbms/drivers/mysql/data_definer.go @@ -0,0 +1,218 @@ +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" +) + +type ( + // dataDefiner for MySQL + dataDefiner struct { + dbName string + conn *sqlx.DB + is *informationSchema + d *mysqlDialect + } +) + +var ( + _ ddl.DataDefiner = new(dataDefiner) +) + +func DataDefiner(dbName string, conn *sqlx.DB) *dataDefiner { + return &dataDefiner{ + dbName: dbName, + conn: conn, + is: InformationSchema(conn), + d: Dialect(), + } +} + +func (dd *dataDefiner) ConvertModel(m *dal.Model) (*ddl.Table, error) { + return ddl.ConvertModel(m, dd.d) +} + +func (dd *dataDefiner) TableCreate(ctx context.Context, t *ddl.Table) error { + return ddl.Exec(ctx, dd.conn, &ddl.CreateTable{Table: t}) +} + +func (dd *dataDefiner) TableLookup(ctx context.Context, t string) (*ddl.Table, error) { + return dd.is.TableLookup(ctx, t, dd.dbName) +} + +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, ""), + 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), + }) +} + +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), + }) +} + +func (dd *dataDefiner) IndexLookup(ctx context.Context, i, t string) (*ddl.Index, error) { + if index, err := dd.is.IndexLookup(ctx, i, t, dd.dbName); err != nil { + return nil, err + } else { + return index, nil + } +} + +func (dd *dataDefiner) IndexCreate(ctx context.Context, t string, i *ddl.Index) error { + return ddl.Exec(ctx, dd.conn, &ddl.CreateIndex{Index: i}) +} + +func (dd *dataDefiner) IndexDrop(ctx context.Context, t, i string) error { + return ddl.Exec(ctx, dd.conn, &ddl.DropIndex{Ident: exp.NewIdentifierExpression("", t, i)}) +} + +// +//// TableExists checks if table exists in the MySQL database +//func (s *schema) TableExists(ctx context.Context, db sqlx.QueryerContext, table string) (bool, error) { +// return ddl.TableExists(ctx, db, Dialect(), table, s.dbName) +//} +// +//// ColumnExists checks if column exists in the MySQL table +//func (s *schema) ColumnExists(ctx context.Context, db sqlx.QueryerContext, column, table string) (bool, error) { +// return ddl.ColumnExists(ctx, db, Dialect(), column, table, s.dbName) +//} +// +//// CreateTable +//// +//// MySQL does not hav CREATE-INDEX-IF-NOT-EXISTS; we need to check index existence manually +//func (s *schema) CreateTable(ctx context.Context, db sqlx.ExtContext, t *ddl.Table) (err error) { +// +// tc := &ddl.CreateTable{ +// Dialect: Dialect(), +// Table: t, +// SuffixClause: "ENGINE=InnoDB DEFAULT CHARSET=utf8", +// } +// +// if err = ddl.Exec(ctx, db, tc); err != nil { +// return +// } +// +// for _, index := range t.Indexes { +// if index.Condition != "" { +// // MySQL, sad little DB does not support +// // conditional indexes +// // +// // We'll solve this on an application level +// continue +// } +// +// var doesIt bool +// if doesIt, err = ddl.IndexExists(ctx, db, Dialect(), index.Name, index.Table, s.dbName); err != nil { +// return +// } else if doesIt { +// continue +// } +// +// ic := &ddl.CreateIndex{ +// Dialect: Dialect(), +// Index: index, +// OmitIfNotExistsClause: true, +// } +// +// if err = ddl.Exec(ctx, db, ic); err != nil { +// return +// } +// +// } +// +// return +//} +// +//func (s *schema) AddColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, cc ...*ddl.Column) (err error) { +// var ( +// aux []any +// exists bool +// ) +// +// for _, c := range cc { +// // check column existence +// if exists, err = s.ColumnExists(ctx, db, c.Name, t.Name); err != nil { +// return +// } else if exists { +// // column exists +// continue +// } +// +// // Sadly, some column types in MySQL can not have default values +// if c.Type.Type == ddl.ColumnTypeJson || c.Type.Type == ddl.ColumnTypeBinary || c.Type.Type == ddl.ColumnTypeText { +// c.DefaultValue = "" +// } +// +// aux = append(aux, &ddl.AddColumn{ +// Dialect: dialect, +// Table: t, +// Column: c, +// }) +// } +// +// return ddl.Exec(ctx, db, aux...) +//} +// +//func (s *schema) DropColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, cc ...string) (err error) { +// var ( +// aux []any +// exists bool +// ) +// +// for _, c := range cc { +// // check column existence +// if exists, err = s.ColumnExists(ctx, db, c, t.Name); err != nil { +// return +// } else if !exists { +// // column exists +// continue +// } +// +// aux = append(aux, &ddl.DropColumn{ +// Dialect: dialect, +// Table: t, +// Column: c, +// }) +// } +// +// return ddl.Exec(ctx, db, aux...) +//} +// +//func (s *schema) RenameColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, old, new string) (err error) { +// var ( +// exists bool +// ) +// +// if exists, err = s.ColumnExists(ctx, db, old, t.Name); err != nil || !exists { +// // error or old column does not exist +// return +// } +// +// if exists, err = s.ColumnExists(ctx, db, new, t.Name); err != nil || exists { +// // error or new column already exists +// return +// } +// +// return ddl.Exec(ctx, db, &ddl.RenameColumn{ +// Dialect: dialect, +// Table: t, +// Old: old, +// New: new, +// }) +//} diff --git a/store/adapters/rdbms/drivers/mysql/dialect.go b/store/adapters/rdbms/drivers/mysql/dialect.go index 42e3b7094..67ae8c108 100644 --- a/store/adapters/rdbms/drivers/mysql/dialect.go +++ b/store/adapters/rdbms/drivers/mysql/dialect.go @@ -99,10 +99,6 @@ func (mysqlDialect) AttributeCast(attr *dal.Attribute, val exp.LiteralExpression return exp.NewLiteralExpression("?", c), nil } -func (mysqlDialect) NativeColumnType(ct ddl.ColumnType) string { - return columnTypeTranslator(ct) -} - func (mysqlDialect) ExprHandler(n *ql.ASTNode, args ...exp.Expression) (exp.Expression, error) { return ql.DefaultRefHandler(n, args...) } @@ -131,3 +127,55 @@ func JSONPath(ident exp.IdentifierExpression, pp ...any) (exp.LiteralExpression, sql.WriteString(`'`) return exp.NewLiteralExpression(sql.String(), ident), nil } + +func (mysqlDialect) NativeColumnType(t dal.Type) (ct *ddl.ColumnType, err error) { + ct = &ddl.ColumnType{ + Null: t.IsNullable(), + } + + switch c := t.(type) { + case *dal.TypeID, *dal.TypeRef: + ct.Name = "BIGINT" + + case *dal.TypeTimestamp: + ct.Name = "DATETIME" + + case *TypeTime: + ct.Name = "TIME" + + case *dal.TypeDate: + ct.Name = "DATE" + + case *dal.TypeNumber: + ct.Name = "DECIMAL" + // @todo precision, scale? + + case *dal.TypeText: + if c.Length > 0 { + // VARCHAR(0) is useless + ct.Name = fmt.Sprintf("VARCHAR(%d)", c.Length) + } else { + ct.Name = "TEXT" + } + + case *dal.TypeJSON: + ct.Name = "JSON" + + case *dal.TypeGeometry: + ct.Name = "JSON" + + case *dal.TypeBlob: + ct.Name = "BLOB" + + case *dal.TypeBoolean: + ct.Name = "TINYINT(1)" + + case *dal.TypeUUID: + ct.Name = "CHAR(36)" + + default: + return nil, fmt.Errorf("unsupported column type: %s ", c.Type()) + } + + return +} diff --git a/store/adapters/rdbms/drivers/mysql/information_schema.go b/store/adapters/rdbms/drivers/mysql/information_schema.go new file mode 100644 index 000000000..5a3c9c6dd --- /dev/null +++ b/store/adapters/rdbms/drivers/mysql/information_schema.go @@ -0,0 +1,206 @@ +package mysql + +import ( + "context" + "database/sql" + "github.com/cortezaproject/corteza-server/pkg/errors" + "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" + "github.com/doug-martin/goqu/v9" + "github.com/doug-martin/goqu/v9/exp" + "github.com/jmoiron/sqlx" +) + +type ( + informationSchema struct { + conn *sqlx.DB + } +) + +func InformationSchema(conn *sqlx.DB) *informationSchema { + return &informationSchema{ + conn: conn, + } +} + +func (i *informationSchema) TableLookup(ctx context.Context, table, dbname string) (*ddl.Table, error) { + var ( + oneTable = i.columnSelect().Where( + exp.ParseIdentifier("TABLE_CATALOG").Eq("def"), + // schema == dbname in MySQL world + exp.ParseIdentifier("TABLE_SCHEMA").Eq(dbname), + exp.ParseIdentifier("TABLE_NAME").Eq(table), + ) + ) + + if out, err := i.scanColumns(ctx, oneTable); err != nil { + return nil, err + } else if len(out) > 0 { + return out[0], nil + } else { + return nil, errors.NotFound("table does not exist") + } +} + +func (i *informationSchema) columnSelect() *goqu.SelectDataset { + return dialect.GOQU().Select( + "TABLE_NAME", + "COLUMN_NAME", + "IS_NULLABLE", + "DATA_TYPE", + ). + From("information_schema.columns"). + Order( + exp.NewOrderedExpression(exp.ParseIdentifier("TABLE_SCHEMA"), exp.AscDir, exp.NoNullsSortType), + exp.NewOrderedExpression(exp.ParseIdentifier("ORDINAL_POSITION"), exp.AscDir, exp.NoNullsSortType), + ) +} + +func (i *informationSchema) scanColumns(ctx context.Context, sd *goqu.SelectDataset) (out []*ddl.Table, err error) { + var ( + at int + has bool + n2p = make(map[string]int) + + // https://dev.mysql.com/doc/mysql-infoschema-excerpt/5.7/en/information-schema-statistics-table.html + aux = make([]struct { + Table string `db:"TABLE_NAME"` + Column string `db:"COLUMN_NAME"` + IsNullable string `db:"IS_NULLABLE"` + Type string `db:"DATA_TYPE"` + }, 0) + ) + + if err = ddl.Structs(ctx, i.conn, sd, &aux); err != nil { + return + } + + out = make([]*ddl.Table, 0, 10) + + for _, v := range aux { + if at, has = n2p[v.Table]; !has { + at = len(out) + n2p[v.Table] = at + out = append(out, &ddl.Table{Ident: v.Table}) + } + + out[at].Columns = append(out[at].Columns, &ddl.Column{ + Ident: v.Column, + Type: &ddl.ColumnType{ + Name: v.Type, + Null: v.IsNullable == "YES", + }, + }) + } + + return +} + +func (i *informationSchema) IndexLookup(ctx context.Context, index, table, dbname string) (*ddl.Index, error) { + var ( + oneIndexOnly = i.indexSelect().Where( + exp.ParseIdentifier("TABLE_SCHEMA").Eq(dbname), + exp.ParseIdentifier("INDEX_NAME").Eq(index), + exp.ParseIdentifier("TABLE_NAME").Eq(table), + ) + ) + + if out, err := i.scanIndexes(ctx, oneIndexOnly); err != nil { + return nil, err + } else if len(out) > 0 { + return out[0], nil + } else { + return nil, nil + } +} + +func (i *informationSchema) indexSelect() *goqu.SelectDataset { + return dialect.GOQU().Select( + "INDEX_NAME", + "TABLE_NAME", + "COLUMN_NAME", + "INDEX_TYPE", + "EXPRESSION", + "INDEX_COMMENT", + ). + From("information_schema.statistics"). + Order( + exp.NewOrderedExpression(exp.ParseIdentifier("TABLE_SCHEMA"), exp.AscDir, exp.NoNullsSortType), + exp.NewOrderedExpression(exp.ParseIdentifier("INDEX_NAME"), exp.AscDir, exp.NoNullsSortType), + exp.NewOrderedExpression(exp.ParseIdentifier("SEQ_IN_INDEX"), exp.AscDir, exp.NoNullsSortType), + ) +} + +func (i *informationSchema) scanIndexes(ctx context.Context, sd *goqu.SelectDataset) (out []*ddl.Index, err error) { + var ( + at int + has bool + n2p = make(map[string]int) + + // https://dev.mysql.com/doc/mysql-infoschema-excerpt/5.7/en/information-schema-statistics-table.html + aux = make([]struct { + Name string `db:"INDEX_NAME"` + Table string `db:"TABLE_NAME"` + NonUnique bool `db:"NON_UNIQUE"` + Type string `db:"INDEX_TYPE"` + + // @todo there's also a "COMMENT" column? + Comment string `db:"INDEX_COMMENT"` + + Expression sql.NullString `db:"EXPRESSION"` + ColumnName string `db:"COLUMN_NAME"` + ColumnSubPart sql.NullInt32 `db:"SUB_PART"` + ColumnCollation sql.NullString `db:"COLLATION"` + + // stats + ColumnStatsCardinality int64 `db:"CARDINALITY"` + }, 0) + ) + + if err = ddl.Structs(ctx, i.conn, sd, &aux); err != nil { + return + } + + out = make([]*ddl.Index, 0, 10) + + // iterate over results (aux) and populate ddl.Index struct + for p, a := range aux { + if at, has = n2p[a.Name]; !has { + out = append(out, &ddl.Index{ + Ident: a.Name, + TableIdent: a.Table, + Type: a.Type, + Comment: a.Comment, + Fields: make([]*ddl.IndexField, 0), + Unique: !a.NonUnique, + Predicate: "", + Meta: nil, + }) + n2p[a.Name] = p + at = p + } + + col := &ddl.IndexField{ + Length: int(a.ColumnSubPart.Int32), + Statistics: &ddl.IndexFieldStatistics{ + Cardinality: a.ColumnStatsCardinality, + }, + } + + switch a.ColumnCollation.String { + case "A": + col.Sorted = ddl.IndexFieldSortAsc + case "D": + col.Sorted = ddl.IndexFieldSortDesc + } + + if a.Expression.Valid { + col.Expression = a.Expression.String + } else { + col.Column = a.ColumnName + } + + out[at].Fields = append(out[at].Fields, col) + } + + return +} diff --git a/store/adapters/rdbms/drivers/mysql/schema.go b/store/adapters/rdbms/drivers/mysql/schema.go deleted file mode 100644 index 9f1b79219..000000000 --- a/store/adapters/rdbms/drivers/mysql/schema.go +++ /dev/null @@ -1,147 +0,0 @@ -package mysql - -import ( - "context" - - "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" - "github.com/jmoiron/sqlx" -) - -type ( - schema struct { - dbName string - } -) - -// TableExists checks if table exists in the MySQL database -func (s *schema) TableExists(ctx context.Context, db sqlx.QueryerContext, table string) (bool, error) { - return ddl.TableExists(ctx, db, Dialect(), table, s.dbName) -} - -// ColumnExists checks if column exists in the MySQL table -func (s *schema) ColumnExists(ctx context.Context, db sqlx.QueryerContext, column, table string) (bool, error) { - return ddl.ColumnExists(ctx, db, Dialect(), column, table, s.dbName) -} - -// CreateTable -// -// MySQL does not hav CREATE-INDEX-IF-NOT-EXISTS; we need to check index existence manually -func (s *schema) CreateTable(ctx context.Context, db sqlx.ExtContext, t *ddl.Table) (err error) { - tc := &ddl.CreateTable{ - Dialect: Dialect(), - Table: t, - SuffixClause: "ENGINE=InnoDB DEFAULT CHARSET=utf8", - } - - if err = ddl.Exec(ctx, db, tc); err != nil { - return - } - - for _, index := range t.Indexes { - if index.Condition != "" { - // MySQL, sad little DB does not support - // conditional indexes - // - // We'll solve this on an application level - continue - } - - var doesIt bool - if doesIt, err = ddl.IndexExists(ctx, db, Dialect(), index.Name, index.Table, s.dbName); err != nil { - return - } else if doesIt { - continue - } - - ic := &ddl.CreateIndex{ - Dialect: Dialect(), - Index: index, - OmitIfNotExistsClause: true, - } - - if err = ddl.Exec(ctx, db, ic); err != nil { - return - } - - } - - return -} - -func (s *schema) AddColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, cc ...*ddl.Column) (err error) { - var ( - aux []any - exists bool - ) - - for _, c := range cc { - // check column existence - if exists, err = s.ColumnExists(ctx, db, c.Name, t.Name); err != nil { - return - } else if exists { - // column exists - continue - } - - // Sadly, some column types in MySQL can not have default values - if c.Type.Type == ddl.ColumnTypeJson || c.Type.Type == ddl.ColumnTypeBinary || c.Type.Type == ddl.ColumnTypeText { - c.DefaultValue = "" - } - - aux = append(aux, &ddl.AddColumn{ - Dialect: dialect, - Table: t, - Column: c, - }) - } - - return ddl.Exec(ctx, db, aux...) -} - -func (s *schema) DropColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, cc ...string) (err error) { - var ( - aux []any - exists bool - ) - - for _, c := range cc { - // check column existence - if exists, err = s.ColumnExists(ctx, db, c, t.Name); err != nil { - return - } else if !exists { - // column exists - continue - } - - aux = append(aux, &ddl.DropColumn{ - Dialect: dialect, - Table: t, - Column: c, - }) - } - - return ddl.Exec(ctx, db, aux...) -} - -func (s *schema) RenameColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, old, new string) (err error) { - var ( - exists bool - ) - - if exists, err = s.ColumnExists(ctx, db, old, t.Name); err != nil || !exists { - // error or old column does not exist - return - } - - if exists, err = s.ColumnExists(ctx, db, new, t.Name); err != nil || exists { - // error or new column already exists - return - } - - return ddl.Exec(ctx, db, &ddl.RenameColumn{ - Dialect: dialect, - Table: t, - Old: old, - New: new, - }) -} diff --git a/store/adapters/rdbms/drivers/mysql/types.go b/store/adapters/rdbms/drivers/mysql/types.go index 057806e4e..c97e800c1 100644 --- a/store/adapters/rdbms/drivers/mysql/types.go +++ b/store/adapters/rdbms/drivers/mysql/types.go @@ -4,7 +4,6 @@ import ( "database/sql" "database/sql/driver" "fmt" - "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" "time" "github.com/cortezaproject/corteza-server/pkg/dal" @@ -42,17 +41,17 @@ func (t *TypeTime) Encode(val any) (driver.Value, error) { return val, nil } -func columnTypeTranslator(ct ddl.ColumnType) string { - switch ct.Type { - case ddl.ColumnTypeIdentifier: - return "BIGINT UNSIGNED" - case ddl.ColumnTypeBinary: - return "BLOB" - case ddl.ColumnTypeTimestamp: - return "DATETIME" - case ddl.ColumnTypeBoolean: - return "TINYINT(1)" - default: - return ddl.ColumnTypeTranslator(ct) - } -} +//func columnTypeTranslator(ct ddl.ColumnType) string { +// switch ct.Type { +// case ddl.ColumnTypeIdentifier: +// return "BIGINT UNSIGNED" +// case ddl.ColumnTypeBinary: +// return "BLOB" +// case ddl.ColumnTypeTimestamp: +// return "DATETIME" +// case ddl.ColumnTypeBoolean: +// return "TINYINT(1)" +// default: +// return ddl.ColumnTypeTranslator(ct) +// } +//} diff --git a/store/adapters/rdbms/drivers/postgres/connect.go b/store/adapters/rdbms/drivers/postgres/connect.go index cbef08951..bbeb2ec9c 100644 --- a/store/adapters/rdbms/drivers/postgres/connect.go +++ b/store/adapters/rdbms/drivers/postgres/connect.go @@ -50,12 +50,12 @@ func Connect(ctx context.Context, dsn string) (_ store.Storer, err error) { s := &rdbms.Store{ DB: db, - DAL: dal.Connection(db, Dialect(), pkgdal.FullOperations()...), + DAL: dal.Connection(db, Dialect(), DataDefiner(cfg.DBName, db), pkgdal.FullOperations()...), Dialect: goquDialectWrapper, ErrorHandler: errorHandler, - SchemaAPI: &schema{schemaName: "public"}, + DataDefiner: DataDefiner(cfg.DBName, db), } s.SetDefaults() diff --git a/store/adapters/rdbms/drivers/postgres/dal.go b/store/adapters/rdbms/drivers/postgres/dal.go index 1934b3a2f..28c6b6e16 100644 --- a/store/adapters/rdbms/drivers/postgres/dal.go +++ b/store/adapters/rdbms/drivers/postgres/dal.go @@ -33,5 +33,5 @@ func dalConnector(ctx context.Context, dsn string, cc ...dal.Operation) (_ dal.C return } - return rdbmsdal.Connection(db, Dialect(), cc...), nil + return rdbmsdal.Connection(db, Dialect(), DataDefiner(cfg.DBName, db), cc...), nil } diff --git a/store/adapters/rdbms/drivers/postgres/data_definer.go b/store/adapters/rdbms/drivers/postgres/data_definer.go new file mode 100644 index 000000000..0b8c374a5 --- /dev/null +++ b/store/adapters/rdbms/drivers/postgres/data_definer.go @@ -0,0 +1,217 @@ +package postgres + +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" +) + +type ( + // dataDefiner for MySQL + dataDefiner struct { + dbName string + conn *sqlx.DB + is *informationSchema + d *postgresDialect + } +) + +var ( + _ ddl.DataDefiner = new(dataDefiner) +) + +func DataDefiner(dbName string, conn *sqlx.DB) *dataDefiner { + return &dataDefiner{ + dbName: dbName, + conn: conn, + is: InformationSchema(conn), + d: Dialect(), + } +} + +func (dd *dataDefiner) ConvertModel(m *dal.Model) (*ddl.Table, error) { + return ddl.ConvertModel(m, dd.d) +} + +func (dd *dataDefiner) TableCreate(ctx context.Context, t *ddl.Table) error { + return ddl.Exec(ctx, dd.conn, &ddl.CreateTable{Table: t}) +} + +func (dd *dataDefiner) TableLookup(ctx context.Context, t string) (*ddl.Table, error) { + return dd.is.TableLookup(ctx, t, "public", dd.dbName) +} + +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, ""), + 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), + }) +} + +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), + }) +} + +func (dd *dataDefiner) IndexLookup(ctx context.Context, i, t string) (*ddl.Index, error) { + if index, err := dd.is.IndexLookup(ctx, i, t, dd.dbName); err != nil { + return nil, err + } else { + return index, nil + } +} + +func (dd *dataDefiner) IndexCreate(ctx context.Context, t string, i *ddl.Index) error { + return ddl.Exec(ctx, dd.conn, &ddl.CreateIndex{Index: i}) +} + +func (dd *dataDefiner) IndexDrop(ctx context.Context, t, i string) error { + return ddl.Exec(ctx, dd.conn, &ddl.DropIndex{Ident: exp.NewIdentifierExpression("", t, i)}) +} + +// +//// TableExists checks if table exists in the MySQL database +//func (s *schema) TableExists(ctx context.Context, db sqlx.QueryerContext, table string) (bool, error) { +// return ddl.TableExists(ctx, db, Dialect(), table, s.dbName) +//} +// +//// ColumnExists checks if column exists in the MySQL table +//func (s *schema) ColumnExists(ctx context.Context, db sqlx.QueryerContext, column, table string) (bool, error) { +// return ddl.ColumnExists(ctx, db, Dialect(), column, table, s.dbName) +//} +// +//// CreateTable +//// +//// MySQL does not hav CREATE-INDEX-IF-NOT-EXISTS; we need to check index existence manually +//func (s *schema) CreateTable(ctx context.Context, db sqlx.ExtContext, t *ddl.Table) (err error) { +// +// tc := &ddl.CreateTable{ +// Dialect: Dialect(), +// Table: t, +// SuffixClause: "ENGINE=InnoDB DEFAULT CHARSET=utf8", +// } +// +// if err = ddl.Exec(ctx, db, tc); err != nil { +// return +// } +// +// for _, index := range t.Indexes { +// if index.Condition != "" { +// // MySQL, sad little DB does not support +// // conditional indexes +// // +// // We'll solve this on an application level +// continue +// } +// +// var doesIt bool +// if doesIt, err = ddl.IndexExists(ctx, db, Dialect(), index.Name, index.Table, s.dbName); err != nil { +// return +// } else if doesIt { +// continue +// } +// +// ic := &ddl.CreateIndex{ +// Dialect: Dialect(), +// Index: index, +// OmitIfNotExistsClause: true, +// } +// +// if err = ddl.Exec(ctx, db, ic); err != nil { +// return +// } +// +// } +// +// return +//} +// +//func (s *schema) AddColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, cc ...*ddl.Column) (err error) { +// var ( +// aux []any +// exists bool +// ) +// +// for _, c := range cc { +// // check column existence +// if exists, err = s.ColumnExists(ctx, db, c.Name, t.Name); err != nil { +// return +// } else if exists { +// // column exists +// continue +// } +// +// // Sadly, some column types in MySQL can not have default values +// if c.Type.Type == ddl.ColumnTypeJson || c.Type.Type == ddl.ColumnTypeBinary || c.Type.Type == ddl.ColumnTypeText { +// c.DefaultValue = "" +// } +// +// aux = append(aux, &ddl.AddColumn{ +// Dialect: dialect, +// Table: t, +// Column: c, +// }) +// } +// +// return ddl.Exec(ctx, db, aux...) +//} +// +//func (s *schema) DropColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, cc ...string) (err error) { +// var ( +// aux []any +// exists bool +// ) +// +// for _, c := range cc { +// // check column existence +// if exists, err = s.ColumnExists(ctx, db, c, t.Name); err != nil { +// return +// } else if !exists { +// // column exists +// continue +// } +// +// aux = append(aux, &ddl.DropColumn{ +// Dialect: dialect, +// Table: t, +// Column: c, +// }) +// } +// +// return ddl.Exec(ctx, db, aux...) +//} +// +//func (s *schema) RenameColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, old, new string) (err error) { +// var ( +// exists bool +// ) +// +// if exists, err = s.ColumnExists(ctx, db, old, t.Name); err != nil || !exists { +// // error or old column does not exist +// return +// } +// +// if exists, err = s.ColumnExists(ctx, db, new, t.Name); err != nil || exists { +// // error or new column already exists +// return +// } +// +// return ddl.Exec(ctx, db, &ddl.RenameColumn{ +// Dialect: dialect, +// Table: t, +// Old: old, +// New: new, +// }) +//} diff --git a/store/adapters/rdbms/drivers/postgres/dialect.go b/store/adapters/rdbms/drivers/postgres/dialect.go index cba3a3d5f..2aba28441 100644 --- a/store/adapters/rdbms/drivers/postgres/dialect.go +++ b/store/adapters/rdbms/drivers/postgres/dialect.go @@ -1,6 +1,7 @@ package postgres import ( + "fmt" "github.com/cortezaproject/corteza-server/pkg/dal" "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" "github.com/cortezaproject/corteza-server/store/adapters/rdbms/drivers" @@ -73,8 +74,67 @@ func (postgresDialect) AttributeCast(attr *dal.Attribute, val exp.LiteralExpress return exp.NewLiteralExpression("?", c), nil } -func (postgresDialect) NativeColumnType(ct ddl.ColumnType) string { - return columnTypeTranslator(ct) +func (postgresDialect) NativeColumnType(t dal.Type) (ct *ddl.ColumnType, err error) { + ct = &ddl.ColumnType{ + Null: t.IsNullable(), + } + + switch c := t.(type) { + case *dal.TypeID, *dal.TypeRef: + ct.Name = "BIGINT" + + case *dal.TypeTimestamp: + ct.Name = "TIMESTAMP" + + if c.Timezone { + ct.Name += "TZ" + } + ct.Name += fmt.Sprintf("(%d)", c.Precision) + + case *TypeTime: + ct.Name = "TIME" + + if c.Timezone { + ct.Name += "TZ" + } + ct.Name += fmt.Sprintf("(%d)", c.Precision) + + case *dal.TypeDate: + ct.Name = "DATE" + + case *dal.TypeNumber: + ct.Name = "NUMERIC" + // @todo precision, scale? + + case *dal.TypeText: + if c.Length > 0 { + // VARCHAR(0) is useless + ct.Name = fmt.Sprintf("VARCHAR(%d)", c.Length) + } else { + ct.Name = "TEXT" + } + + case *dal.TypeJSON: + ct.Name = "JSONB" + + case *dal.TypeGeometry: + // @todo geometry type + ct.Name = "JSONB" + + case *dal.TypeBlob: + ct.Name = "BYTEA" + + case *dal.TypeBoolean: + ct.Name = "BOOLEAN" + + case *dal.TypeUUID: + ct.Name = "UUID" + + default: + return nil, fmt.Errorf("unsupported column type: %s ", c.Type()) + } + + return } func (postgresDialect) ExprHandler(n *ql.ASTNode, args ...exp.Expression) (exp.Expression, error) { diff --git a/store/adapters/rdbms/drivers/postgres/information_schema.go b/store/adapters/rdbms/drivers/postgres/information_schema.go new file mode 100644 index 000000000..02d36e758 --- /dev/null +++ b/store/adapters/rdbms/drivers/postgres/information_schema.go @@ -0,0 +1,213 @@ +package postgres + +import ( + "context" + "github.com/cortezaproject/corteza-server/pkg/errors" + "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" + "github.com/doug-martin/goqu/v9" + "github.com/doug-martin/goqu/v9/exp" + "github.com/jmoiron/sqlx" + "strings" +) + +type ( + informationSchema struct { + conn *sqlx.DB + } +) + +func InformationSchema(conn *sqlx.DB) *informationSchema { + return &informationSchema{ + conn: conn, + } +} + +func (i *informationSchema) TableLookup(ctx context.Context, table, schema, dbname string) (*ddl.Table, error) { + var ( + oneTable = i.columnSelect().Where( + exp.ParseIdentifier("table_name").Eq(table), + exp.ParseIdentifier("table_catalog").Eq(dbname), + exp.ParseIdentifier("table_schema").Eq(schema), + ) + ) + + if out, err := i.scanColumns(ctx, oneTable); err != nil { + return nil, err + } else if len(out) > 0 { + return out[0], nil + } else { + return nil, errors.NotFound("table does not exist") + } +} + +func (i *informationSchema) columnSelect() *goqu.SelectDataset { + return dialect.GOQU().Select( + "table_name", + "column_name", + "is_nullable", + "data_type", + ). + From("information_schema.columns"). + Order( + exp.NewOrderedExpression(exp.ParseIdentifier("table_schema"), exp.AscDir, exp.NoNullsSortType), + exp.NewOrderedExpression(exp.ParseIdentifier("ordinal_position"), exp.AscDir, exp.NoNullsSortType), + ) +} + +func (i *informationSchema) scanColumns(ctx context.Context, sd *goqu.SelectDataset) (out []*ddl.Table, err error) { + var ( + at int + has bool + n2p = make(map[string]int) + + // https://dev.mysql.com/doc/mysql-infoschema-excerpt/5.7/en/information-schema-statistics-table.html + aux = make([]struct { + Table string `db:"table_name"` + Column string `db:"column_name"` + IsNullable bool `db:"is_nullable"` + Type string `db:"data_type"` + }, 0) + ) + + if err = ddl.Structs(ctx, i.conn, sd, &aux); err != nil { + return + } + + out = make([]*ddl.Table, 0, 10) + + for _, v := range aux { + if at, has = n2p[v.Table]; !has { + at = len(out) + n2p[v.Table] = at + out = append(out, &ddl.Table{Ident: v.Table}) + } + + out[at].Columns = append(out[at].Columns, &ddl.Column{ + Ident: v.Column, + Type: &ddl.ColumnType{ + Name: v.Type, + Null: v.IsNullable, + }, + }) + } + + return +} + +func (i *informationSchema) IndexLookup(ctx context.Context, index, table, schema string) (*ddl.Index, error) { + var ( + oneIndex = i.indexSelect().Where( + exp.ParseIdentifier("indexname").Eq(index), + exp.ParseIdentifier("tablename").Eq(table), + exp.ParseIdentifier("schemaname").Eq(schema), + ) + ) + + if out, err := i.scanIndexes(ctx, oneIndex); err != nil { + return nil, err + } else if len(out) > 0 { + return out[0], nil + } else { + return nil, errors.NotFound("index does not exist") + } +} + +func (i *informationSchema) indexSelect() *goqu.SelectDataset { + return dialect.GOQU().Select( + "tablename", + "indexname", + "indexdef", + ). + From("pg_indexes"). + Order( + exp.NewOrderedExpression(exp.ParseIdentifier("tablename"), exp.AscDir, exp.NoNullsSortType), + exp.NewOrderedExpression(exp.ParseIdentifier("indexname"), exp.AscDir, exp.NoNullsSortType), + ) +} + +func (i *informationSchema) scanIndexes(ctx context.Context, sd *goqu.SelectDataset) (out []*ddl.Index, err error) { + var ( + // https://dev.mysql.com/doc/mysql-infoschema-excerpt/5.7/en/information-schema-statistics-table.html + aux = make([]struct { + Table string `db:"tablename"` + Index string `db:"indexname"` + Def string `db:"indexdef"` + }, 0) + ) + + if err = ddl.Structs(ctx, i.conn, sd, &aux); err != nil { + return + } + + out = make([]*ddl.Index, len(aux)) + + //// iterate over results (aux) and populate ddl.Index struct + for i, a := range aux { + out[i] = &ddl.Index{} + if err = parseIndexDefinition(a.Def, out[i]); err != nil { + return + } + } + + return +} + +// parses postgesql specific index definition +func parseIndexDefinition(def string, index *ddl.Index) error { + const ( + TOKEN_INDEX = " INDEX " + TOKEN_ON = " ON " + TOKEN_USING = " USING " + TOKEN_UNIQUE = " UNIQUE INDEX " + TOKEN_WHERE = " WHERE " + ) + + // if def contains TOKEN_UNIQUE, consider this an unique index + index.Unique = strings.Contains(def, TOKEN_UNIQUE) + + // parse postgesql index definition + tpi := strings.Index(def, TOKEN_INDEX) + tpo := strings.Index(def, TOKEN_ON) + tpu := strings.Index(def, TOKEN_USING) + tpw := strings.Index(def, TOKEN_WHERE) + + if tpw == -1 { + tpw = len(def) + } + + // extract index name + index.Ident = def[tpi+len(TOKEN_INDEX) : tpo] + + // extract index table + index.TableIdent = def[tpo+len(TOKEN_ON) : tpu] + index.TableIdent = strings.SplitN(index.TableIdent, ".", 2)[1] + + // extract index fields + fieldsDef := def[tpu+len(TOKEN_USING) : tpw] + + typeAndFields := strings.SplitN(fieldsDef, " ", 2) + + index.Type = typeAndFields[0] + + fields := strings.Split(typeAndFields[1][1:len(typeAndFields[1])-1], ", ") + index.Fields = make([]*ddl.IndexField, len(fields)) + for i, fd := range fields { + f := &ddl.IndexField{} + + if strings.Contains(fd, "(") { + f.Expression = fd + } else { + f.Column = fd + } + + // @todo direction/sorting + index.Fields[i] = f + } + + // extract predicate/where + if tpw != len(def) { + index.Predicate = def[tpw+len(TOKEN_WHERE)+1 : len(def)-1] + } + + return nil +} diff --git a/store/adapters/rdbms/drivers/postgres/information_schema_test.go b/store/adapters/rdbms/drivers/postgres/information_schema_test.go new file mode 100644 index 000000000..c1e23c16a --- /dev/null +++ b/store/adapters/rdbms/drivers/postgres/information_schema_test.go @@ -0,0 +1,76 @@ +package postgres + +import ( + "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" + "github.com/stretchr/testify/require" + "testing" +) + +func Test_parseIndexDefinition(t *testing.T) { + tests := []struct { + name string + def string + index *ddl.Index + wantErr bool + }{ + { + name: "simple index", + def: "CREATE INDEX users_email ON public.users USING btree (email)", + index: &ddl.Index{ + Ident: "users_email", + TableIdent: "users", + Type: "btree", + Fields: []*ddl.IndexField{ + { + Column: "email", + }, + }, + }, + }, + { + name: "with predicate", + def: "CREATE UNIQUE INDEX users_email ON public.users USING btree (email) WHERE (deleted_at IS NULL)", + index: &ddl.Index{ + Ident: "users_email", + TableIdent: "users", + Type: "btree", + Unique: true, + Fields: []*ddl.IndexField{ + { + Column: "email", + }, + }, + Predicate: "deleted_at IS NULL", + }, + }, + { + name: "expressions with predicate", + def: "CREATE UNIQUE INDEX unique_language_handle ON public.templates USING btree (language, lower((handle)::text)) WHERE ((length((handle)::text) > 0) AND (deleted_at IS NULL))", + index: &ddl.Index{ + Ident: "unique_language_handle", + TableIdent: "templates", + Type: "btree", + Unique: true, + Fields: []*ddl.IndexField{ + { + Column: "language", + }, + { + Expression: "lower((handle)::text)", + }, + }, + Predicate: "(length((handle)::text) > 0) AND (deleted_at IS NULL)", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + index := &ddl.Index{} + if err := parseIndexDefinition(tt.def, index); (err != nil) != tt.wantErr { + t.Errorf("parseIndexDefinition() error = %v, wantErr %v", err, tt.wantErr) + } + + require.Equal(t, tt.index, index) + }) + } +} diff --git a/store/adapters/rdbms/drivers/postgres/schema.go b/store/adapters/rdbms/drivers/postgres/schema.go index df434e4c4..256c07461 100644 --- a/store/adapters/rdbms/drivers/postgres/schema.go +++ b/store/adapters/rdbms/drivers/postgres/schema.go @@ -1,116 +1,117 @@ package postgres -import ( - "context" - - "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" - "github.com/jmoiron/sqlx" -) - -// PostgreSQL specific prefixes, sql -// templates, functions and other helpers - -type ( - schema struct { - schemaName string - } -) - -var ( - _ = &schema{} -) - -func (s *schema) TableExists(ctx context.Context, db sqlx.QueryerContext, table string) (bool, error) { - return ddl.TableExists(ctx, db, Dialect(), table, "public") -} - -// ColumnExists checks if column exists in the MySQL table -func (s *schema) ColumnExists(ctx context.Context, db sqlx.QueryerContext, column, table string) (bool, error) { - return ddl.ColumnExists(ctx, db, Dialect(), column, table, "public") -} - -func (s *schema) CreateTable(ctx context.Context, db sqlx.ExtContext, t *ddl.Table) (err error) { - tt := append([]any{ - &ddl.CreateTable{ - Dialect: Dialect(), - Table: t, - SuffixClause: " WITHOUT OIDS", - }}, - ddl.CreateIndexTemplates(&ddl.CreateIndex{OmitFieldLength: true}, t.Indexes...)..., - ) - - return ddl.Exec(ctx, db, tt...) -} - -func (s *schema) AddColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, cc ...*ddl.Column) (err error) { - var ( - aux []any - exists bool - ) - - for _, c := range cc { - // check column existence - if exists, err = s.ColumnExists(ctx, db, c.Name, t.Name); err != nil { - return - } else if exists { - // column exists - continue - } - - aux = append(aux, &ddl.AddColumn{ - Dialect: dialect, - Table: t, - Column: c, - }) - } - - return ddl.Exec(ctx, db, aux...) -} - -func (s *schema) DropColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, cc ...string) (err error) { - var ( - aux []any - exists bool - ) - - for _, c := range cc { - // check column existence - if exists, err = s.ColumnExists(ctx, db, c, t.Name); err != nil { - return - } else if !exists { - // column exists - continue - } - - aux = append(aux, &ddl.DropColumn{ - Dialect: dialect, - Table: t, - Column: c, - }) - } - - return ddl.Exec(ctx, db, aux...) -} - -func (s *schema) RenameColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, old, new string) (err error) { - var ( - exists bool - ) - - if exists, err = s.ColumnExists(ctx, db, old, t.Name); err != nil || !exists { - // error or old column does not exist - return - } - - if exists, err = s.ColumnExists(ctx, db, new, t.Name); err != nil || exists { - // error or new column already exists - return - } - - return ddl.Exec(ctx, db, &ddl.RenameColumn{ - Dialect: dialect, - Table: t, - Old: old, - New: new, - }) -} +// +//import ( +// "context" +// +// "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" +// "github.com/jmoiron/sqlx" +//) +// +//// PostgreSQL specific prefixes, sql +//// templates, functions and other helpers +// +//type ( +// schema struct { +// schemaName string +// } +//) +// +//var ( +// _ = &schema{} +//) +// +//func (s *schema) TableExists(ctx context.Context, db sqlx.QueryerContext, table string) (bool, error) { +// return ddl.TableExists(ctx, db, Dialect(), table, "public") +//} +// +//// ColumnExists checks if column exists in the MySQL table +//func (s *schema) ColumnExists(ctx context.Context, db sqlx.QueryerContext, column, table string) (bool, error) { +// return ddl.ColumnExists(ctx, db, Dialect(), column, table, "public") +//} +// +//func (s *schema) CreateTable(ctx context.Context, db sqlx.ExtContext, t *ddl.Table) (err error) { +// tt := append([]any{ +// &ddl.CreateTable{ +// Dialect: Dialect(), +// Table: t, +// SuffixClause: " WITHOUT OIDS", +// }}, +// ddl.CreateIndexTemplates(&ddl.CreateIndex{OmitFieldLength: true}, t.Indexes...)..., +// ) +// +// return ddl.Exec(ctx, db, tt...) +//} +// +//func (s *schema) AddColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, cc ...*ddl.Column) (err error) { +// var ( +// aux []any +// exists bool +// ) +// +// for _, c := range cc { +// // check column existence +// if exists, err = s.ColumnExists(ctx, db, c.Name, t.Name); err != nil { +// return +// } else if exists { +// // column exists +// continue +// } +// +// aux = append(aux, &ddl.AddColumn{ +// Dialect: dialect, +// Table: t, +// Column: c, +// }) +// } +// +// return ddl.Exec(ctx, db, aux...) +//} +// +//func (s *schema) DropColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, cc ...string) (err error) { +// var ( +// aux []any +// exists bool +// ) +// +// for _, c := range cc { +// // check column existence +// if exists, err = s.ColumnExists(ctx, db, c, t.Name); err != nil { +// return +// } else if !exists { +// // column exists +// continue +// } +// +// aux = append(aux, &ddl.DropColumn{ +// Dialect: dialect, +// Table: t, +// Column: c, +// }) +// } +// +// return ddl.Exec(ctx, db, aux...) +//} +// +//func (s *schema) RenameColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, old, new string) (err error) { +// var ( +// exists bool +// ) +// +// if exists, err = s.ColumnExists(ctx, db, old, t.Name); err != nil || !exists { +// // error or old column does not exist +// return +// } +// +// if exists, err = s.ColumnExists(ctx, db, new, t.Name); err != nil || exists { +// // error or new column already exists +// return +// } +// +// return ddl.Exec(ctx, db, &ddl.RenameColumn{ +// Dialect: dialect, +// Table: t, +// Old: old, +// New: new, +// }) +//} diff --git a/store/adapters/rdbms/drivers/postgres/types.go b/store/adapters/rdbms/drivers/postgres/types.go index 6ccd6f0a3..233e85b35 100644 --- a/store/adapters/rdbms/drivers/postgres/types.go +++ b/store/adapters/rdbms/drivers/postgres/types.go @@ -4,7 +4,6 @@ import ( "database/sql" "database/sql/driver" "fmt" - "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" "time" "github.com/cortezaproject/corteza-server/pkg/dal" @@ -41,7 +40,3 @@ func (t *TypeTime) Decode(raw any) (any, bool, error) { func (t *TypeTime) Encode(val any) (driver.Value, error) { return val, nil } - -func columnTypeTranslator(ct ddl.ColumnType) string { - return ddl.ColumnTypeTranslator(ct) -} diff --git a/store/adapters/rdbms/drivers/sqlite/connect.go b/store/adapters/rdbms/drivers/sqlite/connect.go index 267c2126d..e9d117af0 100644 --- a/store/adapters/rdbms/drivers/sqlite/connect.go +++ b/store/adapters/rdbms/drivers/sqlite/connect.go @@ -70,7 +70,7 @@ func Connect(ctx context.Context, dsn string) (_ store.Storer, err error) { s := &rdbms.Store{ DB: db, - DAL: dal.Connection(db, Dialect(), pkgdal.FullOperations()...), + DAL: dal.Connection(db, Dialect(), DataDefiner(cfg.DBName, db), pkgdal.FullOperations()...), Dialect: goquDialectWrapper, ErrorHandler: errorHandler, @@ -78,7 +78,7 @@ func Connect(ctx context.Context, dsn string) (_ store.Storer, err error) { TxRetryLimit: -1, //TxRetryErrHandler: txRetryErrHandler, - SchemaAPI: &schema{}, + //SchemaAPI: &schema{}, } s.SetDefaults() diff --git a/store/adapters/rdbms/drivers/sqlite/dal.go b/store/adapters/rdbms/drivers/sqlite/dal.go index b478c09ed..9adceeaab 100644 --- a/store/adapters/rdbms/drivers/sqlite/dal.go +++ b/store/adapters/rdbms/drivers/sqlite/dal.go @@ -33,5 +33,5 @@ func dalConnector(ctx context.Context, dsn string, cc ...dal.Operation) (_ dal.C return } - return rdbmsdal.Connection(db, Dialect(), cc...), nil + return rdbmsdal.Connection(db, Dialect(), DataDefiner(cfg.DBName, db), cc...), nil } diff --git a/store/adapters/rdbms/drivers/sqlite/data_definer.go b/store/adapters/rdbms/drivers/sqlite/data_definer.go new file mode 100644 index 000000000..eee121e0b --- /dev/null +++ b/store/adapters/rdbms/drivers/sqlite/data_definer.go @@ -0,0 +1,218 @@ +package sqlite + +import ( + "context" + "fmt" + "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" +) + +type ( + // @todo this is unmodified copy of postgres's data definer struct! + dataDefiner struct { + dbName string + conn *sqlx.DB + is *informationSchema + d *sqliteDialect + } +) + +var ( + _ ddl.DataDefiner = new(dataDefiner) +) + +func DataDefiner(dbName string, conn *sqlx.DB) *dataDefiner { + return &dataDefiner{ + dbName: dbName, + conn: conn, + is: InformationSchema(conn), + d: Dialect(), + } +} + +func (dd *dataDefiner) ConvertModel(m *dal.Model) (*ddl.Table, error) { + return ddl.ConvertModel(m, dd.d) +} + +func (dd *dataDefiner) TableCreate(ctx context.Context, t *ddl.Table) error { + return ddl.Exec(ctx, dd.conn, &ddl.CreateTable{Table: t}) +} + +func (dd *dataDefiner) TableLookup(ctx context.Context, t string) (*ddl.Table, error) { + return nil, fmt.Errorf("not implemented") +} + +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, ""), + 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), + }) +} + +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), + }) +} + +func (dd *dataDefiner) IndexLookup(ctx context.Context, i, t string) (*ddl.Index, error) { + if index, err := dd.is.IndexLookup(ctx, i, t, dd.dbName); err != nil { + return nil, err + } else { + return index, nil + } +} + +func (dd *dataDefiner) IndexCreate(ctx context.Context, t string, i *ddl.Index) error { + return ddl.Exec(ctx, dd.conn, &ddl.CreateIndex{Index: i}) +} + +func (dd *dataDefiner) IndexDrop(ctx context.Context, t, i string) error { + return ddl.Exec(ctx, dd.conn, &ddl.DropIndex{Ident: exp.NewIdentifierExpression("", t, i)}) +} + +// +//// TableExists checks if table exists in the MySQL database +//func (s *schema) TableExists(ctx context.Context, db sqlx.QueryerContext, table string) (bool, error) { +// return ddl.TableExists(ctx, db, Dialect(), table, s.dbName) +//} +// +//// ColumnExists checks if column exists in the MySQL table +//func (s *schema) ColumnExists(ctx context.Context, db sqlx.QueryerContext, column, table string) (bool, error) { +// return ddl.ColumnExists(ctx, db, Dialect(), column, table, s.dbName) +//} +// +//// CreateTable +//// +//// MySQL does not hav CREATE-INDEX-IF-NOT-EXISTS; we need to check index existence manually +//func (s *schema) CreateTable(ctx context.Context, db sqlx.ExtContext, t *ddl.Table) (err error) { +// +// tc := &ddl.CreateTable{ +// Dialect: Dialect(), +// Table: t, +// SuffixClause: "ENGINE=InnoDB DEFAULT CHARSET=utf8", +// } +// +// if err = ddl.Exec(ctx, db, tc); err != nil { +// return +// } +// +// for _, index := range t.Indexes { +// if index.Condition != "" { +// // MySQL, sad little DB does not support +// // conditional indexes +// // +// // We'll solve this on an application level +// continue +// } +// +// var doesIt bool +// if doesIt, err = ddl.IndexExists(ctx, db, Dialect(), index.Name, index.Table, s.dbName); err != nil { +// return +// } else if doesIt { +// continue +// } +// +// ic := &ddl.CreateIndex{ +// Dialect: Dialect(), +// Index: index, +// OmitIfNotExistsClause: true, +// } +// +// if err = ddl.Exec(ctx, db, ic); err != nil { +// return +// } +// +// } +// +// return +//} +// +//func (s *schema) AddColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, cc ...*ddl.Column) (err error) { +// var ( +// aux []any +// exists bool +// ) +// +// for _, c := range cc { +// // check column existence +// if exists, err = s.ColumnExists(ctx, db, c.Name, t.Name); err != nil { +// return +// } else if exists { +// // column exists +// continue +// } +// +// // Sadly, some column types in MySQL can not have default values +// if c.Type.Type == ddl.ColumnTypeJson || c.Type.Type == ddl.ColumnTypeBinary || c.Type.Type == ddl.ColumnTypeText { +// c.DefaultValue = "" +// } +// +// aux = append(aux, &ddl.AddColumn{ +// Dialect: dialect, +// Table: t, +// Column: c, +// }) +// } +// +// return ddl.Exec(ctx, db, aux...) +//} +// +//func (s *schema) DropColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, cc ...string) (err error) { +// var ( +// aux []any +// exists bool +// ) +// +// for _, c := range cc { +// // check column existence +// if exists, err = s.ColumnExists(ctx, db, c, t.Name); err != nil { +// return +// } else if !exists { +// // column exists +// continue +// } +// +// aux = append(aux, &ddl.DropColumn{ +// Dialect: dialect, +// Table: t, +// Column: c, +// }) +// } +// +// return ddl.Exec(ctx, db, aux...) +//} +// +//func (s *schema) RenameColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, old, new string) (err error) { +// var ( +// exists bool +// ) +// +// if exists, err = s.ColumnExists(ctx, db, old, t.Name); err != nil || !exists { +// // error or old column does not exist +// return +// } +// +// if exists, err = s.ColumnExists(ctx, db, new, t.Name); err != nil || exists { +// // error or new column already exists +// return +// } +// +// return ddl.Exec(ctx, db, &ddl.RenameColumn{ +// Dialect: dialect, +// Table: t, +// Old: old, +// New: new, +// }) +//} diff --git a/store/adapters/rdbms/drivers/sqlite/dialect.go b/store/adapters/rdbms/drivers/sqlite/dialect.go index d217a27e3..336958760 100644 --- a/store/adapters/rdbms/drivers/sqlite/dialect.go +++ b/store/adapters/rdbms/drivers/sqlite/dialect.go @@ -1,6 +1,7 @@ package sqlite import ( + "fmt" "github.com/cortezaproject/corteza-server/pkg/dal" "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" "github.com/cortezaproject/corteza-server/store/adapters/rdbms/drivers" @@ -57,8 +58,55 @@ func (sqliteDialect) AttributeCast(attr *dal.Attribute, val exp.LiteralExpressio return drivers.AttributeCast(attr, val) } -func (sqliteDialect) NativeColumnType(ct ddl.ColumnType) string { - return columnTypeTranslator(ct) +func (sqliteDialect) NativeColumnType(t dal.Type) (ct *ddl.ColumnType, err error) { + ct = &ddl.ColumnType{ + Null: t.IsNullable(), + } + + switch c := t.(type) { + case *dal.TypeID, *dal.TypeRef: + ct.Name = "BIGINT" + + case *dal.TypeTimestamp: + ct.Name = "TIMESTAMP" + + case *dal.TypeTime: + ct.Name = "TIMESTAMP" + + case *dal.TypeDate: + ct.Name = "DATE" + + case *dal.TypeNumber: + ct.Name = "NUMERIC" + // @todo precision, scale? + + case *dal.TypeText: + if c.Length > 0 { + ct.Name = fmt.Sprintf("VARCHAR(%d)", c.Length) + } else { + ct.Name = "TEXT" + } + + case *dal.TypeJSON: + ct.Name = "TEXT" + + case *dal.TypeGeometry: + ct.Name = "TEXT" + + case *dal.TypeBlob: + ct.Name = "BLOB" + + case *dal.TypeBoolean: + ct.Name = "BOOLEAN" + + case *dal.TypeUUID: + ct.Name = "CHAR(36)" + + default: + return nil, fmt.Errorf("unsupported column type: %s ", c.Type()) + } + + return } func (sqliteDialect) ExprHandler(n *ql.ASTNode, args ...exp.Expression) (exp.Expression, error) { diff --git a/store/adapters/rdbms/drivers/sqlite/information_schema.go b/store/adapters/rdbms/drivers/sqlite/information_schema.go new file mode 100644 index 000000000..5d5b9c99d --- /dev/null +++ b/store/adapters/rdbms/drivers/sqlite/information_schema.go @@ -0,0 +1,135 @@ +package sqlite + +import ( + "context" + "database/sql" + "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" + "github.com/doug-martin/goqu/v9" + "github.com/doug-martin/goqu/v9/exp" + "github.com/jmoiron/sqlx" +) + +type ( + // @todo this is unmodified copy of mysql's information schema struct! + informationSchema struct { + conn *sqlx.DB + } +) + +func InformationSchema(conn *sqlx.DB) *informationSchema { + return &informationSchema{ + conn: conn, + } +} + +func (i *informationSchema) IndexLookup(ctx context.Context, index, table, schema string) (*ddl.Index, error) { + var ( + oneIndex = i.indexSelect(schema).Where( + exp.ParseIdentifier("INDEX_NAME").Eq(index), + exp.ParseIdentifier("TABLE_NAME").Eq(table), + ) + ) + + if out, err := i.scanIndexes(ctx, oneIndex); err != nil { + return nil, err + } else if len(out) > 0 { + return out[0], nil + } else { + return nil, nil + } +} + +func (i *informationSchema) indexSelect(schema string) *goqu.SelectDataset { + return dialect.GOQU().Select( + "INDEX_NAME", + "TABLE_NAME", + "COLUMN_NAME", + "INDEX_TYPE", + "EXPRESSION", + "INDEX_COMMENT", + ). + From("information_schema.statistics"). + Where( + exp.ParseIdentifier("TABLE_SCHEMA").Eq(schema), + ). + Order( + exp.NewOrderedExpression(exp.ParseIdentifier("TABLE_SCHEMA"), exp.AscDir, exp.NoNullsSortType), + exp.NewOrderedExpression(exp.ParseIdentifier("INDEX_NAME"), exp.AscDir, exp.NoNullsSortType), + exp.NewOrderedExpression(exp.ParseIdentifier("SEQ_IN_INDEX"), exp.AscDir, exp.NoNullsSortType), + ) +} + +func (i *informationSchema) scanIndexes(ctx context.Context, sd *goqu.SelectDataset) (out []*ddl.Index, err error) { + var ( + at int + has bool + n2p = make(map[string]int) + + // https://dev.mysql.com/doc/mysql-infoschema-excerpt/5.7/en/information-schema-statistics-table.html + aux = make([]struct { + Name string `db:"INDEX_NAME"` + Table string `db:"TABLE_NAME"` + NonUnique bool `db:"NON_UNIQUE"` + Type string `db:"INDEX_TYPE"` + + // @todo there's also a "COMMENT" column? + Comment string `db:"INDEX_COMMENT"` + + Expression sql.NullString `db:"EXPRESSION"` + ColumnName string `db:"COLUMN_NAME"` + ColumnSubPart sql.NullInt32 `db:"SUB_PART"` + ColumnCollation sql.NullString `db:"COLLATION"` + + // stats + ColumnStatsCardinality int64 `db:"CARDINALITY"` + }, 0) + ) + + if err = ddl.Structs(ctx, i.conn, sd, &aux); err != nil { + return + } + + out = make([]*ddl.Index, 0, 10) + + // iterate over results (aux) and populate ddl.Index struct + for p, a := range aux { + if at, has = n2p[a.Name]; !has { + out = append(out, &ddl.Index{ + Ident: a.Name, + TableIdent: a.Table, + Type: a.Type, + Comment: a.Comment, + Fields: make([]*ddl.IndexField, 0), + Unique: !a.NonUnique, + Predicate: "", + Meta: nil, + }) + n2p[a.Name] = p + at = p + } + + col := &ddl.IndexField{ + Length: int(a.ColumnSubPart.Int32), + Statistics: &ddl.IndexFieldStatistics{ + Cardinality: a.ColumnStatsCardinality, + }, + } + + switch a.ColumnCollation.String { + case "A": + col.Sorted = ddl.IndexFieldSortAsc + case "D": + col.Sorted = ddl.IndexFieldSortDesc + } + + if a.Expression.Valid { + col.Expression = a.Expression.String + } else { + col.Column = a.ColumnName + } + + out[at].Fields = append(out[at].Fields, col) + } + + return +} diff --git a/store/adapters/rdbms/drivers/sqlite/schema.go b/store/adapters/rdbms/drivers/sqlite/schema.go index 210cb2d96..cf7aae9eb 100644 --- a/store/adapters/rdbms/drivers/sqlite/schema.go +++ b/store/adapters/rdbms/drivers/sqlite/schema.go @@ -1,124 +1,128 @@ package sqlite -import ( - "context" - "fmt" - - "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" - "github.com/jmoiron/sqlx" -) - -type ( - schema struct{} -) - -func (s *schema) TableExists(ctx context.Context, db sqlx.QueryerContext, table string) (bool, error) { - var ( - exists bool - sql = `SELECT COUNT(*) > 0 FROM sqlite_master WHERE type = 'table' AND name = ?` - ) - - if err := sqlx.GetContext(ctx, db, &exists, sql, table); err != nil { - return false, fmt.Errorf("could not check if table exists: %w", err) - } - - return exists, nil -} - -func (s *schema) ColumnExists(ctx context.Context, db sqlx.QueryerContext, column, table string) (bool, error) { - var ( - exists bool - sql = `SELECT COUNT(*) > 0 FROM pragma_table_info(?) WHERE name = ?;` - ) - - if err := sqlx.GetContext(ctx, db, &exists, sql, table, column); err != nil { - return false, fmt.Errorf("could not check if column exists: %w", err) - } - - return exists, nil -} - -func (s *schema) CreateTable(ctx context.Context, db sqlx.ExtContext, t *ddl.Table) (err error) { - tt := append( - []any{&ddl.CreateTable{ - Dialect: Dialect(), - Table: t, - }}, - ddl.CreateIndexTemplates(&ddl.CreateIndex{OmitFieldLength: true}, t.Indexes...)..., - ) - - return ddl.Exec(ctx, db, tt...) -} - -func (s *schema) AddColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, cc ...*ddl.Column) (err error) { - var ( - aux []any - exists bool - ) - - for _, c := range cc { - // check column existence - if exists, err = s.ColumnExists(ctx, db, c.Name, t.Name); err != nil { - return - } else if exists { - // column exists - continue - } - - aux = append(aux, &ddl.AddColumn{ - Dialect: dialect, - Table: t, - Column: c, - }) - } - - return ddl.Exec(ctx, db, aux...) -} - -func (s *schema) DropColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, cc ...string) (err error) { - var ( - aux []any - exists bool - ) - - for _, c := range cc { - // check column existence - if exists, err = s.ColumnExists(ctx, db, c, t.Name); err != nil { - return - } else if !exists { - // column exists - continue - } - - aux = append(aux, &ddl.DropColumn{ - Dialect: dialect, - Table: t, - Column: c, - }) - } - - return ddl.Exec(ctx, db, aux...) -} - -func (s *schema) RenameColumn(ctx context.Context, db sqlx.ExtContext, t *ddl.Table, old, new string) (err error) { - var ( - exists bool - ) - - if exists, err = s.ColumnExists(ctx, db, old, t.Name); err != nil || !exists { - // error or old column does not exist - return - } - - if exists, err = s.ColumnExists(ctx, db, new, t.Name); err != nil || exists { - // error or new column already exists - return - } - - return ddl.Exec(ctx, db, &ddl.RenameColumn{ - Dialect: dialect, - Table: t, - Old: old, - New: new, - }) -} +// +//import ( +// "context" +// "fmt" +// "github.com/cortezaproject/corteza-server/pkg/dal" +// +// "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" +// "github.com/jmoiron/sqlx" +//) +// +//type ( +// schema struct{} +//) +// +//func (s *schema) TableExists(ctx context.Context, db sqlx.QueryerContext, table string) (bool, error) { +// var ( +// exists bool +// sql = `SELECT COUNT(*) > 0 FROM sqlite_master WHERE type = 'table' AND name = ?` +// ) +// +// if err := sqlx.GetContext(ctx, db, &exists, sql, table); err != nil { +// return false, fmt.Errorf("could not check if table exists: %w", err) +// } +// +// return exists, nil +//} +// +//func (s *schema) ColumnExists(ctx context.Context, db sqlx.QueryerContext, column, table string) (bool, error) { +// var ( +// exists bool +// sql = `SELECT COUNT(*) > 0 FROM pragma_table_info(?) WHERE name = ?;` +// ) +// +// if err := sqlx.GetContext(ctx, db, &exists, sql, table, column); err != nil { +// return false, fmt.Errorf("could not check if column exists: %w", err) +// } +// +// return exists, nil +//} +// +//func (s *schema) CreateTable(ctx context.Context, db sqlx.ExtContext, m *dal.Model) (err error) { +// tt := append( +// []any{&ddl.CreateTable{ +// Dialect: Dialect(), +// Model: m, +// }}, +// +// // @todo +// // ddl.CreateIndexTemplates(&ddl.CreateIndex{OmitFieldLength: true}, m.Indexes...)..., +// ) +// +// return ddl.Exec(ctx, db, tt...) +//} +// +//func (s *schema) AddColumn(ctx context.Context, db sqlx.ExtContext, m *dal.Model, aa ...*dal.Attribute) (err error) { +// var ( +// aux []any +// exists bool +// ) +// +// for _, a := range aa { +// // check column existence +// if exists, err = s.ColumnExists(ctx, db, a.Ident, m.Ident); err != nil { +// return +// } else if exists { +// // column exists +// continue +// } +// +// aux = append(aux, &ddl.AddColumn{ +// Dialect: dialect, +// Model: m, +// Attribute: a, +// }) +// } +// +// return ddl.Exec(ctx, db, aux...) +//} +// +//func (s *schema) DropColumn(ctx context.Context, db sqlx.ExtContext, m *dal.Model, cc ...string) (err error) { +// var ( +// aux []any +// exists bool +// ) +// +// for _, c := range cc { +// // check column existence +// if exists, err = s.ColumnExists(ctx, db, c, m.Ident); err != nil { +// return +// } else if !exists { +// // column exists +// continue +// } +// +// aux = append(aux, &ddl.DropColumn{ +// Dialect: dialect, +// Model: m, +// Column: c, +// }) +// } +// +// return ddl.Exec(ctx, db, aux...) +//} +// +//func (s *schema) RenameColumn(ctx context.Context, db sqlx.ExtContext, m *dal.Model, old, new string) (err error) { +// var ( +// exists bool +// ) +// +// if exists, err = s.ColumnExists(ctx, db, old, m.Ident); err != nil || !exists { +// // error or old column does not exist +// return +// } +// +// if exists, err = s.ColumnExists(ctx, db, new, m.Ident); err != nil || exists { +// // error or new column already exists +// return +// } +// +// return ddl.Exec(ctx, db, &ddl.RenameColumn{ +// Dialect: dialect, +// Model: m, +// Old: old, +// New: new, +// }) +//} diff --git a/store/adapters/rdbms/drivers/sqlite/types.go b/store/adapters/rdbms/drivers/sqlite/types.go deleted file mode 100644 index 3fa1c0fde..000000000 --- a/store/adapters/rdbms/drivers/sqlite/types.go +++ /dev/null @@ -1,15 +0,0 @@ -package sqlite - -import "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" - -func columnTypeTranslator(ct ddl.ColumnType) string { - switch ct.Type { - case ddl.ColumnTypeTimestamp: - return "TIMESTAMP" - case ddl.ColumnTypeBinary: - return "BLOB" - default: - return ddl.ColumnTypeTranslator(ct) - } - -} diff --git a/store/adapters/rdbms/drivers/tests/dal_model_test.go b/store/adapters/rdbms/drivers/tests/dal_model_test.go new file mode 100644 index 000000000..94dd16cd7 --- /dev/null +++ b/store/adapters/rdbms/drivers/tests/dal_model_test.go @@ -0,0 +1,70 @@ +package tests + +import ( + "context" + "github.com/cortezaproject/corteza-server/pkg/dal" + "github.com/cortezaproject/corteza-server/pkg/logger" + "github.com/stretchr/testify/require" + "testing" +) + +func TestModelManagement(t *testing.T) { + var ( + ctx = context.Background() + log = logger.Default() + ) + + eachDB(t, func(t *testing.T, c *conn) error { + var ( + req = require.New(t) + ) + + if c.isSQLite { + t.Skip("sqlite does not support index management") + } + + const ( + dalConnID = 1 + dalTableName = "lil_dal_test" + ) + + _, err := c.db.Exec("DROP TABLE IF EXISTS " + dalTableName) + req.NoError(err) + + cw := dal.MakeConnection( + dalConnID, + c.store.ToDalConn(), + dal.ConnectionParams{}, + dal.ConnectionConfig{}, + ) + + svc, err := dal.New(log, true) + req.NoError(err) + req.NoError(svc.ReplaceConnection(ctx, cw, true)) + + req.NoError(svc.ReplaceModel(ctx, &dal.Model{ + Ident: dalTableName, + ConnectionID: dalConnID, + Attributes: dal.AttributeSet{ + &dal.Attribute{ + Ident: "ID", + PrimaryKey: true, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, + }, + + &dal.Attribute{ + Ident: "OwnerID", + Sortable: true, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "rel_owner"}, + }, + }, + })) + + _, err = c.db.Exec("DROP TABLE " + dalTableName) + req.NoError(err) + + return nil + }) +} diff --git a/store/adapters/rdbms/drivers/tests/information_schema_test.go b/store/adapters/rdbms/drivers/tests/information_schema_test.go new file mode 100644 index 000000000..23e248021 --- /dev/null +++ b/store/adapters/rdbms/drivers/tests/information_schema_test.go @@ -0,0 +1,31 @@ +package tests + +import ( + "context" + "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" + "github.com/stretchr/testify/require" + "testing" +) + +func TestIndexManagement(t *testing.T) { + var ( + ctx = context.Background() + ) + + eachDB(t, func(t *testing.T, c *conn) error { + if c.isSQLite { + t.Skip("sqlite does not support index management") + } + + var ( + req = require.New(t) + dd = c.store.DataDefiner(c.db) + ii, err = dd.IndexLookup(ctx, ddl.PRIMARY_KEY, "users") + ) + + req.NoError(err) + req.NotNil(ii) + + return nil + }) +} diff --git a/store/adapters/rdbms/rdbms_store.go b/store/adapters/rdbms/rdbms_store.go index f2fd38307..3c8de9a19 100644 --- a/store/adapters/rdbms/rdbms_store.go +++ b/store/adapters/rdbms/rdbms_store.go @@ -33,14 +33,6 @@ type ( DATE func(interface{}) exp.SQLFunctionExpression } - schemaAPI interface { - TableExists(context.Context, sqlx.QueryerContext, string) (bool, error) - CreateTable(context.Context, sqlx.ExtContext, *ddl.Table) error - AddColumn(context.Context, sqlx.ExtContext, *ddl.Table, ...*ddl.Column) error - RenameColumn(context.Context, sqlx.ExtContext, *ddl.Table, string, string) error - DropColumn(context.Context, sqlx.ExtContext, *ddl.Table, ...string) error - } - Store struct { DB sqlx.ExtContext @@ -50,9 +42,8 @@ type ( // Logger for connection Logger *zap.Logger - // tools to modify DB schema (create tables, indexes..) - // @todo maybe this does not need to be here - SchemaAPI schemaAPI + // data definer interface use for schema information lookups and modification + DataDefiner ddl.DataDefiner Dialect goqu.DialectWrapper @@ -102,7 +93,7 @@ func (s *Store) withTx(tx sqlx.ExtContext) *Store { DB: tx, Logger: s.Logger, - SchemaAPI: s.SchemaAPI, + DataDefiner: s.DataDefiner, Dialect: s.Dialect, TxRetryErrHandler: s.TxRetryErrHandler, ErrorHandler: s.ErrorHandler, diff --git a/store/adapters/rdbms/upgrade.go b/store/adapters/rdbms/upgrade.go index f670e7cd2..d1941b59e 100644 --- a/store/adapters/rdbms/upgrade.go +++ b/store/adapters/rdbms/upgrade.go @@ -3,44 +3,86 @@ package rdbms import ( "context" "fmt" + automationModels "github.com/cortezaproject/corteza-server/automation/model" + composeModels "github.com/cortezaproject/corteza-server/compose/model" + federationModels "github.com/cortezaproject/corteza-server/federation/model" + "github.com/cortezaproject/corteza-server/pkg/dal" + "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" + systemModels "github.com/cortezaproject/corteza-server/system/model" "go.uber.org/zap" ) func (s *Store) Upgrade(ctx context.Context) (err error) { - var ( - tableExists bool + + err = createTablesFromModels( + ctx, + s.log(ctx), + s.DataDefiner, + systemModels.All(), + composeModels.All(), + automationModels.All(), + federationModels.All(), ) - for _, t := range Tables() { + if err != nil { + return err + } - 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) - } + //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 + // } + //} + // + return +} - 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) +func createTablesFromModels(ctx context.Context, log *zap.Logger, dd ddl.DataDefiner, sets ...dal.ModelSet) (err error) { + var ( + tbl *ddl.Table + ) + + for _, mm := range sets { + for _, m := range mm { + log.Debug("creating table", zap.String("table", m.Ident)) + + if tbl, err = dd.ConvertModel(m); err != nil { + return fmt.Errorf("can not convert model %q to table: %w", m.Ident, err) + } + + if err = dd.TableCreate(ctx, tbl); err != nil { + return fmt.Errorf("can not create table from mdoel model %q: %w", m.Ident, 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 - } - } - - return + return nil } diff --git a/store/adapters/rdbms/upgrade_fixes.go b/store/adapters/rdbms/upgrade_fixes.go index 96819711a..31e44e6ba 100644 --- a/store/adapters/rdbms/upgrade_fixes.go +++ b/store/adapters/rdbms/upgrade_fixes.go @@ -1,191 +1,182 @@ package rdbms -import ( - "context" - "encoding/json" - labelsType "github.com/cortezaproject/corteza-server/pkg/label/types" - "github.com/cortezaproject/corteza-server/store" - . "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" - "go.uber.org/zap" -) +//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"}, +// ) -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, - &Table{Name: "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, - &Table{Name: "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, - &Table{Name: "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, - &Table{Name: "compose_record"}, - &Column{Type: ColumnType{Type: ColumnTypeInteger}, DefaultValue: "1", Name: "revision"}, - ) - - //return // will probably not need this... - //var ( - // log = s.log(ctx) - //) - // - //const ( - // envKeySkip = "UPGRADE_COMPOSE_RECORD_CHANGES_PREFILL_SKIP" - // - // 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 - - }) - -} +//return // will probably not need this... +//var ( +// log = s.log(ctx) +//) +// +//const ( +// envKeySkip = "UPGRADE_COMPOSE_RECORD_CHANGES_PREFILL_SKIP" +// +// 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 +// +// }) +// +//} diff --git a/store/adapters/rdbms/upgrade_tables.go b/store/adapters/rdbms/upgrade_tables.go index 5804eed7a..496aea481 100644 --- a/store/adapters/rdbms/upgrade_tables.go +++ b/store/adapters/rdbms/upgrade_tables.go @@ -1,9 +1,5 @@ package rdbms -import ( - . "github.com/cortezaproject/corteza-server/store/adapters/rdbms/ddl" -) - const ( handleLength = 64 resourceLength = 512 @@ -29,741 +25,741 @@ const ( ) // 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, - ) -} +//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, +// ) +//} diff --git a/store/ddl.go b/store/ddl.go new file mode 100644 index 000000000..23cd50e24 --- /dev/null +++ b/store/ddl.go @@ -0,0 +1,13 @@ +package store + +import "github.com/cortezaproject/corteza-server/pkg/dal" + +type ( + DDL interface { + // EnsureModel ensures model exists in the store in form of a collection or a database table + // + // This includes all model's attributes, constraints and indexes. + // All must exist and be of the right type. + EnsureModel(model *dal.Model) error + } +) diff --git a/store/store.go b/store/store.go deleted file mode 100644 index 3ca604e33..000000000 --- a/store/store.go +++ /dev/null @@ -1,13 +0,0 @@ -package store - -const ( - // TxRetryHardLimit is the absolute maximum retries we'll allow - TxRetryHardLimit = 100 - - DefaultSliceCapacity = 1000 - - MinEnsureFetchLimit = 10 - MaxRefetches = 100 - - MaxLimit = 1000 -) diff --git a/system/model/models.gen.go b/system/model/models.gen.go index 1c0ca77e5..74c5245c8 100644 --- a/system/model/models.gen.go +++ b/system/model/models.gen.go @@ -24,102 +24,75 @@ var ( ResourceType: types.AttachmentResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ - Ident: "OwnerID", - + Ident: "OwnerID", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "rel_owner"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "rel_owner"}, }, &dal.Attribute{ - Ident: "Kind", - + Ident: "Kind", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "kind"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "kind"}, }, &dal.Attribute{ Ident: "Url", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "url"}, }, &dal.Attribute{ Ident: "PreviewUrl", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "preview_url"}, }, &dal.Attribute{ - Ident: "Name", - + Ident: "Name", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "name"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "name"}, }, &dal.Attribute{ Ident: "Meta", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "meta"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, }, @@ -130,96 +103,68 @@ var ( ResourceType: types.ApplicationResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ - Ident: "Name", - + Ident: "Name", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "name"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "name"}, }, &dal.Attribute{ - Ident: "OwnerID", - + Ident: "OwnerID", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "rel_owner"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "rel_owner"}, }, &dal.Attribute{ - Ident: "Enabled", - + Ident: "Enabled", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "enabled"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "enabled"}, }, &dal.Attribute{ - Ident: "Weight", - + Ident: "Weight", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "weight"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "weight"}, }, &dal.Attribute{ Ident: "Unify", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "unify"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, }, @@ -230,138 +175,107 @@ var ( ResourceType: types.ApigwRouteResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ - Ident: "Endpoint", - + Ident: "Endpoint", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "endpoint"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "endpoint"}, }, &dal.Attribute{ - Ident: "Method", - + Ident: "Method", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "method"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "method"}, }, &dal.Attribute{ - Ident: "Enabled", - + Ident: "Enabled", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "enabled"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "enabled"}, }, &dal.Attribute{ - Ident: "Group", - + Ident: "Group", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "rel_group"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "rel_group"}, }, &dal.Attribute{ Ident: "Meta", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "meta"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ Ident: "CreatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "created_by"}, }, &dal.Attribute{ Ident: "UpdatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "updated_by"}, }, &dal.Attribute{ Ident: "DeletedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "deleted_by"}, }, }, @@ -372,146 +286,114 @@ var ( ResourceType: types.ApigwFilterResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ - Ident: "Route", - + Ident: "Route", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "rel_route"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "rel_route"}, }, &dal.Attribute{ - Ident: "Weight", - + Ident: "Weight", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "weight"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "weight"}, }, &dal.Attribute{ Ident: "Ref", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "ref"}, }, &dal.Attribute{ - Ident: "Kind", - + Ident: "Kind", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "kind"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "kind"}, }, &dal.Attribute{ - Ident: "Enabled", - + Ident: "Enabled", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "enabled"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "enabled"}, }, &dal.Attribute{ Ident: "Params", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "params"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ Ident: "CreatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "created_by"}, }, &dal.Attribute{ Ident: "UpdatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "updated_by"}, }, &dal.Attribute{ Ident: "DeletedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "deleted_by"}, }, }, @@ -522,200 +404,163 @@ var ( ResourceType: types.AuthClientResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ Ident: "Handle", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "handle"}, }, &dal.Attribute{ Ident: "Meta", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "meta"}, }, &dal.Attribute{ Ident: "Secret", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "secret"}, }, &dal.Attribute{ Ident: "Scope", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "scope"}, }, &dal.Attribute{ Ident: "ValidGrant", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "valid_grant"}, }, &dal.Attribute{ Ident: "RedirectURI", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "redirect_uri"}, }, &dal.Attribute{ - Ident: "Enabled", - + Ident: "Enabled", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "enabled"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "enabled"}, }, &dal.Attribute{ - Ident: "Trusted", - + Ident: "Trusted", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "trusted"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "trusted"}, }, &dal.Attribute{ Ident: "ValidFrom", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "valid_from"}, }, &dal.Attribute{ - Ident: "ExpiresAt", - + Ident: "ExpiresAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "expires_at"}, }, &dal.Attribute{ Ident: "Security", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "security"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ Ident: "OwnedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "owned_by"}, }, &dal.Attribute{ Ident: "CreatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "created_by"}, }, &dal.Attribute{ Ident: "UpdatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "updated_by"}, }, &dal.Attribute{ Ident: "DeletedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "deleted_by"}, }, }, @@ -726,35 +571,25 @@ var ( ResourceType: types.AuthConfirmedClientResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "UserID", - + Ident: "UserID", PrimaryKey: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "rel_user"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "rel_user"}, }, &dal.Attribute{ - Ident: "ClientID", - + Ident: "ClientID", PrimaryKey: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "rel_client"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "rel_client"}, }, &dal.Attribute{ - Ident: "ConfirmedAt", - + Ident: "ConfirmedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "confirmed_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "confirmed_at"}, }, }, } @@ -764,66 +599,52 @@ var ( ResourceType: types.AuthSessionResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ Ident: "Data", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "data"}, }, &dal.Attribute{ Ident: "UserID", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "rel_user"}, }, &dal.Attribute{ - Ident: "ExpiresAt", - + Ident: "ExpiresAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "expires_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "expires_at"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ Ident: "RemoteAddr", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "remote_addr"}, }, &dal.Attribute{ Ident: "UserAgent", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "user_agent"}, }, }, @@ -834,98 +655,80 @@ var ( ResourceType: types.AuthOa2tokenResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ Ident: "Code", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "code"}, }, &dal.Attribute{ Ident: "Access", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "access"}, }, &dal.Attribute{ Ident: "Refresh", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "refresh"}, }, &dal.Attribute{ - Ident: "ExpiresAt", - + Ident: "ExpiresAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "expires_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "expires_at"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ Ident: "Data", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "data"}, }, &dal.Attribute{ Ident: "ClientID", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "rel_client"}, }, &dal.Attribute{ Ident: "UserID", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "rel_user"}, }, &dal.Attribute{ Ident: "RemoteAddr", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "remote_addr"}, }, &dal.Attribute{ Ident: "UserAgent", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "user_agent"}, }, }, @@ -936,112 +739,84 @@ var ( ResourceType: types.CredentialResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ Ident: "OwnerID", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "rel_owner"}, }, &dal.Attribute{ Ident: "Kind", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "kind"}, }, &dal.Attribute{ Ident: "Label", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "label"}, }, &dal.Attribute{ Ident: "Credentials", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "credentials"}, }, &dal.Attribute{ Ident: "Meta", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "meta"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ - Ident: "LastUsedAt", - + Ident: "LastUsedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "last_used_at"}, }, &dal.Attribute{ - Ident: "ExpiresAt", - + Ident: "ExpiresAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "expires_at"}, }, }, @@ -1052,156 +827,122 @@ var ( ResourceType: types.DataPrivacyRequestResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ - Ident: "Kind", - + Ident: "Kind", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "kind"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "kind"}, }, &dal.Attribute{ - Ident: "Status", - + Ident: "Status", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "status"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "status"}, }, &dal.Attribute{ Ident: "Payload", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "payload"}, }, &dal.Attribute{ - Ident: "RequestedAt", - + Ident: "RequestedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "requested_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "requested_at"}, }, &dal.Attribute{ Ident: "RequestedBy", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "requested_by"}, }, &dal.Attribute{ - Ident: "CompletedAt", - + Ident: "CompletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "completed_at"}, }, &dal.Attribute{ Ident: "CompletedBy", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "completed_by"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ Ident: "CreatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "created_by"}, }, &dal.Attribute{ Ident: "UpdatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "updated_by"}, }, &dal.Attribute{ Ident: "DeletedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "deleted_by"}, }, }, @@ -1212,106 +953,86 @@ var ( ResourceType: types.DataPrivacyRequestCommentResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ Ident: "RequestID", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "rel_request"}, }, &dal.Attribute{ Ident: "Comment", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "comment"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ Ident: "CreatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "created_by"}, }, &dal.Attribute{ Ident: "UpdatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "updated_by"}, }, &dal.Attribute{ Ident: "DeletedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "deleted_by"}, }, }, @@ -1322,118 +1043,93 @@ var ( ResourceType: types.QueueResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ - Ident: "Consumer", - + Ident: "Consumer", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "consumer"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "consumer"}, }, &dal.Attribute{ - Ident: "Queue", - + Ident: "Queue", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "queue"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "queue"}, }, &dal.Attribute{ Ident: "Meta", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "meta"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ Ident: "CreatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "created_by"}, }, &dal.Attribute{ Ident: "UpdatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "updated_by"}, }, &dal.Attribute{ Ident: "DeletedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "deleted_by"}, }, }, @@ -1444,56 +1140,40 @@ var ( ResourceType: types.QueueMessageResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ - Ident: "Queue", - + Ident: "Queue", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "queue"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "queue"}, }, &dal.Attribute{ Ident: "Payload", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "payload"}, }, &dal.Attribute{ - Ident: "Processed", - + Ident: "Processed", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "processed"}, }, &dal.Attribute{ - Ident: "Created", - + Ident: "Created", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "created"}, }, }, @@ -1504,132 +1184,98 @@ var ( ResourceType: types.ReminderResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ - Ident: "Resource", - + Ident: "Resource", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "resource"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "resource"}, }, &dal.Attribute{ Ident: "Payload", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "payload"}, }, &dal.Attribute{ Ident: "SnoozeCount", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "snooze_count"}, }, &dal.Attribute{ Ident: "AssignedTo", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "assigned_to"}, }, &dal.Attribute{ Ident: "AssignedBy", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "assigned_by"}, }, &dal.Attribute{ - Ident: "AssignedAt", - + Ident: "AssignedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "assigned_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "assigned_at"}, }, &dal.Attribute{ Ident: "DismissedBy", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "dismissed_by"}, }, &dal.Attribute{ - Ident: "DismissedAt", - + Ident: "DismissedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "dismissed_at"}, }, &dal.Attribute{ - Ident: "RemindAt", - + Ident: "RemindAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "remind_at"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, }, @@ -1640,144 +1286,120 @@ var ( ResourceType: types.ReportResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ Ident: "Handle", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "handle"}, }, &dal.Attribute{ Ident: "Meta", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "meta"}, }, &dal.Attribute{ Ident: "Scenarios", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "scenarios"}, }, &dal.Attribute{ Ident: "Sources", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "sources"}, }, &dal.Attribute{ Ident: "Blocks", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "blocks"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ Ident: "OwnedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "owned_by"}, }, &dal.Attribute{ Ident: "CreatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "created_by"}, }, &dal.Attribute{ Ident: "UpdatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "updated_by"}, }, &dal.Attribute{ Ident: "DeletedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "deleted_by"}, }, }, @@ -1788,136 +1410,113 @@ var ( ResourceType: types.ResourceTranslationResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ Ident: "Lang", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "lang"}, }, &dal.Attribute{ Ident: "Resource", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "resource"}, }, &dal.Attribute{ Ident: "K", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "k"}, }, &dal.Attribute{ Ident: "Message", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "message"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ Ident: "OwnedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "owned_by"}, }, &dal.Attribute{ Ident: "CreatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "created_by"}, }, &dal.Attribute{ Ident: "UpdatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "updated_by"}, }, &dal.Attribute{ Ident: "DeletedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "deleted_by"}, }, }, @@ -1928,86 +1527,62 @@ var ( ResourceType: types.RoleResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ - Ident: "Name", - + Ident: "Name", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "name"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "name"}, }, &dal.Attribute{ Ident: "Handle", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "handle"}, }, &dal.Attribute{ Ident: "Meta", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "meta"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ - Ident: "ArchivedAt", - + Ident: "ArchivedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "archived_at"}, }, }, @@ -2018,25 +1593,18 @@ var ( ResourceType: types.RoleMemberResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "UserID", - + Ident: "UserID", PrimaryKey: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "rel_user"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "rel_user"}, }, &dal.Attribute{ - Ident: "RoleID", - + Ident: "RoleID", PrimaryKey: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "rel_role"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "rel_role"}, }, }, } @@ -2046,51 +1614,39 @@ var ( ResourceType: types.SettingValueResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "Name", - + Ident: "Name", PrimaryKey: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "name"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "name"}, }, &dal.Attribute{ - Ident: "OwnedBy", - + Ident: "OwnedBy", PrimaryKey: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "rel_owner"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "rel_owner"}, }, &dal.Attribute{ Ident: "Value", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "value"}, }, &dal.Attribute{ Ident: "UpdatedBy", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "updated_by"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "updated_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "updated_at"}, }, }, } @@ -2100,122 +1656,90 @@ var ( ResourceType: types.TemplateResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ Ident: "Handle", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "handle"}, }, &dal.Attribute{ - Ident: "Language", - + Ident: "Language", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "language"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "language"}, }, &dal.Attribute{ - Ident: "Type", - + Ident: "Type", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "type"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "type"}, }, &dal.Attribute{ Ident: "Partial", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "partial"}, }, &dal.Attribute{ Ident: "Meta", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "meta"}, }, &dal.Attribute{ - Ident: "Template", - + Ident: "Template", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "template"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "template"}, }, &dal.Attribute{ Ident: "OwnerID", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "rel_owner"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ - Ident: "LastUsedAt", - + Ident: "LastUsedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "last_used_at"}, }, }, @@ -2226,124 +1750,90 @@ var ( ResourceType: types.UserResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ Ident: "Handle", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "handle"}, }, &dal.Attribute{ - Ident: "Email", - + Ident: "Email", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "email"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "email"}, }, &dal.Attribute{ Ident: "EmailConfirmed", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "email_confirmed"}, }, &dal.Attribute{ - Ident: "Username", - + Ident: "Username", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "username"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "username"}, }, &dal.Attribute{ - Ident: "Name", - + Ident: "Name", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "name"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "name"}, }, &dal.Attribute{ - Ident: "Kind", - + Ident: "Kind", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "kind"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "kind"}, }, &dal.Attribute{ Ident: "Meta", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "meta"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ - Ident: "SuspendedAt", - + Ident: "SuspendedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "suspended_at"}, }, }, @@ -2354,124 +1844,100 @@ var ( ResourceType: types.DalConnectionResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ Ident: "Handle", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "handle"}, }, &dal.Attribute{ - Ident: "Type", - + Ident: "Type", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "type"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "type"}, }, &dal.Attribute{ Ident: "Meta", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "meta"}, }, &dal.Attribute{ Ident: "Config", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "config"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ Ident: "CreatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "created_by"}, }, &dal.Attribute{ Ident: "UpdatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "updated_by"}, }, &dal.Attribute{ Ident: "DeletedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "deleted_by"}, }, }, @@ -2482,122 +1948,127 @@ var ( ResourceType: types.DalSensitivityLevelResourceType, Attributes: dal.AttributeSet{ - &dal.Attribute{ - Ident: "ID", - + Ident: "ID", PrimaryKey: true, - - Type: dal.TypeID{}, - - Store: &dal.CodecAlias{Ident: "id"}, + Type: &dal.TypeID{}, + Store: &dal.CodecAlias{Ident: "id"}, }, &dal.Attribute{ Ident: "Handle", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "handle"}, }, &dal.Attribute{ - Ident: "Level", - + Ident: "Level", Sortable: true, - - Type: dal.TypeText{}, - - Store: &dal.CodecAlias{Ident: "level"}, + Type: &dal.TypeText{}, + Store: &dal.CodecAlias{Ident: "level"}, }, &dal.Attribute{ Ident: "Meta", - Type: dal.TypeText{}, - + Type: &dal.TypeText{}, Store: &dal.CodecAlias{Ident: "meta"}, }, &dal.Attribute{ - Ident: "CreatedAt", - + Ident: "CreatedAt", Sortable: true, - - Type: dal.TypeTimestamp{}, - - Store: &dal.CodecAlias{Ident: "created_at"}, + Type: &dal.TypeTimestamp{}, + Store: &dal.CodecAlias{Ident: "created_at"}, }, &dal.Attribute{ - Ident: "UpdatedAt", - + Ident: "UpdatedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "updated_at"}, }, &dal.Attribute{ - Ident: "DeletedAt", - + Ident: "DeletedAt", Sortable: true, - - Type: dal.TypeTimestamp{ - Nullable: true, - }, - + Type: &dal.TypeTimestamp{ + Nullable: true}, Store: &dal.CodecAlias{Ident: "deleted_at"}, }, &dal.Attribute{ Ident: "CreatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "created_by"}, }, &dal.Attribute{ Ident: "UpdatedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "updated_by"}, }, &dal.Attribute{ Ident: "DeletedBy", - Type: dal.TypeRef{ + Type: &dal.TypeRef{ RefAttribute: "id", RefModel: &dal.ModelRef{ ResourceType: "corteza::system:user", }, }, - Store: &dal.CodecAlias{Ident: "deleted_by"}, }, }, } ) +func All() dal.ModelSet { + return dal.ModelSet{ + Attachment, + Application, + ApigwRoute, + ApigwFilter, + AuthClient, + AuthConfirmedClient, + AuthSession, + AuthOa2token, + Credential, + DataPrivacyRequest, + DataPrivacyRequestComment, + Queue, + QueueMessage, + Reminder, + Report, + ResourceTranslation, + Role, + RoleMember, + SettingValue, + Template, + User, + DalConnection, + DalSensitivityLevel, + } +} + func Register(ctx context.Context, mr modelReplacer) (err error) { if err = mr.ReplaceModel(ctx, Attachment); err != nil { return