github.com/MontFerret/ferret@v0.18.0/pkg/compiler/compiler_filter_test.go (about)

     1  package compiler_test
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	. "github.com/smartystreets/goconvey/convey"
     8  
     9  	"github.com/MontFerret/ferret/pkg/compiler"
    10  	"github.com/MontFerret/ferret/pkg/runtime/core"
    11  	"github.com/MontFerret/ferret/pkg/runtime/values"
    12  )
    13  
    14  func TestForFilter(t *testing.T) {
    15  	Convey("Should compile query with FILTER i > 2", t, func() {
    16  		c := compiler.New()
    17  
    18  		p, err := c.Compile(`
    19  			FOR i IN [ 1, 2, 3, 4, 1, 3 ]
    20  				FILTER i > 2
    21  				RETURN i
    22  		`)
    23  
    24  		So(err, ShouldBeNil)
    25  
    26  		out, err := p.Run(context.Background())
    27  
    28  		So(err, ShouldBeNil)
    29  
    30  		So(string(out), ShouldEqual, `[3,4,3]`)
    31  	})
    32  
    33  	Convey("Should compile query with FILTER i > 1 AND i < 3", t, func() {
    34  		c := compiler.New()
    35  
    36  		p, err := c.Compile(`
    37  			FOR i IN [ 1, 2, 3, 4, 1, 3 ]
    38  				FILTER i > 1 AND i < 4
    39  				RETURN i
    40  		`)
    41  
    42  		So(err, ShouldBeNil)
    43  
    44  		out, err := p.Run(context.Background())
    45  
    46  		So(err, ShouldBeNil)
    47  
    48  		So(string(out), ShouldEqual, `[2,3,3]`)
    49  	})
    50  
    51  	Convey("Should compile query with a regexp FILTER statement", t, func() {
    52  		c := compiler.New()
    53  
    54  		p, err := c.Compile(`
    55  			LET users = [
    56  				{
    57  					age: 31,
    58  					gender: "m",
    59  					name: "Josh"
    60  				},
    61  				{
    62  					age: 29,
    63  					gender: "f",
    64  					name: "Mary"
    65  				},
    66  				{
    67  					age: 36,
    68  					gender: "m",
    69  					name: "Peter"
    70  				}
    71  			]
    72  			FOR u IN users
    73  				FILTER u.name =~ "r"
    74  				RETURN u
    75  		`)
    76  
    77  		So(err, ShouldBeNil)
    78  
    79  		out, err := p.Run(context.Background())
    80  
    81  		So(err, ShouldBeNil)
    82  
    83  		So(string(out), ShouldEqual, `[{"age":29,"gender":"f","name":"Mary"},{"age":36,"gender":"m","name":"Peter"}]`)
    84  	})
    85  
    86  	Convey("Should compile query with multiple FILTER statements", t, func() {
    87  		c := compiler.New()
    88  
    89  		p, err := c.Compile(`
    90  			LET users = [
    91  				{
    92  					active: true,
    93  					age: 31,
    94  					gender: "m"
    95  				},
    96  				{
    97  					active: true,
    98  					age: 29,
    99  					gender: "f"
   100  				},
   101  				{
   102  					active: true,
   103  					age: 36,
   104  					gender: "m"
   105  				}
   106  			]
   107  			FOR u IN users
   108  				FILTER u.active == true
   109  				FILTER u.age < 35
   110  				RETURN u
   111  		`)
   112  
   113  		So(err, ShouldBeNil)
   114  
   115  		out, err := p.Run(context.Background())
   116  
   117  		So(err, ShouldBeNil)
   118  
   119  		So(string(out), ShouldEqual, `[{"active":true,"age":31,"gender":"m"},{"active":true,"age":29,"gender":"f"}]`)
   120  	})
   121  
   122  	Convey("Should compile query with multiple FILTER statements", t, func() {
   123  		c := compiler.New()
   124  
   125  		p, err := c.Compile(`
   126  			LET users = [
   127  				{
   128  					active: true,
   129  					age: 31,
   130  					gender: "m"
   131  				},
   132  				{
   133  					active: true,
   134  					age: 29,
   135  					gender: "f"
   136  				},
   137  				{
   138  					active: true,
   139  					age: 36,
   140  					gender: "m"
   141  				},
   142  				{
   143  					active: false,
   144  					age: 69,
   145  					gender: "m"
   146  				}
   147  			]
   148  			FOR u IN users
   149  				FILTER u.active == true
   150  				LIMIT 2
   151  				FILTER u.gender == "m"
   152  				RETURN u
   153  		`)
   154  
   155  		So(err, ShouldBeNil)
   156  
   157  		out, err := p.Run(context.Background())
   158  
   159  		So(err, ShouldBeNil)
   160  
   161  		So(string(out), ShouldEqual, `[{"active":true,"age":31,"gender":"m"}]`)
   162  	})
   163  
   164  	Convey("Should compile query with left side expression", t, func() {
   165  		c := compiler.New()
   166  
   167  		p, err := c.Compile(`
   168  			LET users = [
   169  				{
   170  					active: true,
   171  					age: 31,
   172  					gender: "m"
   173  				},
   174  				{
   175  					active: true,
   176  					age: 29,
   177  					gender: "f"
   178  				},
   179  				{
   180  					active: true,
   181  					age: 36,
   182  					gender: "m"
   183  				},
   184  				{
   185  					active: false,
   186  					age: 69,
   187  					gender: "m"
   188  				}
   189  			]
   190  			FOR u IN users
   191  				FILTER u.active
   192  				RETURN u
   193  		`)
   194  
   195  		So(err, ShouldBeNil)
   196  
   197  		out, err := p.Run(context.Background())
   198  
   199  		So(err, ShouldBeNil)
   200  
   201  		So(string(out), ShouldEqual, `[{"active":true,"age":31,"gender":"m"},{"active":true,"age":29,"gender":"f"},{"active":true,"age":36,"gender":"m"}]`)
   202  	})
   203  
   204  	Convey("Should compile query with multiple left side expression", t, func() {
   205  		c := compiler.New()
   206  
   207  		p, err := c.Compile(`
   208  			LET users = [
   209  				{
   210  					active: true,
   211  					married: true,
   212  					age: 31,
   213  					gender: "m"
   214  				},
   215  				{
   216  					active: true,
   217  					married: false,
   218  					age: 25,
   219  					gender: "f"
   220  				},
   221  				{
   222  					active: true,
   223  					married: false,
   224  					age: 36,
   225  					gender: "m"
   226  				},
   227  				{
   228  					active: false,
   229  					married: true,
   230  					age: 69,
   231  					gender: "m"
   232  				},
   233  				{
   234  					active: true,
   235  					married: true,
   236  					age: 45,
   237  					gender: "f"
   238  				}
   239  			]
   240  			FOR u IN users
   241  				FILTER u.active AND u.married
   242  				RETURN u
   243  		`)
   244  
   245  		So(err, ShouldBeNil)
   246  
   247  		out, err := p.Run(context.Background())
   248  
   249  		So(err, ShouldBeNil)
   250  
   251  		So(string(out), ShouldEqual, `[{"active":true,"age":31,"gender":"m","married":true},{"active":true,"age":45,"gender":"f","married":true}]`)
   252  	})
   253  
   254  	Convey("Should compile query with multiple left side expression and with binary operator", t, func() {
   255  		c := compiler.New()
   256  
   257  		p, err := c.Compile(`
   258  			LET users = [
   259  				{
   260  					active: true,
   261  					married: true,
   262  					age: 31,
   263  					gender: "m"
   264  				},
   265  				{
   266  					active: true,
   267  					married: false,
   268  					age: 25,
   269  					gender: "f"
   270  				},
   271  				{
   272  					active: true,
   273  					married: false,
   274  					age: 36,
   275  					gender: "m"
   276  				},
   277  				{
   278  					active: false,
   279  					married: true,
   280  					age: 69,
   281  					gender: "m"
   282  				},
   283  				{
   284  					active: true,
   285  					married: true,
   286  					age: 45,
   287  					gender: "f"
   288  				}
   289  			]
   290  			FOR u IN users
   291  				FILTER !u.active AND u.married
   292  				RETURN u
   293  		`)
   294  
   295  		So(err, ShouldBeNil)
   296  
   297  		out, err := p.Run(context.Background())
   298  
   299  		So(err, ShouldBeNil)
   300  
   301  		So(string(out), ShouldEqual, `[{"active":false,"age":69,"gender":"m","married":true}]`)
   302  	})
   303  
   304  	Convey("Should compile query with multiple left side expression and with binary operator 2", t, func() {
   305  		c := compiler.New()
   306  
   307  		p, err := c.Compile(`
   308  			LET users = [
   309  				{
   310  					active: true,
   311  					married: true,
   312  					age: 31,
   313  					gender: "m"
   314  				},
   315  				{
   316  					active: true,
   317  					married: false,
   318  					age: 25,
   319  					gender: "f"
   320  				},
   321  				{
   322  					active: true,
   323  					married: false,
   324  					age: 36,
   325  					gender: "m"
   326  				},
   327  				{
   328  					active: false,
   329  					married: true,
   330  					age: 69,
   331  					gender: "m"
   332  				},
   333  				{
   334  					active: true,
   335  					married: true,
   336  					age: 45,
   337  					gender: "f"
   338  				}
   339  			]
   340  			FOR u IN users
   341  				FILTER !u.active AND !u.married
   342  				RETURN u
   343  		`)
   344  
   345  		So(err, ShouldBeNil)
   346  
   347  		out, err := p.Run(context.Background())
   348  
   349  		So(err, ShouldBeNil)
   350  
   351  		So(string(out), ShouldEqual, `[]`)
   352  	})
   353  
   354  	Convey("Should define variables", t, func() {
   355  		c := compiler.New()
   356  
   357  		p, err := c.Compile(`
   358  			FOR i IN [ 1, 2, 3, 4, 1, 3 ]
   359  				LET x = 2
   360  				FILTER i > x
   361  				RETURN i + x
   362  		`)
   363  
   364  		So(err, ShouldBeNil)
   365  
   366  		out, err := p.Run(context.Background())
   367  
   368  		So(err, ShouldBeNil)
   369  
   370  		So(string(out), ShouldEqual, `[5,6,5]`)
   371  	})
   372  
   373  	Convey("Should call functions", t, func() {
   374  		c := compiler.New()
   375  		counterA := 0
   376  		counterB := 0
   377  		c.RegisterFunction("COUNT_A", func(ctx context.Context, args ...core.Value) (core.Value, error) {
   378  			counterA++
   379  
   380  			return values.None, nil
   381  		})
   382  
   383  		c.RegisterFunction("COUNT_B", func(ctx context.Context, args ...core.Value) (core.Value, error) {
   384  			counterB++
   385  
   386  			return values.None, nil
   387  		})
   388  
   389  		p, err := c.Compile(`
   390  			FOR i IN [ 1, 2, 3, 4, 1, 3 ]
   391  				LET x = 2
   392  				COUNT_A()
   393  				FILTER i > x
   394  				COUNT_B()
   395  				RETURN i + x
   396  		`)
   397  
   398  		So(err, ShouldBeNil)
   399  
   400  		out, err := p.Run(context.Background())
   401  
   402  		So(err, ShouldBeNil)
   403  		So(counterA, ShouldEqual, 6)
   404  		So(counterB, ShouldEqual, 3)
   405  		So(string(out), ShouldEqual, `[5,6,5]`)
   406  	})
   407  }
   408  
   409  func BenchmarkFilter(b *testing.B) {
   410  	p := compiler.New().MustCompile(`
   411  			LET users = [
   412  				{
   413  					active: true,
   414  					age: 31,
   415  					gender: "m"
   416  				},
   417  				{
   418  					active: true,
   419  					age: 29,
   420  					gender: "f"
   421  				},
   422  				{
   423  					active: true,
   424  					age: 36,
   425  					gender: "m"
   426  				},
   427  				{
   428  					active: false,
   429  					age: 69,
   430  					gender: "m"
   431  				}
   432  			]
   433  			FOR u IN users
   434  				FILTER u.age < 35
   435  				RETURN u
   436  		`)
   437  
   438  	for n := 0; n < b.N; n++ {
   439  		p.Run(context.Background())
   440  	}
   441  }
   442  
   443  func BenchmarkFilter2(b *testing.B) {
   444  	p := compiler.New().MustCompile(`
   445  			LET users = [
   446  				{
   447  					active: true,
   448  					age: 31,
   449  					gender: "m"
   450  				},
   451  				{
   452  					active: true,
   453  					age: 29,
   454  					gender: "f"
   455  				},
   456  				{
   457  					active: true,
   458  					age: 36,
   459  					gender: "m"
   460  				},
   461  				{
   462  					active: false,
   463  					age: 69,
   464  					gender: "m"
   465  				}
   466  			]
   467  			FOR u IN users
   468  				FILTER u.active == true
   469  				FILTER u.age < 35
   470  				RETURN u
   471  		`)
   472  
   473  	for n := 0; n < b.N; n++ {
   474  		p.Run(context.Background())
   475  	}
   476  }
   477  
   478  func BenchmarkFilter3(b *testing.B) {
   479  	p := compiler.New().MustCompile(`
   480  			LET users = [
   481  				{
   482  					active: true,
   483  					age: 31,
   484  					gender: "m"
   485  				},
   486  				{
   487  					active: true,
   488  					age: 29,
   489  					gender: "f"
   490  				},
   491  				{
   492  					active: true,
   493  					age: 36,
   494  					gender: "m"
   495  				},
   496  				{
   497  					active: false,
   498  					age: 69,
   499  					gender: "m"
   500  				}
   501  			]
   502  			FOR u IN users
   503  				FILTER u.active == true
   504  				LIMIT 2
   505  				FILTER u.gender == "m"
   506  				RETURN u
   507  		`)
   508  
   509  	for n := 0; n < b.N; n++ {
   510  		p.Run(context.Background())
   511  	}
   512  }
   513  
   514  func BenchmarkFilter4(b *testing.B) {
   515  	p := compiler.New().MustCompile(`
   516  			LET users = [
   517  				{
   518  					active: true,
   519  					married: true,
   520  					age: 31,
   521  					gender: "m"
   522  				},
   523  				{
   524  					active: true,
   525  					married: false,
   526  					age: 25,
   527  					gender: "f"
   528  				},
   529  				{
   530  					active: true,
   531  					married: false,
   532  					age: 36,
   533  					gender: "m"
   534  				},
   535  				{
   536  					active: false,
   537  					married: true,
   538  					age: 69,
   539  					gender: "m"
   540  				},
   541  				{
   542  					active: true,
   543  					married: true,
   544  					age: 45,
   545  					gender: "f"
   546  				}
   547  			]
   548  			FOR u IN users
   549  				FILTER !u.active AND u.married
   550  				LIMIT 2
   551  				RETURN u
   552  		`)
   553  
   554  	for n := 0; n < b.N; n++ {
   555  		p.Run(context.Background())
   556  	}
   557  }