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  }