github.com/mithrandie/csvq@v1.18.1/lib/query/header_test.go (about) 1 package query 2 3 import ( 4 "reflect" 5 "testing" 6 7 "github.com/mithrandie/csvq/lib/parser" 8 "github.com/mithrandie/csvq/lib/value" 9 ) 10 11 func TestHeader_TableColumns(t *testing.T) { 12 h := Header{ 13 { 14 View: "t1", 15 Column: "c1", 16 Aliases: []string{"a1"}, 17 IsFromTable: true, 18 }, 19 { 20 View: "t1", 21 Column: "c2", 22 Aliases: []string{"a3"}, 23 IsFromTable: false, 24 }, 25 { 26 Column: "c3", 27 IsFromTable: true, 28 }, 29 } 30 expect := []parser.QueryExpression{ 31 parser.FieldReference{View: parser.Identifier{Literal: "t1"}, Column: parser.Identifier{Literal: "c1"}}, 32 parser.FieldReference{Column: parser.Identifier{Literal: "c3"}}, 33 } 34 35 result := h.TableColumns() 36 if !reflect.DeepEqual(result, expect) { 37 t.Errorf("columns = %s, want %s for %#v", result, expect, h) 38 } 39 } 40 41 func TestHeader_TableColumnNames(t *testing.T) { 42 h := Header{ 43 { 44 View: "t1", 45 Column: "c1", 46 Aliases: []string{"a1"}, 47 IsFromTable: true, 48 }, 49 { 50 View: "t1", 51 Column: "c2", 52 Aliases: []string{"a3"}, 53 IsFromTable: false, 54 }, 55 { 56 Column: "c3", 57 IsFromTable: true, 58 }, 59 } 60 expect := []string{ 61 "c1", 62 "c3", 63 } 64 65 result := h.TableColumnNames() 66 if !reflect.DeepEqual(result, expect) { 67 t.Errorf("column names = %s, want %s for %#v", result, expect, h) 68 } 69 } 70 71 var headerContainsObjectTests = []struct { 72 Expr parser.QueryExpression 73 Result int 74 Ok bool 75 }{ 76 { 77 Expr: parser.AggregateFunction{ 78 Name: "count", 79 Args: []parser.QueryExpression{ 80 parser.AllColumns{}, 81 }, 82 }, 83 Result: 5, 84 Ok: true, 85 }, 86 { 87 Expr: parser.FieldReference{ 88 View: parser.Identifier{Literal: "t2"}, 89 Column: parser.Identifier{Literal: "c1"}, 90 }, 91 Result: 4, 92 Ok: true, 93 }, 94 { 95 Expr: parser.ColumnNumber{ 96 View: parser.Identifier{Literal: "t1"}, 97 Number: value.NewInteger(2), 98 }, 99 Result: 1, 100 Ok: true, 101 }, 102 { 103 Expr: parser.NewIntegerValueFromString("1"), 104 Result: 6, 105 Ok: true, 106 }, 107 { 108 Expr: parser.NewStringValue("1"), 109 Result: -1, 110 Ok: false, 111 }, 112 { 113 Expr: parser.NewIntegerValueFromString("2"), 114 Result: -1, 115 Ok: false, 116 }, 117 { 118 Expr: parser.ColumnNumber{ 119 View: parser.Identifier{Literal: "t1"}, 120 Number: value.NewInteger(999), 121 }, 122 Result: -1, 123 Ok: false, 124 }, 125 } 126 127 func TestHeader_ContainsObject(t *testing.T) { 128 h := Header{ 129 { 130 View: "t1", 131 Column: "c1", 132 Aliases: []string{"a1"}, 133 Number: 1, 134 IsFromTable: true, 135 }, 136 { 137 View: "t1", 138 Column: "c2", 139 Aliases: []string{"a2"}, 140 Number: 2, 141 IsFromTable: true, 142 }, 143 { 144 View: "t1", 145 Column: "count(*)", 146 Number: 3, 147 IsFromTable: true, 148 }, 149 { 150 Column: "c3", 151 IsFromTable: false, 152 }, 153 { 154 View: "t2", 155 Column: "c1", 156 Aliases: []string{"a3"}, 157 Number: 1, 158 IsFromTable: true, 159 }, 160 { 161 Identifier: "COUNT(*)", 162 Column: "count(*)", 163 IsFromTable: false, 164 }, 165 { 166 Identifier: "@__PT:I:1", 167 Column: "1", 168 IsFromTable: false, 169 }, 170 { 171 Identifier: "@__PT:I:1", 172 Column: "1", 173 IsFromTable: false, 174 }, 175 } 176 177 for _, v := range headerContainsObjectTests { 178 result, ok := h.ContainsObject(v.Expr) 179 if ok != v.Ok { 180 t.Errorf("%s: contains flag = %t, want %t", v.Expr.String(), ok, v.Ok) 181 continue 182 } 183 if result != v.Result { 184 t.Errorf("%s: index = %d, want %d", v.Expr.String(), result, v.Result) 185 } 186 } 187 188 dual := NewDualView() 189 expr := parser.NewStringValue("") 190 191 result, ok := dual.Header.ContainsObject(expr) 192 if ok != false { 193 t.Errorf("%s: contains flag = %t, want %t", "<empty string>", ok, false) 194 } 195 if result != -1 { 196 t.Errorf("%s: index = %d, want %d", "<empty string>", result, -1) 197 } 198 } 199 200 var headerFieldNumberIndexTests = []struct { 201 Number parser.ColumnNumber 202 Result int 203 Error string 204 }{ 205 { 206 Number: parser.ColumnNumber{ 207 View: parser.Identifier{Literal: "t1"}, 208 Number: value.NewInteger(2), 209 }, 210 Result: 1, 211 }, 212 { 213 Number: parser.ColumnNumber{ 214 View: parser.Identifier{Literal: "t1"}, 215 Number: value.NewInteger(0), 216 }, 217 Error: "field not exists", 218 }, 219 { 220 Number: parser.ColumnNumber{ 221 View: parser.Identifier{Literal: "t1"}, 222 Number: value.NewInteger(9), 223 }, 224 Error: "field not exists", 225 }, 226 } 227 228 func TestHeader_FieldNumberIndex(t *testing.T) { 229 h := Header{ 230 { 231 View: "t1", 232 Column: "c1", 233 Aliases: []string{"a1"}, 234 Number: 1, 235 IsFromTable: true, 236 }, 237 { 238 View: "t1", 239 Column: "c2", 240 Aliases: []string{"a2"}, 241 Number: 2, 242 IsFromTable: true, 243 }, 244 { 245 Column: "c3", 246 IsFromTable: false, 247 }, 248 { 249 View: "t2", 250 Column: "c1", 251 Aliases: []string{"a3"}, 252 Number: 1, 253 IsFromTable: true, 254 }, 255 } 256 257 for _, v := range headerFieldNumberIndexTests { 258 result, err := h.FieldNumberIndex(v.Number) 259 if err != nil { 260 if len(v.Error) < 1 { 261 t.Errorf("%s: unexpected error %q", v.Number.String(), err) 262 } else if err.Error() != v.Error { 263 t.Errorf("%s: error %q, want error %q", v.Number.String(), err, v.Error) 264 } 265 continue 266 } 267 if 0 < len(v.Error) { 268 t.Errorf("%s: no error, want error %q", v.Number.String(), v.Error) 269 continue 270 } 271 if result != v.Result { 272 t.Errorf("%s: index = %d, want %d", v.Number.String(), result, v.Result) 273 } 274 } 275 } 276 277 var headerFieldIndexTests = []struct { 278 Ref parser.FieldReference 279 Result int 280 Error string 281 }{ 282 { 283 Ref: parser.FieldReference{ 284 View: parser.Identifier{Literal: "t2"}, 285 Column: parser.Identifier{Literal: "c1"}, 286 }, 287 Result: 3, 288 }, 289 { 290 Ref: parser.FieldReference{ 291 Column: parser.Identifier{Literal: "a2"}, 292 }, 293 Result: 1, 294 }, 295 { 296 Ref: parser.FieldReference{ 297 Column: parser.Identifier{Literal: "c2"}, 298 }, 299 Result: 1, 300 }, 301 { 302 Ref: parser.FieldReference{ 303 Column: parser.Identifier{Literal: "c4"}, 304 }, 305 Result: 5, 306 }, 307 { 308 Ref: parser.FieldReference{ 309 Column: parser.Identifier{Literal: " c4 "}, 310 }, 311 Result: 5, 312 }, 313 { 314 Ref: parser.FieldReference{ 315 Column: parser.Identifier{Literal: "c5"}, 316 }, 317 Result: 6, 318 }, 319 { 320 Ref: parser.FieldReference{ 321 Column: parser.Identifier{Literal: "c1"}, 322 }, 323 Error: "field ambiguous", 324 }, 325 { 326 Ref: parser.FieldReference{ 327 Column: parser.Identifier{Literal: "d1"}, 328 }, 329 Error: "field not exists", 330 }, 331 } 332 333 func TestHeader_FieldIndex(t *testing.T) { 334 h := Header{ 335 { 336 View: "t1", 337 Column: "c1", 338 Aliases: []string{"a1"}, 339 IsFromTable: true, 340 }, 341 { 342 View: "t1", 343 Column: "c2", 344 Aliases: []string{"a2"}, 345 IsFromTable: false, 346 }, 347 { 348 Column: "c3", 349 IsFromTable: true, 350 }, 351 { 352 View: "t2", 353 Column: "c1", 354 Aliases: []string{"a3"}, 355 IsFromTable: true, 356 }, 357 { 358 View: "t3", 359 Column: "c4", 360 IsFromTable: true, 361 }, 362 { 363 Column: "c4", 364 IsFromTable: true, 365 IsJoinColumn: true, 366 }, 367 { 368 View: "t4", 369 Column: " c5 ", 370 IsFromTable: true, 371 }, 372 } 373 374 for _, v := range headerFieldIndexTests { 375 result, err := h.FieldIndex(v.Ref) 376 if err != nil { 377 if len(v.Error) < 1 { 378 t.Errorf("%s: unexpected error %q", v.Ref.String(), err) 379 } else if err.Error() != v.Error { 380 t.Errorf("%s: error %q, want error %q", v.Ref.String(), err, v.Error) 381 } 382 continue 383 } 384 if 0 < len(v.Error) { 385 t.Errorf("%s: no error, want error %q", v.Ref.String(), v.Error) 386 continue 387 } 388 if result != v.Result { 389 t.Errorf("%s: index = %d, want %d", v.Ref.String(), result, v.Result) 390 } 391 } 392 } 393 394 func TestNewHeader(t *testing.T) { 395 ref := "table1" 396 words := []string{"column1", "column2"} 397 var expect Header = []HeaderField{ 398 { 399 View: "table1", 400 Column: InternalIdColumn, 401 }, 402 { 403 View: "table1", 404 Column: "column1", 405 Number: 1, 406 IsFromTable: true, 407 }, 408 { 409 View: "table1", 410 Column: "column2", 411 Number: 2, 412 IsFromTable: true, 413 }, 414 } 415 if !reflect.DeepEqual(NewHeaderWithId(ref, words), expect) { 416 t.Errorf("header = %v, want %v", NewHeaderWithId(ref, words), expect) 417 } 418 } 419 420 func TestNewHeaderWithoutId(t *testing.T) { 421 ref := "table1" 422 words := []string{"column1", "column2"} 423 var expect Header = []HeaderField{ 424 { 425 View: "table1", 426 Column: "column1", 427 Number: 1, 428 IsFromTable: true, 429 }, 430 { 431 View: "table1", 432 Column: "column2", 433 Number: 2, 434 IsFromTable: true, 435 }, 436 } 437 if !reflect.DeepEqual(NewHeader(ref, words), expect) { 438 t.Errorf("header = %v, want %v", NewHeader(ref, words), expect) 439 } 440 } 441 442 var headerUpdateTests = []struct { 443 Name string 444 Header Header 445 Reference string 446 Fields []parser.QueryExpression 447 Result Header 448 Error string 449 }{ 450 { 451 Name: "Header Update", 452 Header: []HeaderField{ 453 { 454 View: "table1", 455 Column: "column1", 456 Aliases: []string{"alias1"}, 457 }, 458 { 459 View: "table1", 460 Column: "column2", 461 Aliases: []string{"alias2"}, 462 }, 463 { 464 View: "table2", 465 Column: "column3", 466 }, 467 }, 468 Reference: "ref1", 469 Fields: []parser.QueryExpression{ 470 parser.Identifier{Literal: "c1"}, 471 parser.Identifier{Literal: "c2"}, 472 parser.Identifier{Literal: "c3"}, 473 }, 474 Result: []HeaderField{ 475 { 476 View: "ref1", 477 Column: "c1", 478 }, 479 { 480 View: "ref1", 481 Column: "c2", 482 }, 483 { 484 View: "ref1", 485 Column: "c3", 486 }, 487 }, 488 }, 489 { 490 Name: "Header Update Without Fields", 491 Header: []HeaderField{ 492 { 493 View: "table1", 494 Column: "column1", 495 Aliases: []string{"alias1"}, 496 }, 497 { 498 View: "table1", 499 Column: "column2", 500 Aliases: []string{"alias2"}, 501 }, 502 { 503 View: "table2", 504 Column: "column3", 505 }, 506 }, 507 Reference: "ref1", 508 Result: []HeaderField{ 509 { 510 View: "ref1", 511 Column: "column1", 512 }, 513 { 514 View: "ref1", 515 Column: "column2", 516 }, 517 { 518 View: "ref1", 519 Column: "column3", 520 }, 521 }, 522 }, 523 { 524 Name: "Header Update Field Length Error", 525 Header: []HeaderField{ 526 { 527 View: "table1", 528 Column: "column1", 529 Aliases: []string{"alias1"}, 530 }, 531 { 532 View: "table1", 533 Column: "column2", 534 Aliases: []string{"alias2"}, 535 }, 536 { 537 View: "table2", 538 Column: "column3", 539 }, 540 }, 541 Reference: "ref1", 542 Fields: []parser.QueryExpression{ 543 parser.Identifier{Literal: "c1"}, 544 parser.Identifier{Literal: "c2"}, 545 }, 546 Error: "field length does not match", 547 }, 548 { 549 Name: "Header Update Field Name Duplicate Error", 550 Header: []HeaderField{ 551 { 552 View: "table1", 553 Column: "column1", 554 Aliases: []string{"alias1"}, 555 }, 556 { 557 View: "table1", 558 Column: "column2", 559 Aliases: []string{"alias2"}, 560 }, 561 { 562 View: "table2", 563 Column: "column3", 564 }, 565 }, 566 Reference: "ref1", 567 Fields: []parser.QueryExpression{ 568 parser.Identifier{Literal: "c1"}, 569 parser.Identifier{Literal: "c2"}, 570 parser.Identifier{Literal: "c2"}, 571 }, 572 Error: "field name c2 is a duplicate", 573 }, 574 } 575 576 func TestHeader_Update(t *testing.T) { 577 for _, v := range headerUpdateTests { 578 err := v.Header.Update(v.Reference, v.Fields) 579 if err != nil { 580 if len(v.Error) < 1 { 581 t.Errorf("%s: unexpected error %q", v.Name, err) 582 } else if err.Error() != v.Error { 583 t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error) 584 } 585 continue 586 } 587 if 0 < len(v.Error) { 588 t.Errorf("%s: no error, want error %q", v.Name, v.Error) 589 continue 590 } 591 if !reflect.DeepEqual(v.Header, v.Result) { 592 t.Errorf("%s: header = %v, want %v", v.Name, v.Header, v.Result) 593 } 594 } 595 }