github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/appdef/impl_view_test.go (about) 1 /* 2 * Copyright (c) 2021-present Sigma-Soft, Ltd. 3 * @author: Nikolay Nikitin 4 */ 5 6 package appdef 7 8 import ( 9 "regexp" 10 "testing" 11 12 "github.com/stretchr/testify/require" 13 ) 14 15 func TestAddView(t *testing.T) { 16 require := require.New(t) 17 18 adb := New() 19 adb.AddPackage("test", "test.com/test") 20 21 numName := NewQName("test", "natural") 22 _ = adb.AddData(numName, DataKind_int64, NullQName, MinExcl(0)) 23 24 digsData := NewQName("test", "digs") 25 _ = adb.AddData(digsData, DataKind_string, NullQName, Pattern(`^\d+$`, "only digits allowed")) 26 27 docName := NewQName("test", "doc") 28 _ = adb.AddCDoc(docName) 29 30 kbName := NewQName("test", "KB") 31 _ = adb.AddData(kbName, DataKind_bytes, NullQName, MinLen(1), MaxLen(1024, "up to 1 KB")) 32 33 viewName := NewQName("test", "view") 34 vb := adb.AddView(viewName) 35 36 t.Run("must be ok to build view", func(t *testing.T) { 37 38 vb.SetComment("test view") 39 40 t.Run("must be ok to add partition key fields", func(t *testing.T) { 41 vb.Key().PartKey().AddDataField("pkF1", numName) 42 vb.Key().PartKey().AddField("pkF2", DataKind_bool) 43 44 t.Run("panic if field already exists in view", func(t *testing.T) { 45 require.Panics(func() { 46 vb.Key().PartKey().AddField("pkF1", DataKind_int64) 47 }) 48 }) 49 50 t.Run("panic if variable length field added to pk", func(t *testing.T) { 51 require.Panics(func() { 52 vb.Key().PartKey().AddField("pkF3", DataKind_string) 53 }) 54 require.Panics(func() { 55 vb.Key().PartKey().AddDataField("pkF3", digsData) 56 }) 57 }) 58 59 t.Run("panic if unknown data type field added to pk", func(t *testing.T) { 60 require.Panics(func() { 61 vb.Key().PartKey().AddDataField("pkF3", NewQName("test", "unknown")) 62 }) 63 }) 64 }) 65 66 t.Run("must be ok to add clustering columns fields", func(t *testing.T) { 67 vb.Key().ClustCols().AddField("ccF1", DataKind_int64) 68 vb.Key().ClustCols().AddRefField("ccF2", docName) 69 70 t.Run("panic if field already exists in view", func(t *testing.T) { 71 require.Panics(func() { 72 vb.Key().ClustCols().AddField("ccF1", DataKind_int64) 73 }) 74 }) 75 76 t.Run("panic if unknown data type field added to cc", func(t *testing.T) { 77 require.Panics(func() { 78 vb.Key().ClustCols().AddDataField("ccF3", NewQName("test", "unknown")) 79 }) 80 }) 81 }) 82 83 t.Run("must be ok to add value fields", func(t *testing.T) { 84 vb.Value(). 85 AddField("valF1", DataKind_bool, true). 86 AddDataField("valF2", digsData, false, MaxLen(100)).SetFieldComment("valF2", "up to 100 digits") 87 }) 88 }) 89 90 app, err := adb.Build() 91 require.NoError(err) 92 view := app.View(viewName) 93 94 t.Run("must be ok to read view", func(t *testing.T) { 95 require.Equal("test view", view.Comment()) 96 require.Equal(viewName, view.QName()) 97 require.Equal(TypeKind_ViewRecord, view.Kind()) 98 99 checkValueValF2 := func(f IField) { 100 require.Equal("valF2", f.Name()) 101 require.False(f.Required()) 102 cnt := 0 103 for k, c := range f.Constraints() { 104 cnt++ 105 switch k { 106 case ConstraintKind_MaxLen: 107 require.EqualValues(100, c.Value()) 108 case ConstraintKind_Pattern: 109 require.EqualValues(`^\d+$`, c.Value().(*regexp.Regexp).String()) 110 require.Equal("only digits allowed", c.Comment()) 111 default: 112 require.Fail("unexpected constraint", "constraint: %v", c) 113 } 114 } 115 require.Equal("up to 100 digits", f.Comment()) 116 } 117 118 require.Equal(7, view.FieldCount()) 119 cnt := 0 120 for _, f := range view.Fields() { 121 cnt++ 122 switch cnt { 123 case 1: 124 require.Equal(SystemField_QName, f.Name()) 125 require.True(f.IsSys()) 126 case 2: 127 require.Equal("pkF1", f.Name()) 128 require.Equal(numName, f.Data().QName()) 129 require.True(f.Required()) 130 case 3: 131 require.Equal("pkF2", f.Name()) 132 require.True(f.Required()) 133 case 4: 134 require.Equal("ccF1", f.Name()) 135 require.False(f.Required()) 136 case 5: 137 require.Equal("ccF2", f.Name()) 138 require.False(f.Required()) 139 case 6: 140 require.Equal("valF1", f.Name()) 141 require.True(f.Required()) 142 case 7: 143 checkValueValF2(f) 144 default: 145 require.Fail("unexpected field «%s»", f.Name()) 146 } 147 } 148 require.Equal(view.FieldCount(), cnt) 149 150 t.Run("must be ok to read view full key", func(t *testing.T) { 151 key := view.Key() 152 require.Equal(4, key.FieldCount()) 153 cnt := 0 154 for _, f := range key.Fields() { 155 cnt++ 156 switch cnt { 157 case 1: 158 require.Equal("pkF1", f.Name()) 159 require.Equal(numName, f.Data().QName()) 160 require.True(f.Required()) 161 case 2: 162 require.Equal("pkF2", f.Name()) 163 require.True(f.Required()) 164 case 3: 165 require.Equal("ccF1", f.Name()) 166 require.False(f.Required()) 167 case 4: 168 require.Equal("ccF2", f.Name()) 169 require.False(f.Required()) 170 default: 171 require.Fail("unexpected field «%s»", f.Name()) 172 } 173 } 174 require.Equal(key.FieldCount(), cnt) 175 }) 176 177 t.Run("must be ok to read view partition key", func(t *testing.T) { 178 pk := view.Key().PartKey() 179 require.Equal(2, pk.FieldCount()) 180 cnt := 0 181 for _, f := range pk.Fields() { 182 cnt++ 183 switch cnt { 184 case 1: 185 require.Equal("pkF1", f.Name()) 186 require.Equal(numName, f.Data().QName()) 187 require.True(f.Required()) 188 case 2: 189 require.Equal("pkF2", f.Name()) 190 require.True(f.Required()) 191 default: 192 require.Fail("unexpected field «%s»", f.Name()) 193 } 194 } 195 require.Equal(pk.FieldCount(), cnt) 196 require.NotPanics(func() { pk.isPartKey() }) 197 }) 198 199 t.Run("must be ok to read view clustering columns", func(t *testing.T) { 200 cc := view.Key().ClustCols() 201 require.Equal(2, cc.FieldCount()) 202 cnt := 0 203 for _, f := range cc.Fields() { 204 cnt++ 205 switch cnt { 206 case 1: 207 require.Equal("ccF1", f.Name()) 208 require.False(f.Required()) 209 case 2: 210 require.Equal("ccF2", f.Name()) 211 require.False(f.Required()) 212 default: 213 require.Fail("unexpected field «%s»", f.Name()) 214 } 215 } 216 require.Equal(cc.FieldCount(), cnt) 217 require.NotPanics(func() { cc.isClustCols() }) 218 }) 219 220 t.Run("must be ok to read view value", func(t *testing.T) { 221 val := view.Value() 222 require.Equal(3, val.FieldCount()) 223 cnt := 0 224 for _, f := range val.Fields() { 225 cnt++ 226 switch cnt { 227 case 1: 228 require.Equal(SystemField_QName, f.Name()) 229 require.True(f.IsSys()) 230 case 2: 231 require.Equal("valF1", f.Name()) 232 require.True(f.Required()) 233 case 3: 234 checkValueValF2(f) 235 default: 236 require.Fail("unexpected field «%s»", f.Name()) 237 } 238 } 239 require.Equal(val.FieldCount(), cnt) 240 require.NotPanics(func() { val.isViewValue() }) 241 }) 242 243 t.Run("must be ok to cast Type() as IView", func(t *testing.T) { 244 typ := app.Type(viewName) 245 require.NotNil(typ) 246 require.Equal(TypeKind_ViewRecord, typ.Kind()) 247 248 v, ok := typ.(IView) 249 require.True(ok) 250 require.Equal(v, view) 251 }) 252 253 require.Nil(app.View(NewQName("test", "unknown")), "find unknown view must return nil") 254 255 t.Run("must be nil if not view", func(t *testing.T) { 256 require.Nil(app.View(docName)) 257 258 typ := app.Type(docName) 259 require.NotNil(typ) 260 v, ok := typ.(IView) 261 require.False(ok) 262 require.Nil(v) 263 }) 264 }) 265 266 t.Run("must be ok to add fields to view after app build", func(t *testing.T) { 267 vb.Key().PartKey(). 268 AddRefField("pkF3", docName). 269 SetFieldComment("pkF3", "test comment") 270 271 vb.Key().ClustCols(). 272 AddDataField("ccF3", kbName).SetFieldComment("ccF3", "one KB") 273 274 t.Run("panic if add second variable length field", func(t *testing.T) { 275 require.Panics(func() { 276 vb.Key().ClustCols().AddField("ccF3_1", DataKind_bytes) 277 }) 278 require.Panics(func() { 279 vb.Key().ClustCols().AddDataField("ccF3_1", kbName) 280 }) 281 }) 282 283 vb.Value(). 284 AddRefField("valF3", false, docName). 285 AddField("valF4", DataKind_bytes, false, MaxLen(1024)).SetFieldComment("valF4", "test comment"). 286 AddField("valF5", DataKind_bool, false).SetFieldVerify("valF5", VerificationKind_EMail) 287 288 _, err := adb.Build() 289 require.NoError(err) 290 291 require.Equal(3, view.Key().PartKey().FieldCount()) 292 require.Equal(3, view.Key().ClustCols().FieldCount()) 293 require.Equal(6, view.Key().FieldCount()) 294 295 require.Equal(view.Key().FieldCount()+view.Value().FieldCount(), view.FieldCount()) 296 297 require.Equal("test comment", view.Key().Field("pkF3").Comment()) 298 require.Equal("one KB", view.Key().Field("ccF3").Comment()) 299 300 require.Equal(5, view.Value().UserFieldCount()) 301 302 cnt := 0 303 for _, f := range view.Value().Fields() { 304 cnt++ 305 switch f.Name() { 306 case SystemField_QName: 307 require.Equal(DataKind_QName, f.DataKind()) 308 require.True(f.IsSys()) 309 case "valF1": 310 require.Equal(DataKind_bool, f.DataKind()) 311 require.True(f.Required()) 312 case "valF2": 313 require.Equal(DataKind_string, f.DataKind()) 314 require.False(f.Required()) 315 // valF2 constraints checked above 316 case "valF3": 317 require.Equal(DataKind_RecordID, f.DataKind()) 318 require.False(f.Required()) 319 require.EqualValues(QNames{docName}, f.(IRefField).Refs()) 320 case "valF4": 321 require.Equal(DataKind_bytes, f.DataKind()) 322 require.False(f.Required()) 323 require.Equal("test comment", f.Comment()) 324 cnt := 0 325 for _, c := range f.Constraints() { 326 cnt++ 327 switch cnt { 328 case 1: 329 require.Equal(ConstraintKind_MaxLen, c.Kind()) 330 require.EqualValues(1024, c.Value()) 331 default: 332 require.Fail("unexpected constraint", "constraint: %v", c) 333 } 334 } 335 require.EqualValues(1, cnt) 336 case "valF5": 337 require.Equal(DataKind_bool, f.DataKind()) 338 require.False(f.Required()) 339 require.True(f.Verifiable()) 340 require.True(f.VerificationKind(VerificationKind_EMail)) 341 require.False(f.VerificationKind(VerificationKind_Phone)) 342 default: 343 require.Fail("unexpected value field", "field name: %s", f.Name()) 344 } 345 } 346 require.Equal(view.Value().UserFieldCount()+1, cnt) 347 }) 348 } 349 350 func TestViewValidate(t *testing.T) { 351 require := require.New(t) 352 353 viewName := NewQName("test", "view") 354 355 adb := New() 356 adb.AddPackage("test", "test.com/test") 357 358 v := adb.AddView(viewName) 359 require.NotNil(v) 360 361 t.Run("must be error if no pkey fields", func(t *testing.T) { 362 _, err := adb.Build() 363 require.ErrorIs(err, ErrMissedError) 364 }) 365 366 v.Key().PartKey().AddField("pk1", DataKind_bool) 367 368 t.Run("must be error if no ccols fields", func(t *testing.T) { 369 _, err := adb.Build() 370 require.ErrorIs(err, ErrMissedError) 371 }) 372 373 v.Key().ClustCols().AddField("cc1", DataKind_string, MaxLen(100)) 374 _, err := adb.Build() 375 require.NoError(err) 376 }