github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/appdef/impl_unique.go (about) 1 /* 2 * Copyright (c) 2023-present Sigma-Soft, Ltd. 3 * @author: Nikolay Nikitin 4 */ 5 6 package appdef 7 8 import ( 9 "fmt" 10 "slices" 11 ) 12 13 // # Implements: 14 // - IUnique 15 type unique struct { 16 comment 17 name QName 18 fields []IField 19 } 20 21 func newUnique(name QName, fieldNames []FieldName, fields IFields) *unique { 22 u := &unique{ 23 name: name, 24 fields: make([]IField, 0), 25 } 26 slices.Sort(fieldNames) 27 for _, f := range fieldNames { 28 fld := fields.Field(f) 29 if fld == nil { 30 panic(ErrFieldNotFound(f)) 31 } 32 u.fields = append(u.fields, fld) 33 } 34 return u 35 } 36 37 func (u unique) Name() QName { 38 return u.name 39 } 40 41 func (u unique) Fields() []IField { 42 return u.fields 43 } 44 45 func (u unique) String() string { 46 return fmt.Sprintf("unique «%v»", u.name) 47 } 48 49 // # Implements: 50 // - IUniques 51 type uniques struct { 52 app *appDef 53 fields IFields 54 uniques map[QName]IUnique 55 field IField 56 } 57 58 func makeUniques(app *appDef, fields IFields) uniques { 59 uu := uniques{ 60 app: app, 61 fields: fields, 62 uniques: make(map[QName]IUnique), 63 } 64 return uu 65 } 66 67 func (uu *uniques) setUniqueField(name FieldName) { 68 if name == NullName { 69 uu.field = nil 70 return 71 } 72 if ok, err := ValidFieldName(name); !ok { 73 panic((fmt.Errorf("unique field name «%v» is invalid: %w", name, err))) 74 } 75 76 fld := uu.fields.Field(name) 77 if fld == nil { 78 panic(ErrFieldNotFound(name)) 79 } 80 81 uu.field = fld 82 } 83 84 func (uu uniques) UniqueByName(name QName) IUnique { 85 if u, ok := uu.uniques[name]; ok { 86 return u 87 } 88 return nil 89 } 90 91 func (uu uniques) UniqueCount() int { 92 return len(uu.uniques) 93 } 94 95 func (uu uniques) UniqueField() IField { 96 return uu.field 97 } 98 99 func (uu uniques) Uniques() map[QName]IUnique { 100 return uu.uniques 101 } 102 103 func (uu *uniques) addUnique(name QName, fields []FieldName, comment ...string) { 104 if name == NullQName { 105 panic(ErrMissed("unique name")) 106 } 107 if ok, err := ValidQName(name); !ok { 108 panic(fmt.Errorf("unique name «%v» is invalid: %w", name, err)) 109 } 110 if uu.UniqueByName(name) != nil { 111 panic(ErrAlreadyExists("unique «%v»", name)) 112 } 113 114 if uu.app != nil { 115 if t := uu.app.TypeByName(name); t != nil { 116 panic(ErrAlreadyExists("unique «%v» already used for %v", name, t)) 117 } 118 } 119 120 if len(fields) == 0 { 121 panic(ErrMissed("unique «%v» fields", name)) 122 } 123 if i, j := duplicates(fields); i >= 0 { 124 panic(ErrAlreadyExists("fields in unique «%v» has duplicates (fields[%d] == fields[%d] == %q)", name, i, j, fields[i])) 125 } 126 127 if len(fields) > MaxTypeUniqueFieldsCount { 128 panic(ErrTooMany("fields in unique «%v», maximum is %d", name, MaxTypeUniqueFieldsCount)) 129 } 130 131 for _, un := range uu.uniques { 132 ff := make([]FieldName, 0) 133 for _, f := range un.Fields() { 134 ff = append(ff, f.Name()) 135 } 136 if overlaps(fields, ff) { 137 panic(ErrAlreadyExists("type already has %v which fields overlaps new unique fields", un)) 138 } 139 } 140 141 if len(uu.uniques) >= MaxTypeUniqueCount { 142 panic(ErrTooMany("uniques, maximum is %d", MaxTypeUniqueCount)) 143 } 144 145 un := newUnique(name, fields, uu.fields) 146 un.comment.setComment(comment...) 147 148 uu.uniques[name] = un 149 } 150 151 // # Implements: 152 // - IUniquesBuilder 153 type uniquesBuilder struct { 154 *uniques 155 } 156 157 func makeUniquesBuilder(uniques *uniques) uniquesBuilder { 158 return uniquesBuilder{ 159 uniques: uniques, 160 } 161 } 162 163 func (ub *uniquesBuilder) AddUnique(name QName, fields []FieldName, comment ...string) IUniquesBuilder { 164 ub.addUnique(name, fields, comment...) 165 return ub 166 } 167 168 func (ub *uniquesBuilder) SetUniqueField(name FieldName) IUniquesBuilder { 169 ub.setUniqueField(name) 170 return ub 171 } 172 173 // If the slices have duplicates, then the indices of the first pair are returned, otherwise (-1, -1) 174 func duplicates[T comparable](s []T) (int, int) { 175 for i := range s { 176 for j := i + 1; j < len(s); j++ { 177 if s[i] == s[j] { 178 return i, j 179 } 180 } 181 } 182 return -1, -1 183 } 184 185 // Returns is slice sub is a subset of slice set, i.e. all elements from sub exist in set 186 func subSet[T comparable](sub, set []T) bool { 187 for _, v1 := range sub { 188 found := false 189 for _, v2 := range set { 190 found = v1 == v2 191 if found { 192 break 193 } 194 } 195 if !found { 196 return false 197 } 198 } 199 return true 200 } 201 202 // Returns is set1 and set2 overlaps, i.e. set1 is subset of set2 or set2 is subset of set1 203 func overlaps[T comparable](set1, set2 []T) bool { 204 return subSet(set1, set2) || subSet(set2, set1) 205 }