3
0

Fix dal schema alterations not presenting/reloading revision models

This commit is contained in:
Tomaž Jerman 2023-12-12 15:27:48 +01:00
parent 3e1d7bd42b
commit 33821ddd9f
14 changed files with 185 additions and 76 deletions

View File

@ -183,7 +183,7 @@ export default {
}, },
batch: { batch: {
type: String, type: Array,
required: false, required: false,
default: undefined, default: undefined,
}, },
@ -217,8 +217,8 @@ export default {
watch: { watch: {
batch: { batch: {
handler (batch) { handler (batch) {
if (batch) { if (batch && batch.length) {
this.load(batch) this.load(...batch)
} }
}, },
}, },
@ -243,7 +243,7 @@ export default {
for (const a of alteration) { for (const a of alteration) {
a.processing = false a.processing = false
} }
this.load(this.batch) this.load(...this.batch)
this.processing = false this.processing = false
}) })
}, },
@ -266,13 +266,13 @@ export default {
for (const a of alteration) { for (const a of alteration) {
a.processing = false a.processing = false
} }
this.load(this.batch) this.load(...this.batch)
this.processing = false this.processing = false
}) })
}, },
async load (batchID) { async load (...batchID) {
if (!batchID) { if (!batchID || (batchID && !batchID.length)) {
this.alterations = [] this.alterations = []
return return
} }

View File

@ -885,11 +885,12 @@ export default {
// Check if module has Alterations to resolve // Check if module has Alterations to resolve
this.dalSchemaAlterations.batchID = undefined this.dalSchemaAlterations.batchID = undefined
for (const i of this.module.issues) { // Pull all batchIDs as they can differ in cases where a related resource
if (i.meta.batchID) { // also requires alterations.
this.dalSchemaAlterations.batchID = i.meta.batchID // @todo this should probably perhaps change but I'm not entirely sure how
break const aux = (this.module.issues || []).map(({ meta }) => meta.batchID).filter(b => b)
} if (aux.length > 0) {
this.dalSchemaAlterations.batchID = aux
} }
}, },

View File

@ -2529,6 +2529,8 @@ export default class System {
const { const {
alterationID, alterationID,
batchID, batchID,
resource,
resourceType,
kind, kind,
deleted, deleted,
completed, completed,
@ -2543,6 +2545,8 @@ export default class System {
cfg.params = { cfg.params = {
alterationID, alterationID,
batchID, batchID,
resource,
resourceType,
kind, kind,
deleted, deleted,
completed, completed,

View File

@ -81,10 +81,9 @@ func (a recordsLookupArgs) GetRecord() (bool, uint64, *types.Record) {
// Lookup function Compose record lookup // Lookup function Compose record lookup
// //
// expects implementation of lookup function: // expects implementation of lookup function:
// // func (h recordsHandler) lookup(ctx context.Context, args *recordsLookupArgs) (results *recordsLookupResults, err error) {
// func (h recordsHandler) lookup(ctx context.Context, args *recordsLookupArgs) (results *recordsLookupResults, err error) { // return
// return // }
// }
func (h recordsHandler) Lookup() *atypes.Function { func (h recordsHandler) Lookup() *atypes.Function {
return &atypes.Function{ return &atypes.Function{
Ref: "composeRecordsLookup", Ref: "composeRecordsLookup",
@ -256,10 +255,9 @@ func (a recordsSearchArgs) GetNamespace() (bool, uint64, string, *types.Namespac
// Search function Compose records search // Search function Compose records search
// //
// expects implementation of search function: // expects implementation of search function:
// // func (h recordsHandler) search(ctx context.Context, args *recordsSearchArgs) (results *recordsSearchResults, err error) {
// func (h recordsHandler) search(ctx context.Context, args *recordsSearchArgs) (results *recordsSearchResults, err error) { // return
// return // }
// }
func (h recordsHandler) Search() *atypes.Function { func (h recordsHandler) Search() *atypes.Function {
return &atypes.Function{ return &atypes.Function{
Ref: "composeRecordsSearch", Ref: "composeRecordsSearch",
@ -510,10 +508,9 @@ func (a recordsFirstArgs) GetNamespace() (bool, uint64, string, *types.Namespace
// First function Compose record lookup (first created) // First function Compose record lookup (first created)
// //
// expects implementation of first function: // expects implementation of first function:
// // func (h recordsHandler) first(ctx context.Context, args *recordsFirstArgs) (results *recordsFirstResults, err error) {
// func (h recordsHandler) first(ctx context.Context, args *recordsFirstArgs) (results *recordsFirstResults, err error) { // return
// return // }
// }
func (h recordsHandler) First() *atypes.Function { func (h recordsHandler) First() *atypes.Function {
return &atypes.Function{ return &atypes.Function{
Ref: "composeRecordsFirst", Ref: "composeRecordsFirst",
@ -640,10 +637,9 @@ func (a recordsLastArgs) GetNamespace() (bool, uint64, string, *types.Namespace)
// Last function Compose record lookup (last created) // Last function Compose record lookup (last created)
// //
// expects implementation of last function: // expects implementation of last function:
// // func (h recordsHandler) last(ctx context.Context, args *recordsLastArgs) (results *recordsLastResults, err error) {
// func (h recordsHandler) last(ctx context.Context, args *recordsLastArgs) (results *recordsLastResults, err error) { // return
// return // }
// }
func (h recordsHandler) Last() *atypes.Function { func (h recordsHandler) Last() *atypes.Function {
return &atypes.Function{ return &atypes.Function{
Ref: "composeRecordsLast", Ref: "composeRecordsLast",
@ -796,10 +792,9 @@ func (a recordsEachArgs) GetNamespace() (bool, uint64, string, *types.Namespace)
// Each function Compose records // Each function Compose records
// //
// expects implementation of each function: // expects implementation of each function:
// // func (h recordsHandler) each(ctx context.Context, args *recordsEachArgs) (results *recordsEachResults, err error) {
// func (h recordsHandler) each(ctx context.Context, args *recordsEachArgs) (results *recordsEachResults, err error) { // return
// return // }
// }
func (h recordsHandler) Each() *atypes.Function { func (h recordsHandler) Each() *atypes.Function {
return &atypes.Function{ return &atypes.Function{
Ref: "composeRecordsEach", Ref: "composeRecordsEach",
@ -964,10 +959,9 @@ func (a recordsNewArgs) GetNamespace() (bool, uint64, string, *types.Namespace)
// New function Compose record maker // New function Compose record maker
// //
// expects implementation of new function: // expects implementation of new function:
// // func (h recordsHandler) new(ctx context.Context, args *recordsNewArgs) (results *recordsNewResults, err error) {
// func (h recordsHandler) new(ctx context.Context, args *recordsNewArgs) (results *recordsNewResults, err error) { // return
// return // }
// }
func (h recordsHandler) New() *atypes.Function { func (h recordsHandler) New() *atypes.Function {
return &atypes.Function{ return &atypes.Function{
Ref: "composeRecordsNew", Ref: "composeRecordsNew",
@ -1078,10 +1072,9 @@ type (
// Validate function Compose record validator // Validate function Compose record validator
// //
// expects implementation of validate function: // expects implementation of validate function:
// // func (h recordsHandler) validate(ctx context.Context, args *recordsValidateArgs) (results *recordsValidateResults, err error) {
// func (h recordsHandler) validate(ctx context.Context, args *recordsValidateArgs) (results *recordsValidateResults, err error) { // return
// return // }
// }
func (h recordsHandler) Validate() *atypes.Function { func (h recordsHandler) Validate() *atypes.Function {
return &atypes.Function{ return &atypes.Function{
Ref: "composeRecordsValidate", Ref: "composeRecordsValidate",
@ -1159,10 +1152,9 @@ type (
// Create function Compose record create // Create function Compose record create
// //
// expects implementation of create function: // expects implementation of create function:
// // func (h recordsHandler) create(ctx context.Context, args *recordsCreateArgs) (results *recordsCreateResults, err error) {
// func (h recordsHandler) create(ctx context.Context, args *recordsCreateArgs) (results *recordsCreateResults, err error) { // return
// return // }
// }
func (h recordsHandler) Create() *atypes.Function { func (h recordsHandler) Create() *atypes.Function {
return &atypes.Function{ return &atypes.Function{
Ref: "composeRecordsCreate", Ref: "composeRecordsCreate",
@ -1237,10 +1229,9 @@ type (
// Update function Compose record update // Update function Compose record update
// //
// expects implementation of update function: // expects implementation of update function:
// // func (h recordsHandler) update(ctx context.Context, args *recordsUpdateArgs) (results *recordsUpdateResults, err error) {
// func (h recordsHandler) update(ctx context.Context, args *recordsUpdateArgs) (results *recordsUpdateResults, err error) { // return
// return // }
// }
func (h recordsHandler) Update() *atypes.Function { func (h recordsHandler) Update() *atypes.Function {
return &atypes.Function{ return &atypes.Function{
Ref: "composeRecordsUpdate", Ref: "composeRecordsUpdate",
@ -1337,10 +1328,9 @@ func (a recordsDeleteArgs) GetRecord() (bool, uint64, *types.Record) {
// Delete function Compose record delete // Delete function Compose record delete
// //
// expects implementation of delete function: // expects implementation of delete function:
// // func (h recordsHandler) delete(ctx context.Context, args *recordsDeleteArgs) (err error) {
// func (h recordsHandler) delete(ctx context.Context, args *recordsDeleteArgs) (err error) { // return
// return // }
// }
func (h recordsHandler) Delete() *atypes.Function { func (h recordsHandler) Delete() *atypes.Function {
return &atypes.Function{ return &atypes.Function{
Ref: "composeRecordsDelete", Ref: "composeRecordsDelete",
@ -1464,10 +1454,9 @@ func (a recordsReportArgs) GetNamespace() (bool, uint64, string, *types.Namespac
// Report function Report // Report function Report
// //
// expects implementation of report function: // expects implementation of report function:
// // func (h recordsHandler) report(ctx context.Context, args *recordsReportArgs) (results *recordsReportResults, err error) {
// func (h recordsHandler) report(ctx context.Context, args *recordsReportArgs) (results *recordsReportResults, err error) { // return
// return // }
// }
func (h recordsHandler) Report() *atypes.Function { func (h recordsHandler) Report() *atypes.Function {
return &atypes.Function{ return &atypes.Function{
Ref: "composeRecordsReport", Ref: "composeRecordsReport",

View File

@ -310,6 +310,7 @@ func (svc module) procDal(m *types.Module) {
} }
m.Issues = svc.dal.SearchModelIssues(m.ID) 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 { if len(m.Issues) == 0 {
m.Issues = nil m.Issues = nil
} }

View File

@ -45,6 +45,19 @@ func (svc *service) SearchModelIssues(resourceID uint64) (out []Issue) {
return svc.modelIssues[resourceID] 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 { func (svc *service) hasConnectionIssues(connectionID uint64) bool {
return len(svc.SearchConnectionIssues(connectionID)) > 0 return len(svc.SearchConnectionIssues(connectionID)) > 0
} }

View File

@ -64,6 +64,7 @@ type (
SearchConnectionIssues(connectionID uint64) (out []Issue) SearchConnectionIssues(connectionID uint64) (out []Issue)
SearchModelIssues(resourceID 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 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 ( var (
connectionID = alts[0].ConnectionID connectionID = alts[0].ConnectionID
resource = alts[0].Resource resource = alts[0].Resource

View File

@ -831,8 +831,8 @@ func DalSchemaAlterationFilter(d drivers.Dialect, f systemType.DalSchemaAlterati
ee = append(ee, goqu.C("id").In(f.AlterationID)) ee = append(ee, goqu.C("id").In(f.AlterationID))
} }
if f.BatchID > 0 { if len(f.BatchID) > 0 {
ee = append(ee, goqu.C("batch_id").Eq(f.BatchID)) ee = append(ee, goqu.C("batch_id").In(f.BatchID))
} }
return ee, f, err return ee, f, err

View File

@ -86,7 +86,7 @@ dal_schema_alteration: {
resource: {goType: "[]string", ident: "resource" } resource: {goType: "[]string", ident: "resource" }
resourceType: {goType: "string", ident: "resourceType", storeIdent: "resource_type" } resourceType: {goType: "string", ident: "resourceType", storeIdent: "resource_type" }
alteration_id: {goType: "[]uint64", ident: "alterationID", storeIdent: "id" } alteration_id: {goType: "[]uint64", ident: "alterationID", storeIdent: "id" }
batch_id: {goType: "uint64", ident: "batchID" } batch_id: {goType: "[]uint64", ident: "batchID" }
kind: {} kind: {}
deleted: {goType: "filter.State", storeIdent: "deleted_at"} deleted: {goType: "filter.State", storeIdent: "deleted_at"}
completed: {goType: "filter.State", storeIdent: "completed_at"} completed: {goType: "filter.State", storeIdent: "completed_at"}

View File

@ -932,8 +932,14 @@ endpoints:
type: "[]string" type: "[]string"
title: Filter by alteration ID title: Filter by alteration ID
- name: batchID - name: batchID
type: "uint64" type: "[]string"
title: Filter by batch ID title: Filter by batch ID
- name: resource
type: "[]string"
title: Search by resource
- name: resourceType
type: string
title: Search by resource type
- type: string - type: string
name: kind name: kind
title: Search by kind title: Search by kind

View File

@ -5,6 +5,7 @@ import (
"github.com/cortezaproject/corteza/server/pkg/api" "github.com/cortezaproject/corteza/server/pkg/api"
"github.com/cortezaproject/corteza/server/pkg/filter" "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/rest/request"
"github.com/cortezaproject/corteza/server/system/service" "github.com/cortezaproject/corteza/server/system/service"
"github.com/cortezaproject/corteza/server/system/types" "github.com/cortezaproject/corteza/server/system/types"
@ -60,8 +61,10 @@ func (ctrl DalSchemaAlteration) List(ctx context.Context, r *request.DalSchemaAl
f = types.DalSchemaAlterationFilter{ f = types.DalSchemaAlterationFilter{
AlterationID: r.AlterationID, AlterationID: r.AlterationID,
BatchID: r.BatchID, BatchID: id.Uints(r.BatchID...),
Kind: r.Kind, Kind: r.Kind,
Resource: r.Resource,
ResourceType: r.ResourceType,
Deleted: filter.State(r.Deleted), Deleted: filter.State(r.Deleted),
Dismissed: filter.State(r.Dismissed), Dismissed: filter.State(r.Dismissed),

View File

@ -42,7 +42,17 @@ type (
// BatchID GET parameter // BatchID GET parameter
// //
// Filter by batch ID // 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 // Kind GET parameter
// //
@ -102,6 +112,8 @@ func (r DalSchemaAlterationList) Auditable() map[string]interface{} {
return map[string]interface{}{ return map[string]interface{}{
"alterationID": r.AlterationID, "alterationID": r.AlterationID,
"batchID": r.BatchID, "batchID": r.BatchID,
"resource": r.Resource,
"resourceType": r.ResourceType,
"kind": r.Kind, "kind": r.Kind,
"deleted": r.Deleted, "deleted": r.Deleted,
"completed": r.Completed, "completed": r.Completed,
@ -116,10 +128,20 @@ func (r DalSchemaAlterationList) GetAlterationID() []string {
} }
// Auditable returns all auditable/loggable parameters // Auditable returns all auditable/loggable parameters
func (r DalSchemaAlterationList) GetBatchID() uint64 { func (r DalSchemaAlterationList) GetBatchID() []string {
return r.BatchID 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 // Auditable returns all auditable/loggable parameters
func (r DalSchemaAlterationList) GetKind() string { func (r DalSchemaAlterationList) GetKind() string {
return r.Kind return r.Kind
@ -163,8 +185,30 @@ func (r *DalSchemaAlterationList) Fill(req *http.Request) (err error) {
return err return err
} }
} }
if val, ok := tmp["batchID"]; ok && len(val) > 0 { if val, ok := tmp["batchID[]"]; ok {
r.BatchID, err = payload.ParseUint64(val[0]), nil 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 { if err != nil {
return err return err
} }

View File

@ -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) { func (svc dalSchemaAlteration) reloadAlteredModels(ctx context.Context, s store.Storer, alts types.DalSchemaAlterationSet) (err error) {
if len(alts) == 0 { // Skip any models whish were already reloaded by some alterations.
return // 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 { for _, a := range alts {
if a.Resource != alts[0].Resource { k := mkKey(a)
panic("reloadAlteredModels requires all alterations to be for the same resource") 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 // Fetch current alterations to see if there are any left over
_, f, err := store.SearchDalSchemaAlterations(ctx, s, types.DalSchemaAlterationFilter{ _, f, err := store.SearchDalSchemaAlterations(ctx, s, types.DalSchemaAlterationFilter{
Resource: []string{alt.Resource}, Resource: []string{alt.Resource},
Deleted: filter.StateExcluded, ResourceType: alt.ResourceType,
Completed: filter.StateExcluded, Deleted: filter.StateExcluded,
Dismissed: filter.StateExcluded, Completed: filter.StateExcluded,
Dismissed: filter.StateExcluded,
Paging: filter.Paging{ Paging: filter.Paging{
IncTotal: true, IncTotal: true,

View File

@ -49,7 +49,7 @@ type (
DalSchemaAlterationFilter struct { DalSchemaAlterationFilter struct {
AlterationID []string `json:"alterationID"` AlterationID []string `json:"alterationID"`
BatchID uint64 `json:"batchID,string"` BatchID []uint64 `json:"batchID,string"`
Kind string `json:"kind"` Kind string `json:"kind"`
Resource []string `json:"resource"` Resource []string `json:"resource"`
ResourceType string `json:"resourceType"` ResourceType string `json:"resourceType"`