github.com/mithrandie/csvq@v1.18.1/lib/query/inline_tables_test.go (about)

     1  package query
     2  
     3  import (
     4  	"context"
     5  	"reflect"
     6  	"testing"
     7  
     8  	"github.com/mithrandie/csvq/lib/parser"
     9  	"github.com/mithrandie/csvq/lib/value"
    10  )
    11  
    12  var inlineTableMapSetTests = []struct {
    13  	Name   string
    14  	Expr   parser.InlineTable
    15  	Result InlineTableMap
    16  	Error  string
    17  }{
    18  	{
    19  		Name: "InlineTableMap Set",
    20  		Expr: parser.InlineTable{
    21  			Name: parser.Identifier{Literal: "it"},
    22  			Fields: []parser.QueryExpression{
    23  				parser.Identifier{Literal: "c1"},
    24  				parser.Identifier{Literal: "c2"},
    25  				parser.Identifier{Literal: "num"},
    26  			},
    27  			Query: parser.SelectQuery{
    28  				SelectEntity: parser.SelectEntity{
    29  					SelectClause: parser.SelectClause{
    30  						Fields: []parser.QueryExpression{
    31  							parser.Field{Object: parser.FieldReference{Column: parser.Identifier{Literal: "column1"}}},
    32  							parser.Field{Object: parser.FieldReference{Column: parser.Identifier{Literal: "column2"}}},
    33  							parser.Field{Object: parser.NewIntegerValueFromString("1")},
    34  						},
    35  					},
    36  					FromClause: parser.FromClause{
    37  						Tables: []parser.QueryExpression{
    38  							parser.Table{Object: parser.Identifier{Literal: "table1"}},
    39  						},
    40  					},
    41  				},
    42  			},
    43  		},
    44  		Result: InlineTableMap{
    45  			"IT": &View{
    46  				Header: NewHeader("it", []string{"c1", "c2", "num"}),
    47  				RecordSet: []Record{
    48  					NewRecord([]value.Primary{
    49  						value.NewString("1"),
    50  						value.NewString("str1"),
    51  						value.NewInteger(1),
    52  					}),
    53  					NewRecord([]value.Primary{
    54  						value.NewString("2"),
    55  						value.NewString("str2"),
    56  						value.NewInteger(1),
    57  					}),
    58  					NewRecord([]value.Primary{
    59  						value.NewString("3"),
    60  						value.NewString("str3"),
    61  						value.NewInteger(1),
    62  					}),
    63  				},
    64  			},
    65  		},
    66  	},
    67  	{
    68  		Name: "InlineTableMap Set Recursive Table",
    69  		Expr: parser.InlineTable{
    70  			Recursive: parser.Token{Token: parser.RECURSIVE, Literal: "recursive"},
    71  			Name:      parser.Identifier{Literal: "it_recursive"},
    72  			Fields: []parser.QueryExpression{
    73  				parser.Identifier{Literal: "n"},
    74  			},
    75  			Query: parser.SelectQuery{
    76  				SelectEntity: parser.SelectSet{
    77  					LHS: parser.SelectEntity{
    78  						SelectClause: parser.SelectClause{
    79  							Fields: []parser.QueryExpression{
    80  								parser.Field{Object: parser.NewIntegerValueFromString("1")},
    81  							},
    82  						},
    83  					},
    84  					Operator: parser.Token{Token: parser.UNION, Literal: "union"},
    85  					RHS: parser.SelectEntity{
    86  						SelectClause: parser.SelectClause{
    87  							Fields: []parser.QueryExpression{
    88  								parser.Field{
    89  									Object: parser.Arithmetic{
    90  										LHS:      parser.FieldReference{Column: parser.Identifier{Literal: "n"}},
    91  										RHS:      parser.NewIntegerValueFromString("1"),
    92  										Operator: parser.Token{Token: '+', Literal: "+"},
    93  									},
    94  								},
    95  							},
    96  						},
    97  						FromClause: parser.FromClause{
    98  							Tables: []parser.QueryExpression{
    99  								parser.Table{Object: parser.Identifier{Literal: "it_recursive"}},
   100  							},
   101  						},
   102  						WhereClause: parser.WhereClause{
   103  							Filter: parser.Comparison{
   104  								LHS:      parser.FieldReference{Column: parser.Identifier{Literal: "n"}},
   105  								RHS:      parser.NewIntegerValueFromString("3"),
   106  								Operator: parser.Token{Token: '<', Literal: "<"},
   107  							},
   108  						},
   109  					},
   110  				},
   111  			},
   112  		},
   113  		Result: InlineTableMap{
   114  			"IT": &View{
   115  				Header: NewHeader("it", []string{"c1", "c2", "num"}),
   116  				RecordSet: []Record{
   117  					NewRecord([]value.Primary{
   118  						value.NewString("1"),
   119  						value.NewString("str1"),
   120  						value.NewInteger(1),
   121  					}),
   122  					NewRecord([]value.Primary{
   123  						value.NewString("2"),
   124  						value.NewString("str2"),
   125  						value.NewInteger(1),
   126  					}),
   127  					NewRecord([]value.Primary{
   128  						value.NewString("3"),
   129  						value.NewString("str3"),
   130  						value.NewInteger(1),
   131  					}),
   132  				},
   133  			},
   134  			"IT_RECURSIVE": &View{
   135  				Header: []HeaderField{
   136  					{
   137  						View:        "it_recursive",
   138  						Column:      "n",
   139  						Number:      1,
   140  						IsFromTable: true,
   141  					},
   142  				},
   143  				RecordSet: []Record{
   144  					NewRecord([]value.Primary{
   145  						value.NewInteger(1),
   146  					}),
   147  					NewRecord([]value.Primary{
   148  						value.NewInteger(2),
   149  					}),
   150  					NewRecord([]value.Primary{
   151  						value.NewInteger(3),
   152  					}),
   153  				},
   154  			},
   155  		},
   156  	},
   157  	{
   158  		Name: "InlineTableMap Set Redefined Error",
   159  		Expr: parser.InlineTable{
   160  			Name: parser.Identifier{Literal: "it"},
   161  			Fields: []parser.QueryExpression{
   162  				parser.Identifier{Literal: "c1"},
   163  				parser.Identifier{Literal: "c2"},
   164  			},
   165  			Query: parser.SelectQuery{
   166  				SelectEntity: parser.SelectEntity{
   167  					SelectClause: parser.SelectClause{
   168  						Fields: []parser.QueryExpression{
   169  							parser.Field{Object: parser.FieldReference{Column: parser.Identifier{Literal: "column1"}}},
   170  							parser.Field{Object: parser.FieldReference{Column: parser.Identifier{Literal: "column2"}}},
   171  						},
   172  					},
   173  					FromClause: parser.FromClause{
   174  						Tables: []parser.QueryExpression{
   175  							parser.Table{Object: parser.Identifier{Literal: "table1"}},
   176  						},
   177  					},
   178  				},
   179  			},
   180  		},
   181  		Error: "inline table it is redefined",
   182  	},
   183  	{
   184  		Name: "InlineTableMap Set Query Error",
   185  		Expr: parser.InlineTable{
   186  			Name: parser.Identifier{Literal: "it2"},
   187  			Fields: []parser.QueryExpression{
   188  				parser.Identifier{Literal: "c1"},
   189  				parser.Identifier{Literal: "c2"},
   190  			},
   191  			Query: parser.SelectQuery{
   192  				SelectEntity: parser.SelectEntity{
   193  					SelectClause: parser.SelectClause{
   194  						Fields: []parser.QueryExpression{
   195  							parser.Field{Object: parser.FieldReference{Column: parser.Identifier{Literal: "column1"}}},
   196  							parser.Field{Object: parser.FieldReference{Column: parser.Identifier{Literal: "notexist"}}},
   197  						},
   198  					},
   199  					FromClause: parser.FromClause{
   200  						Tables: []parser.QueryExpression{
   201  							parser.Table{Object: parser.Identifier{Literal: "table1"}},
   202  						},
   203  					},
   204  				},
   205  			},
   206  		},
   207  		Error: "field notexist does not exist",
   208  	},
   209  	{
   210  		Name: "InlineTableMap Set Field Length Error",
   211  		Expr: parser.InlineTable{
   212  			Name: parser.Identifier{Literal: "it2"},
   213  			Fields: []parser.QueryExpression{
   214  				parser.Identifier{Literal: "c1"},
   215  			},
   216  			Query: parser.SelectQuery{
   217  				SelectEntity: parser.SelectEntity{
   218  					SelectClause: parser.SelectClause{
   219  						Fields: []parser.QueryExpression{
   220  							parser.Field{Object: parser.FieldReference{Column: parser.Identifier{Literal: "column1"}}},
   221  							parser.Field{Object: parser.FieldReference{Column: parser.Identifier{Literal: "column2"}}},
   222  						},
   223  					},
   224  					FromClause: parser.FromClause{
   225  						Tables: []parser.QueryExpression{
   226  							parser.Table{Object: parser.Identifier{Literal: "table1"}},
   227  						},
   228  					},
   229  				},
   230  			},
   231  		},
   232  		Error: "select query should return exactly 1 field for inline table it2",
   233  	},
   234  	{
   235  		Name: "InlineTableMap Set Duplicate Field Name Error",
   236  		Expr: parser.InlineTable{
   237  			Name: parser.Identifier{Literal: "it2"},
   238  			Fields: []parser.QueryExpression{
   239  				parser.Identifier{Literal: "c1"},
   240  				parser.Identifier{Literal: "c1"},
   241  			},
   242  			Query: parser.SelectQuery{
   243  				SelectEntity: parser.SelectEntity{
   244  					SelectClause: parser.SelectClause{
   245  						Fields: []parser.QueryExpression{
   246  							parser.Field{Object: parser.FieldReference{Column: parser.Identifier{Literal: "column1"}}},
   247  							parser.Field{Object: parser.FieldReference{Column: parser.Identifier{Literal: "column2"}}},
   248  						},
   249  					},
   250  					FromClause: parser.FromClause{
   251  						Tables: []parser.QueryExpression{
   252  							parser.Table{Object: parser.Identifier{Literal: "table1"}},
   253  						},
   254  					},
   255  				},
   256  			},
   257  		},
   258  		Error: "field name c1 is a duplicate",
   259  	},
   260  }
   261  
   262  func TestInlineTableMap_Set(t *testing.T) {
   263  	defer func() {
   264  		_ = TestTx.CachedViews.Clean(TestTx.FileContainer)
   265  		initFlag(TestTx.Flags)
   266  	}()
   267  
   268  	TestTx.Flags.Repository = TestDataDir
   269  
   270  	it := InlineTableMap{}
   271  
   272  	scope := NewReferenceScope(TestTx)
   273  	ctx := context.Background()
   274  	for _, v := range inlineTableMapSetTests {
   275  		_ = TestTx.CachedViews.Clean(TestTx.FileContainer)
   276  		err := it.Set(ctx, scope, v.Expr)
   277  		if err != nil {
   278  			if len(v.Error) < 1 {
   279  				t.Errorf("%s: unexpected error %q", v.Name, err)
   280  			} else if err.Error() != v.Error {
   281  				t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error)
   282  			}
   283  			continue
   284  		}
   285  		if 0 < len(v.Error) {
   286  			t.Errorf("%s: no error, want error %q", v.Name, v.Error)
   287  			continue
   288  		}
   289  		if !reflect.DeepEqual(it, v.Result) {
   290  			t.Errorf("%s: result = %v, want %v", v.Name, it, v.Result)
   291  		}
   292  	}
   293  
   294  	recursiveExpr := parser.InlineTable{
   295  		Recursive: parser.Token{Token: parser.RECURSIVE, Literal: "recursive"},
   296  		Name:      parser.Identifier{Literal: "nested_error"},
   297  		Fields: []parser.QueryExpression{
   298  			parser.Identifier{Literal: "n"},
   299  		},
   300  		Query: parser.SelectQuery{},
   301  	}
   302  	scope.RecursiveTable = &recursiveExpr
   303  	expectErr := "recursive queries are nested"
   304  	err := it.Set(ctx, scope, recursiveExpr)
   305  	if err == nil {
   306  		t.Errorf("no error, want error %q", expectErr)
   307  	} else if err.Error() != expectErr {
   308  		t.Errorf("error %q, want error %q", err.Error(), expectErr)
   309  	}
   310  }
   311  
   312  var inlineTableMapGetTests = []struct {
   313  	Name      string
   314  	TableName parser.Identifier
   315  	Result    *View
   316  	Error     string
   317  }{
   318  	{
   319  		Name:      "InlineTableMap Get",
   320  		TableName: parser.Identifier{Literal: "it"},
   321  		Result: &View{
   322  			Header: NewHeader("it", []string{"c1", "c2", "num"}),
   323  			RecordSet: []Record{
   324  				NewRecord([]value.Primary{
   325  					value.NewString("1"),
   326  					value.NewString("str1"),
   327  					value.NewInteger(1),
   328  				}),
   329  				NewRecord([]value.Primary{
   330  					value.NewString("2"),
   331  					value.NewString("str2"),
   332  					value.NewInteger(1),
   333  				}),
   334  				NewRecord([]value.Primary{
   335  					value.NewString("3"),
   336  					value.NewString("str3"),
   337  					value.NewInteger(1),
   338  				}),
   339  			},
   340  		},
   341  	},
   342  	{
   343  		Name:      "InlineTableMap Get Undefined Error",
   344  		TableName: parser.Identifier{Literal: "notexist"},
   345  		Error:     "inline table notexist is undefined",
   346  	},
   347  }
   348  
   349  func TestInlineTableMap_Get(t *testing.T) {
   350  	it := InlineTableMap{
   351  		"IT": &View{
   352  			Header: NewHeader("it", []string{"c1", "c2", "num"}),
   353  			RecordSet: []Record{
   354  				NewRecord([]value.Primary{
   355  					value.NewString("1"),
   356  					value.NewString("str1"),
   357  					value.NewInteger(1),
   358  				}),
   359  				NewRecord([]value.Primary{
   360  					value.NewString("2"),
   361  					value.NewString("str2"),
   362  					value.NewInteger(1),
   363  				}),
   364  				NewRecord([]value.Primary{
   365  					value.NewString("3"),
   366  					value.NewString("str3"),
   367  					value.NewInteger(1),
   368  				}),
   369  			},
   370  		},
   371  	}
   372  
   373  	for _, v := range inlineTableMapGetTests {
   374  		ret, err := it.Get(v.TableName)
   375  		if err != nil {
   376  			if len(v.Error) < 1 {
   377  				t.Errorf("%s: unexpected error %q", v.Name, err)
   378  			} else if err.Error() != v.Error {
   379  				t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error)
   380  			}
   381  			continue
   382  		}
   383  		if 0 < len(v.Error) {
   384  			t.Errorf("%s: no error, want error %q", v.Name, v.Error)
   385  			continue
   386  		}
   387  		if !reflect.DeepEqual(ret, v.Result) {
   388  			t.Errorf("%s: result = %v, want %v", v.Name, ret, v.Result)
   389  		}
   390  	}
   391  }