snapshot of https://github.com/cortezaproject/corteza.git (2024.9.x, 2026-09-18; blobs > 131072B omitted)
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
This commit is contained in:
189
server/pkg/dal/diff.go
Normal file
189
server/pkg/dal/diff.go
Normal file
@@ -0,0 +1,189 @@
|
||||
package dal
|
||||
|
||||
type (
|
||||
modelDiffType string
|
||||
// ModelDiff defines one identified missmatch between two models
|
||||
ModelDiff struct {
|
||||
Type modelDiffType
|
||||
// Original will be nil when a new attribute is being added
|
||||
Original *Attribute
|
||||
// Asserted will be nil wen an existing attribute is being removed
|
||||
Asserted *Attribute
|
||||
}
|
||||
|
||||
ModelDiffSet []*ModelDiff
|
||||
)
|
||||
|
||||
const (
|
||||
AttributeMissing modelDiffType = "attributeMissing"
|
||||
AttributeTypeMissmatch modelDiffType = "typeMissmatch"
|
||||
AttributeSensitivityMismatch modelDiffType = "sensitivityMismatch"
|
||||
AttributeCodecMismatch modelDiffType = "codecMismatch"
|
||||
)
|
||||
|
||||
// Diff calculates the diff between models a and b where a is used as base
|
||||
func (a *Model) Diff(b *Model) (out ModelDiffSet) {
|
||||
if a == nil {
|
||||
a = &Model{}
|
||||
}
|
||||
if b == nil {
|
||||
b = &Model{}
|
||||
}
|
||||
|
||||
bIndex := make(map[string]struct {
|
||||
found bool
|
||||
attr *Attribute
|
||||
})
|
||||
for _, _attr := range b.Attributes {
|
||||
attr := _attr
|
||||
bIndex[attr.Ident] = struct {
|
||||
found bool
|
||||
attr *Attribute
|
||||
}{
|
||||
attr: attr,
|
||||
}
|
||||
}
|
||||
|
||||
aIndex := make(map[string]struct {
|
||||
found bool
|
||||
attr *Attribute
|
||||
})
|
||||
for _, _attr := range a.Attributes {
|
||||
attr := _attr
|
||||
aIndex[attr.Ident] = struct {
|
||||
found bool
|
||||
attr *Attribute
|
||||
}{
|
||||
attr: attr,
|
||||
}
|
||||
}
|
||||
|
||||
// Deleted and update ones
|
||||
for _, _attrA := range a.Attributes {
|
||||
attrA := _attrA
|
||||
// store is an interface to something that could be a pointer.
|
||||
// we need to copy it to make sure we don't get a nil pointer
|
||||
// make sure not to modify this since it would modify the original
|
||||
attrA.Store = _attrA.Store
|
||||
|
||||
// Missmatches
|
||||
attrBAux, ok := bIndex[attrA.Ident]
|
||||
if !ok {
|
||||
out = append(out, &ModelDiff{
|
||||
Type: AttributeMissing,
|
||||
Original: attrA,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
// Typecheck
|
||||
if attrA.Type.Type() != attrBAux.attr.Type.Type() {
|
||||
out = append(out, &ModelDiff{
|
||||
Type: AttributeTypeMissmatch,
|
||||
Original: attrA,
|
||||
Asserted: attrBAux.attr,
|
||||
})
|
||||
}
|
||||
|
||||
// Other stuff
|
||||
// @todo improve; for now it'll do
|
||||
if attrA.SensitivityLevelID != attrBAux.attr.SensitivityLevelID {
|
||||
out = append(out, &ModelDiff{
|
||||
Type: AttributeSensitivityMismatch,
|
||||
Original: attrA,
|
||||
Asserted: attrBAux.attr,
|
||||
})
|
||||
}
|
||||
if attrA.Store.Type() != attrBAux.attr.Store.Type() {
|
||||
out = append(out, &ModelDiff{
|
||||
Type: AttributeCodecMismatch,
|
||||
Original: attrA,
|
||||
Asserted: attrBAux.attr,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// New
|
||||
for _, _attrB := range b.Attributes {
|
||||
attrB := _attrB
|
||||
|
||||
// Missmatches
|
||||
_, ok := aIndex[attrB.Ident]
|
||||
if !ok {
|
||||
out = append(out, &ModelDiff{
|
||||
Type: AttributeMissing,
|
||||
Original: nil,
|
||||
Asserted: attrB,
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (dd ModelDiffSet) Alterations() (out []*Alteration) {
|
||||
add := func(a *Alteration) {
|
||||
out = append(out, a)
|
||||
}
|
||||
|
||||
for _, d := range dd {
|
||||
switch d.Type {
|
||||
case AttributeMissing:
|
||||
if d.Asserted == nil {
|
||||
// @todo if this was the last attribute we can consider dropping this column
|
||||
if d.Original.Store.Type() == AttributeCodecRecordValueSetJSON {
|
||||
break
|
||||
}
|
||||
|
||||
add(&Alteration{
|
||||
AttributeDelete: &AttributeDelete{
|
||||
Attr: d.Original,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
if d.Asserted.Store.Type() == AttributeCodecRecordValueSetJSON {
|
||||
add(&Alteration{
|
||||
AttributeAdd: &AttributeAdd{
|
||||
Attr: &Attribute{
|
||||
Ident: d.Asserted.StoreIdent(),
|
||||
Type: &TypeJSON{Nullable: false},
|
||||
Store: &CodecPlain{},
|
||||
},
|
||||
},
|
||||
})
|
||||
} else {
|
||||
add(&Alteration{
|
||||
AttributeAdd: &AttributeAdd{
|
||||
Attr: d.Asserted,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case AttributeTypeMissmatch:
|
||||
// @todo we might have to do some validation earlier on
|
||||
if d.Original.Store.Type() == AttributeCodecRecordValueSetJSON {
|
||||
break
|
||||
}
|
||||
|
||||
add(&Alteration{
|
||||
AttributeReType: &AttributeReType{
|
||||
Attr: d.Asserted,
|
||||
To: d.Asserted.Type,
|
||||
},
|
||||
})
|
||||
|
||||
case AttributeCodecMismatch:
|
||||
add(&Alteration{
|
||||
AttributeReEncode: &AttributeReEncode{
|
||||
Attr: d.Asserted,
|
||||
To: d.Asserted.Store,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user