diff --git a/client/web/compose/src/components/Admin/Module/DalSchemaAlterations.vue b/client/web/compose/src/components/Admin/Module/DalSchemaAlterations.vue index b5959c5d3..d2da9973c 100644 --- a/client/web/compose/src/components/Admin/Module/DalSchemaAlterations.vue +++ b/client/web/compose/src/components/Admin/Module/DalSchemaAlterations.vue @@ -183,7 +183,7 @@ export default { }, batch: { - type: String, + type: Array, required: false, default: undefined, }, @@ -217,8 +217,8 @@ export default { watch: { batch: { handler (batch) { - if (batch) { - this.load(batch) + if (batch && batch.length) { + this.load(...batch) } }, }, @@ -243,7 +243,7 @@ export default { for (const a of alteration) { a.processing = false } - this.load(this.batch) + this.load(...this.batch) this.processing = false }) }, @@ -266,13 +266,13 @@ export default { for (const a of alteration) { a.processing = false } - this.load(this.batch) + this.load(...this.batch) this.processing = false }) }, - async load (batchID) { - if (!batchID) { + async load (...batchID) { + if (!batchID || (batchID && !batchID.length)) { this.alterations = [] return } diff --git a/client/web/compose/src/views/Admin/Modules/Edit.vue b/client/web/compose/src/views/Admin/Modules/Edit.vue index 52eb725d0..e21154647 100644 --- a/client/web/compose/src/views/Admin/Modules/Edit.vue +++ b/client/web/compose/src/views/Admin/Modules/Edit.vue @@ -885,11 +885,12 @@ export default { // Check if module has Alterations to resolve this.dalSchemaAlterations.batchID = undefined - for (const i of this.module.issues) { - if (i.meta.batchID) { - this.dalSchemaAlterations.batchID = i.meta.batchID - break - } + // Pull all batchIDs as they can differ in cases where a related resource + // also requires alterations. + // @todo this should probably perhaps change but I'm not entirely sure how + const aux = (this.module.issues || []).map(({ meta }) => meta.batchID).filter(b => b) + if (aux.length > 0) { + this.dalSchemaAlterations.batchID = aux } }, diff --git a/lib/js/src/api-clients/system.ts b/lib/js/src/api-clients/system.ts index 8e8f7b537..723cf41e5 100644 --- a/lib/js/src/api-clients/system.ts +++ b/lib/js/src/api-clients/system.ts @@ -2529,6 +2529,8 @@ export default class System { const { alterationID, batchID, + resource, + resourceType, kind, deleted, completed, @@ -2543,6 +2545,8 @@ export default class System { cfg.params = { alterationID, batchID, + resource, + resourceType, kind, deleted, completed, diff --git a/server/compose/automation/records_handler.gen.go b/server/compose/automation/records_handler.gen.go index 3a909fd99..f48c5c4c6 100644 --- a/server/compose/automation/records_handler.gen.go +++ b/server/compose/automation/records_handler.gen.go @@ -81,10 +81,9 @@ func (a recordsLookupArgs) GetRecord() (bool, uint64, *types.Record) { // Lookup function Compose record lookup // // expects implementation of lookup function: -// -// func (h recordsHandler) lookup(ctx context.Context, args *recordsLookupArgs) (results *recordsLookupResults, err error) { -// return -// } +// func (h recordsHandler) lookup(ctx context.Context, args *recordsLookupArgs) (results *recordsLookupResults, err error) { +// return +// } func (h recordsHandler) Lookup() *atypes.Function { return &atypes.Function{ Ref: "composeRecordsLookup", @@ -256,10 +255,9 @@ func (a recordsSearchArgs) GetNamespace() (bool, uint64, string, *types.Namespac // Search function Compose records search // // expects implementation of search function: -// -// func (h recordsHandler) search(ctx context.Context, args *recordsSearchArgs) (results *recordsSearchResults, err error) { -// return -// } +// func (h recordsHandler) search(ctx context.Context, args *recordsSearchArgs) (results *recordsSearchResults, err error) { +// return +// } func (h recordsHandler) Search() *atypes.Function { return &atypes.Function{ Ref: "composeRecordsSearch", @@ -510,10 +508,9 @@ func (a recordsFirstArgs) GetNamespace() (bool, uint64, string, *types.Namespace // First function Compose record lookup (first created) // // expects implementation of first function: -// -// func (h recordsHandler) first(ctx context.Context, args *recordsFirstArgs) (results *recordsFirstResults, err error) { -// return -// } +// func (h recordsHandler) first(ctx context.Context, args *recordsFirstArgs) (results *recordsFirstResults, err error) { +// return +// } func (h recordsHandler) First() *atypes.Function { return &atypes.Function{ Ref: "composeRecordsFirst", @@ -640,10 +637,9 @@ func (a recordsLastArgs) GetNamespace() (bool, uint64, string, *types.Namespace) // Last function Compose record lookup (last created) // // expects implementation of last function: -// -// func (h recordsHandler) last(ctx context.Context, args *recordsLastArgs) (results *recordsLastResults, err error) { -// return -// } +// func (h recordsHandler) last(ctx context.Context, args *recordsLastArgs) (results *recordsLastResults, err error) { +// return +// } func (h recordsHandler) Last() *atypes.Function { return &atypes.Function{ Ref: "composeRecordsLast", @@ -796,10 +792,9 @@ func (a recordsEachArgs) GetNamespace() (bool, uint64, string, *types.Namespace) // Each function Compose records // // expects implementation of each function: -// -// func (h recordsHandler) each(ctx context.Context, args *recordsEachArgs) (results *recordsEachResults, err error) { -// return -// } +// func (h recordsHandler) each(ctx context.Context, args *recordsEachArgs) (results *recordsEachResults, err error) { +// return +// } func (h recordsHandler) Each() *atypes.Function { return &atypes.Function{ Ref: "composeRecordsEach", @@ -964,10 +959,9 @@ func (a recordsNewArgs) GetNamespace() (bool, uint64, string, *types.Namespace) // New function Compose record maker // // expects implementation of new function: -// -// func (h recordsHandler) new(ctx context.Context, args *recordsNewArgs) (results *recordsNewResults, err error) { -// return -// } +// func (h recordsHandler) new(ctx context.Context, args *recordsNewArgs) (results *recordsNewResults, err error) { +// return +// } func (h recordsHandler) New() *atypes.Function { return &atypes.Function{ Ref: "composeRecordsNew", @@ -1078,10 +1072,9 @@ type ( // Validate function Compose record validator // // expects implementation of validate function: -// -// func (h recordsHandler) validate(ctx context.Context, args *recordsValidateArgs) (results *recordsValidateResults, err error) { -// return -// } +// func (h recordsHandler) validate(ctx context.Context, args *recordsValidateArgs) (results *recordsValidateResults, err error) { +// return +// } func (h recordsHandler) Validate() *atypes.Function { return &atypes.Function{ Ref: "composeRecordsValidate", @@ -1159,10 +1152,9 @@ type ( // Create function Compose record create // // expects implementation of create function: -// -// func (h recordsHandler) create(ctx context.Context, args *recordsCreateArgs) (results *recordsCreateResults, err error) { -// return -// } +// func (h recordsHandler) create(ctx context.Context, args *recordsCreateArgs) (results *recordsCreateResults, err error) { +// return +// } func (h recordsHandler) Create() *atypes.Function { return &atypes.Function{ Ref: "composeRecordsCreate", @@ -1237,10 +1229,9 @@ type ( // Update function Compose record update // // expects implementation of update function: -// -// func (h recordsHandler) update(ctx context.Context, args *recordsUpdateArgs) (results *recordsUpdateResults, err error) { -// return -// } +// func (h recordsHandler) update(ctx context.Context, args *recordsUpdateArgs) (results *recordsUpdateResults, err error) { +// return +// } func (h recordsHandler) Update() *atypes.Function { return &atypes.Function{ Ref: "composeRecordsUpdate", @@ -1337,10 +1328,9 @@ func (a recordsDeleteArgs) GetRecord() (bool, uint64, *types.Record) { // Delete function Compose record delete // // expects implementation of delete function: -// -// func (h recordsHandler) delete(ctx context.Context, args *recordsDeleteArgs) (err error) { -// return -// } +// func (h recordsHandler) delete(ctx context.Context, args *recordsDeleteArgs) (err error) { +// return +// } func (h recordsHandler) Delete() *atypes.Function { return &atypes.Function{ Ref: "composeRecordsDelete", @@ -1464,10 +1454,9 @@ func (a recordsReportArgs) GetNamespace() (bool, uint64, string, *types.Namespac // Report function Report // // expects implementation of report function: -// -// func (h recordsHandler) report(ctx context.Context, args *recordsReportArgs) (results *recordsReportResults, err error) { -// return -// } +// func (h recordsHandler) report(ctx context.Context, args *recordsReportArgs) (results *recordsReportResults, err error) { +// return +// } func (h recordsHandler) Report() *atypes.Function { return &atypes.Function{ Ref: "composeRecordsReport", diff --git a/server/compose/service/module.go b/server/compose/service/module.go index ba4bb009f..76c4eb115 100644 --- a/server/compose/service/module.go +++ b/server/compose/service/module.go @@ -310,6 +310,7 @@ func (svc module) procDal(m *types.Module) { } m.Issues = svc.dal.SearchModelIssues(m.ID) + m.Issues = append(m.Issues, svc.dal.SearchResourceIssues("corteza::system:revision", m.RbacResource())...) if len(m.Issues) == 0 { m.Issues = nil } diff --git a/server/pkg/dal/issues.go b/server/pkg/dal/issues.go index 828b435a0..6b317371b 100644 --- a/server/pkg/dal/issues.go +++ b/server/pkg/dal/issues.go @@ -45,6 +45,19 @@ func (svc *service) SearchModelIssues(resourceID uint64) (out []Issue) { return svc.modelIssues[resourceID] } +func (svc *service) SearchResourceIssues(resourceType, resource string) (out []Issue) { + var m *Model + for _, ax := range svc.models { + m = ax.FindByResourceIdent(resourceType, resource) + } + + if m == nil { + return + } + + return svc.modelIssues[m.ResourceID] +} + func (svc *service) hasConnectionIssues(connectionID uint64) bool { return len(svc.SearchConnectionIssues(connectionID)) > 0 } diff --git a/server/pkg/dal/service.go b/server/pkg/dal/service.go index 0b0050ecb..4cef0eaeb 100644 --- a/server/pkg/dal/service.go +++ b/server/pkg/dal/service.go @@ -64,6 +64,7 @@ type ( SearchConnectionIssues(connectionID uint64) (out []Issue) SearchModelIssues(resourceID uint64) (out []Issue) + SearchResourceIssues(resourceType, resource string) (out []Issue) } ) @@ -794,6 +795,41 @@ func (svc *service) ApplyAlteration(ctx context.Context, alts ...*Alteration) (e return } + altsIndexed := make(map[uint64]map[string]map[string][]*Alteration) + for _, a := range alts { + if _, ok := altsIndexed[a.ConnectionID]; !ok { + altsIndexed[a.ConnectionID] = make(map[string]map[string][]*Alteration) + } + + if _, ok := altsIndexed[a.ConnectionID][a.ResourceType]; !ok { + altsIndexed[a.ConnectionID][a.ResourceType] = make(map[string][]*Alteration) + } + + altsIndexed[a.ConnectionID][a.ResourceType][a.Resource] = append(altsIndexed[a.ConnectionID][a.ResourceType][a.Resource], a) + } + + var auxErrs []error + for _, byCon := range altsIndexed { + for _, byRt := range byCon { + for _, byR := range byRt { + auxErrs, err = svc.applyAlteration(ctx, byR...) + if err != nil { + return + } + + errs = append(errs, auxErrs...) + } + } + } + + return +} + +func (svc *service) applyAlteration(ctx context.Context, alts ...*Alteration) (errs []error, err error) { + if len(alts) == 0 { + return + } + var ( connectionID = alts[0].ConnectionID resource = alts[0].Resource diff --git a/server/store/adapters/rdbms/filters.gen.go b/server/store/adapters/rdbms/filters.gen.go index c920ddeec..0d4f445cf 100644 --- a/server/store/adapters/rdbms/filters.gen.go +++ b/server/store/adapters/rdbms/filters.gen.go @@ -831,8 +831,8 @@ func DalSchemaAlterationFilter(d drivers.Dialect, f systemType.DalSchemaAlterati ee = append(ee, goqu.C("id").In(f.AlterationID)) } - if f.BatchID > 0 { - ee = append(ee, goqu.C("batch_id").Eq(f.BatchID)) + if len(f.BatchID) > 0 { + ee = append(ee, goqu.C("batch_id").In(f.BatchID)) } return ee, f, err diff --git a/server/system/dal_schema_alteration.cue b/server/system/dal_schema_alteration.cue index d34192c2e..62bda7927 100644 --- a/server/system/dal_schema_alteration.cue +++ b/server/system/dal_schema_alteration.cue @@ -86,7 +86,7 @@ dal_schema_alteration: { resource: {goType: "[]string", ident: "resource" } resourceType: {goType: "string", ident: "resourceType", storeIdent: "resource_type" } alteration_id: {goType: "[]uint64", ident: "alterationID", storeIdent: "id" } - batch_id: {goType: "uint64", ident: "batchID" } + batch_id: {goType: "[]uint64", ident: "batchID" } kind: {} deleted: {goType: "filter.State", storeIdent: "deleted_at"} completed: {goType: "filter.State", storeIdent: "completed_at"} diff --git a/server/system/rest.yaml b/server/system/rest.yaml index 236958213..7b17b5e1f 100644 --- a/server/system/rest.yaml +++ b/server/system/rest.yaml @@ -932,8 +932,14 @@ endpoints: type: "[]string" title: Filter by alteration ID - name: batchID - type: "uint64" + type: "[]string" title: Filter by batch ID + - name: resource + type: "[]string" + title: Search by resource + - name: resourceType + type: string + title: Search by resource type - type: string name: kind title: Search by kind diff --git a/server/system/rest/dal_schema_alteration.go b/server/system/rest/dal_schema_alteration.go index a3b19ea26..d736b444a 100644 --- a/server/system/rest/dal_schema_alteration.go +++ b/server/system/rest/dal_schema_alteration.go @@ -5,6 +5,7 @@ import ( "github.com/cortezaproject/corteza/server/pkg/api" "github.com/cortezaproject/corteza/server/pkg/filter" + "github.com/cortezaproject/corteza/server/pkg/id" "github.com/cortezaproject/corteza/server/system/rest/request" "github.com/cortezaproject/corteza/server/system/service" "github.com/cortezaproject/corteza/server/system/types" @@ -60,8 +61,10 @@ func (ctrl DalSchemaAlteration) List(ctx context.Context, r *request.DalSchemaAl f = types.DalSchemaAlterationFilter{ AlterationID: r.AlterationID, - BatchID: r.BatchID, + BatchID: id.Uints(r.BatchID...), Kind: r.Kind, + Resource: r.Resource, + ResourceType: r.ResourceType, Deleted: filter.State(r.Deleted), Dismissed: filter.State(r.Dismissed), diff --git a/server/system/rest/request/dalSchemaAlteration.go b/server/system/rest/request/dalSchemaAlteration.go index 28443e940..55fe40d53 100644 --- a/server/system/rest/request/dalSchemaAlteration.go +++ b/server/system/rest/request/dalSchemaAlteration.go @@ -42,7 +42,17 @@ type ( // BatchID GET parameter // // Filter by batch ID - BatchID uint64 `json:",string"` + BatchID []string + + // Resource GET parameter + // + // Search by resource + Resource []string + + // ResourceType GET parameter + // + // Search by resource type + ResourceType string // Kind GET parameter // @@ -102,6 +112,8 @@ func (r DalSchemaAlterationList) Auditable() map[string]interface{} { return map[string]interface{}{ "alterationID": r.AlterationID, "batchID": r.BatchID, + "resource": r.Resource, + "resourceType": r.ResourceType, "kind": r.Kind, "deleted": r.Deleted, "completed": r.Completed, @@ -116,10 +128,20 @@ func (r DalSchemaAlterationList) GetAlterationID() []string { } // Auditable returns all auditable/loggable parameters -func (r DalSchemaAlterationList) GetBatchID() uint64 { +func (r DalSchemaAlterationList) GetBatchID() []string { return r.BatchID } +// Auditable returns all auditable/loggable parameters +func (r DalSchemaAlterationList) GetResource() []string { + return r.Resource +} + +// Auditable returns all auditable/loggable parameters +func (r DalSchemaAlterationList) GetResourceType() string { + return r.ResourceType +} + // Auditable returns all auditable/loggable parameters func (r DalSchemaAlterationList) GetKind() string { return r.Kind @@ -163,8 +185,30 @@ func (r *DalSchemaAlterationList) Fill(req *http.Request) (err error) { return err } } - if val, ok := tmp["batchID"]; ok && len(val) > 0 { - r.BatchID, err = payload.ParseUint64(val[0]), nil + if val, ok := tmp["batchID[]"]; ok { + r.BatchID, err = val, nil + if err != nil { + return err + } + } else if val, ok := tmp["batchID"]; ok { + r.BatchID, err = val, nil + if err != nil { + return err + } + } + if val, ok := tmp["resource[]"]; ok { + r.Resource, err = val, nil + if err != nil { + return err + } + } else if val, ok := tmp["resource"]; ok { + r.Resource, err = val, nil + if err != nil { + return err + } + } + if val, ok := tmp["resourceType"]; ok && len(val) > 0 { + r.ResourceType, err = val[0], nil if err != nil { return err } diff --git a/server/system/service/dal_schema_alteration.go b/server/system/service/dal_schema_alteration.go index a5b846075..637412485 100644 --- a/server/system/service/dal_schema_alteration.go +++ b/server/system/service/dal_schema_alteration.go @@ -402,25 +402,37 @@ func (svc dalSchemaAlteration) toPkgAlterations(ctx context.Context, aa ...*type } func (svc dalSchemaAlteration) reloadAlteredModels(ctx context.Context, s store.Storer, alts types.DalSchemaAlterationSet) (err error) { - if len(alts) == 0 { - return + // Skip any models whish were already reloaded by some alterations. + // These might be mixed up so we'll need to do it like so. + processed := make(map[string]bool, 3) + mkKey := func(a *types.DalSchemaAlteration) string { + return fmt.Sprintf("%s;%s", a.ResourceType, a.Resource) } - // @todo consider lifting this constraint and handle arbitrary sets of alterations for _, a := range alts { - if a.Resource != alts[0].Resource { - panic("reloadAlteredModels requires all alterations to be for the same resource") + k := mkKey(a) + if processed[k] { + continue + } + processed[k] = true + + err = svc.reloadAlteredModel(ctx, s, a) + if err != nil { + return } } - alt := alts[0] + return +} +func (svc dalSchemaAlteration) reloadAlteredModel(ctx context.Context, s store.Storer, alt *types.DalSchemaAlteration) (err error) { // Fetch current alterations to see if there are any left over _, f, err := store.SearchDalSchemaAlterations(ctx, s, types.DalSchemaAlterationFilter{ - Resource: []string{alt.Resource}, - Deleted: filter.StateExcluded, - Completed: filter.StateExcluded, - Dismissed: filter.StateExcluded, + Resource: []string{alt.Resource}, + ResourceType: alt.ResourceType, + Deleted: filter.StateExcluded, + Completed: filter.StateExcluded, + Dismissed: filter.StateExcluded, Paging: filter.Paging{ IncTotal: true, diff --git a/server/system/types/dal_schema_ateration.go b/server/system/types/dal_schema_ateration.go index 347c27b2c..859d75f63 100644 --- a/server/system/types/dal_schema_ateration.go +++ b/server/system/types/dal_schema_ateration.go @@ -49,7 +49,7 @@ type ( DalSchemaAlterationFilter struct { AlterationID []string `json:"alterationID"` - BatchID uint64 `json:"batchID,string"` + BatchID []uint64 `json:"batchID,string"` Kind string `json:"kind"` Resource []string `json:"resource"` ResourceType string `json:"resourceType"`