github.com/rohankumardubey/aresdb@v0.0.2-0.20190517170215-e54e3ca06b9c/query/sql_parser_test.go (about)

     1  //  Copyright (c) 2017-2018 Uber Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package query
    16  
    17  import (
    18  	"github.com/onsi/ginkgo"
    19  	. "github.com/onsi/gomega"
    20  	"github.com/uber/aresdb/common"
    21  )
    22  
    23  var _ = ginkgo.Describe("SQL Parser", func() {
    24  
    25  	logger := common.NewLoggerFactory().GetDefaultLogger()
    26  
    27  	runTest := func(sqls []string, aql AQLQuery, log common.Logger) {
    28  		for _, sql := range sqls {
    29  			actual, err := Parse(sql, logger)
    30  			expected := aql
    31  			expected.SQLQuery = sql
    32  			Ω(err).Should(BeNil())
    33  			Ω(*actual).Should(BeEquivalentTo(expected))
    34  		}
    35  	}
    36  
    37  	ginkgo.It("parse row filters should work", func() {
    38  		sqls := []string{
    39  			`SELECT count(*) AS completed_trips, sum(fare)
    40  			FROM trips
    41  			WHERE status='completed' AND NOT status = 'cancelled' OR marketplace='agora'
    42  			GROUP BY status`,
    43  		}
    44  		res := AQLQuery{
    45  			Table:      "trips",
    46  			Measures:   []Measure{{Alias: "completed_trips", Expr: "count(*)"}, {Expr: "sum(fare)"}},
    47  			Filters:    []string{"status='completed' AND NOT status = 'cancelled' OR marketplace='agora'"},
    48  			Dimensions: []Dimension{{Expr: "status"}},
    49  		}
    50  		runTest(sqls, res, logger)
    51  	})
    52  
    53  	ginkgo.It("parse dimensions should work", func() {
    54  		sqls := []string{
    55  			`SELECT status AS trip_status, count(*) 
    56  			FROM trips 
    57  			GROUP BY trip_status;`,
    58  		}
    59  		res := AQLQuery{
    60  			Table:      "trips",
    61  			Measures:   []Measure{{Alias: "trip_status", Expr: "status"}, {Expr: "count(*)"}},
    62  			Dimensions: []Dimension{{Alias: "trip_status", Expr: "status"}},
    63  		}
    64  		runTest(sqls, res, logger)
    65  	})
    66  
    67  	ginkgo.It("parse non agg AQLQuery should work", func() {
    68  		sqls := []string{
    69  			`SELECT field1, *
    70  			FROM trips;`,
    71  		}
    72  		res := AQLQuery{
    73  			Table:      "trips",
    74  			Measures:   []Measure{{Expr: "1"}},
    75  			Dimensions: []Dimension{{Expr: "field1"}, {Expr: "*"}},
    76  		}
    77  		runTest(sqls, res, logger)
    78  	})
    79  
    80  	ginkgo.It("parse sort by should work", func() {
    81  		sqls := []string{
    82  			`SELECT field1
    83  			FROM trips
    84  			ORDER BY field1;`,
    85  		}
    86  		res := AQLQuery{
    87  			Table:      "trips",
    88  			Measures:   []Measure{{Expr: "1"}},
    89  			Dimensions: []Dimension{{Expr: "field1"}},
    90  			Sorts: []SortField{
    91  				{Name: "field1", Order: "ASC"},
    92  			},
    93  		}
    94  		runTest(sqls, res, logger)
    95  	})
    96  
    97  	ginkgo.It("parse time UDFs should work", func() {
    98  
    99  		sqls := []string{
   100  			// Precision truncation based bucketizer.
   101  			`SELECT count(*) FROM trips
   102  			GROUP BY aql_time_bucket_minute("request_at", "minute", "America/New_York");`,
   103  			`SELECT count(*) FROM trips
   104  			GROUP BY aql_time_bucket_hour("request_at", "minute", "America/New_York");`,
   105  			`SELECT count(*) FROM trips
   106  			GROUP BY aql_time_bucket_day("request_at", "minute", "America/New_York");`,
   107  			`SELECT count(*) FROM trips
   108  			GROUP BY aql_time_bucket_week("request_at", "minute", "America/New_York");`,
   109  			`SELECT count(*) FROM trips
   110  			GROUP BY aql_time_bucket_month("request_at", "minute", "America/New_York");`,
   111  			`SELECT count(*) FROM trips
   112  			GROUP BY aql_time_bucket_quarter("request_at", "minute", "America/New_York");`,
   113  			`SELECT count(*) FROM trips
   114  			GROUP BY aql_time_bucket_year("request_at", "minute", "America/New_York");`,
   115  			// Component based bucketizer.
   116  			`SELECT count(*) FROM trips
   117  			GROUP BY aql_time_bucket_time_of_day("request_at", "minute", "America/New_York");`,
   118  			`SELECT count(*) FROM trips
   119  			GROUP BY aql_time_bucket_minutes_of_day("request_at", "minute", "America/New_York");`,
   120  			`SELECT count(*) FROM trips
   121  			GROUP BY aql_time_bucket_hour_of_day("request_at", "minute", "America/New_York");`,
   122  			`SELECT count(*) FROM trips
   123  			GROUP BY aql_time_bucket_hour_of_week("request_at", "minute", "America/New_York");`,
   124  			`SELECT count(*) FROM trips
   125  			GROUP BY aql_time_bucket_day_of_week("request_at", "minute", "America/New_York");`,
   126  			`SELECT count(*) FROM trips
   127  			GROUP BY aql_time_bucket_day_of_month("request_at", "minute", "America/New_York");`,
   128  			`SELECT count(*) FROM trips
   129  			GROUP BY aql_time_bucket_day_of_year("request_at", "minute", "America/New_York");`,
   130  			`SELECT count(*) FROM trips
   131  			GROUP BY aql_time_bucket_month_of_year("request_at", "minute", "America/New_York");`,
   132  			`SELECT count(*) FROM trips
   133  			GROUP BY aql_time_bucket_quarter_of_year("request_at", "minute", "America/New_York");`,
   134  		}
   135  
   136  		td := Dimension{Expr: "request_at", TimeUnit: "minute"}
   137  		tbs := []string{"minute", "hour", "day", "week", "month", "quarter", "year",
   138  			"time of day", "minutes of day", "hour of day", "hour of week",
   139  			"day of week", "day of month", "day of year", "month of year", "quarter of year"}
   140  		res := AQLQuery{
   141  			Table:      "trips",
   142  			Measures:   []Measure{{Expr: "count(*)"}},
   143  			Dimensions: make([]Dimension, 1),
   144  			Timezone:   "America/New_York",
   145  		}
   146  		for i, sql := range sqls {
   147  			aql, err := Parse(sql, logger)
   148  			Ω(err).Should(BeNil())
   149  			td.TimeBucketizer = tbs[i]
   150  			res.Dimensions[0] = td
   151  			res.SQLQuery = sql
   152  			Ω(*aql).Should(Equal(res))
   153  		}
   154  	})
   155  
   156  	ginkgo.It("parse time filters, time dimension and timezone should work", func() {
   157  		sqls := []string{
   158  			`SELECT count(*)
   159  			FROM trips 
   160  
   161  			WHERE aql_time_filter(request_at, "96 quarter-hours ago", "1 quarter-hours ago", America/New_York)
   162  			GROUP BY aql_time_bucket_minute(request_at, "minute", America/New_York);`,
   163  		}
   164  		res := AQLQuery{
   165  			Table:      "trips",
   166  			Measures:   []Measure{{Expr: "count(*)"}},
   167  			TimeFilter: TimeFilter{Column: "request_at", From: "96 quarter-hours ago", To: "1 quarter-hours ago"},
   168  			Dimensions: []Dimension{{Expr: "request_at", TimeBucketizer: "minute", TimeUnit: "minute"}},
   169  			Timezone:   "America/New_York",
   170  		}
   171  		runTest(sqls, res, logger)
   172  	})
   173  
   174  	ginkgo.It("parse time filters, time dimension and timezone and row filters should work", func() {
   175  		sqls := []string{
   176  			`SELECT  count(*)
   177  			FROM trips 
   178  			WHERE aql_time_filter(request_at, "96 quarter-hours ago", "1 quarter-hours ago", America/New_York) AND marketplace="agora"
   179  			GROUP BY aql_time_bucket_minutes(request_at, "minute", America/New_York);`,
   180  		}
   181  		res := AQLQuery{
   182  			Table:      "trips",
   183  			Measures:   []Measure{{Expr: "count(*)"}},
   184  			TimeFilter: TimeFilter{Column: "request_at", From: "96 quarter-hours ago", To: "1 quarter-hours ago"},
   185  			Dimensions: []Dimension{{Expr: "request_at", TimeBucketizer: "minutes", TimeUnit: "minute"}},
   186  			Filters:    []string{`marketplace="agora"`},
   187  			Timezone:   "America/New_York",
   188  		}
   189  		runTest(sqls, res, logger)
   190  	})
   191  
   192  	ginkgo.It("parse numeric bucketizer should work", func() {
   193  		sqls := []string{
   194  			`SELECT  population AS pop, count(*)
   195  			FROM trips
   196  			WHERE aql_time_filter(request_at, "96 quarter-hours ago", "1 quarter-hours ago", America/New_York) AND marketplace="agora"
   197  			GROUP BY aql_time_bucket_hour(request_at, "minute", America/New_York), aql_numeric_bucket_logbase(pop, 2);`,
   198  		}
   199  		res := AQLQuery{
   200  			Table:      "trips",
   201  			Measures:   []Measure{{Alias: "pop", Expr: "population"}, {Expr: "count(*)"}},
   202  			Dimensions: []Dimension{{Expr: "request_at", TimeBucketizer: "hour", TimeUnit: "minute"}, {Expr: "pop", NumericBucketizer: NumericBucketizerDef{LogBase: 2}}},
   203  			TimeFilter: TimeFilter{Column: "request_at", From: "96 quarter-hours ago", To: "1 quarter-hours ago"},
   204  			Filters:    []string{`marketplace="agora"`},
   205  			Timezone:   "America/New_York",
   206  		}
   207  		runTest(sqls, res, logger)
   208  	})
   209  
   210  	ginkgo.It("parse join should work", func() {
   211  		sqls := []string{
   212  			`SELECT  population AS pop, count(*)
   213  			FROM trips
   214  				LEFT JOIN trips AS rush_leg
   215  					ON trips.workflow_uuid=rush_leg.workflow_uuid AND status='completed'
   216    				LEFT JOIN api_cities AS cities
   217  					ON cities.id=city_id
   218  			WHERE aql_time_filter(request_at, "96 quarter-hours ago", "1 quarter-hours ago", America/New_York) AND marketplace="agora"
   219  			GROUP BY aql_time_bucket_hours(request_at, "minute", America/New_York), aql_numeric_bucket_logbase(pop, 2);`,
   220  		}
   221  		res := AQLQuery{
   222  			Table: "trips",
   223  			Joins: []Join{
   224  				{Table: "trips", Alias: "rush_leg", Conditions: []string{"trips.workflow_uuid=rush_leg.workflow_uuid", "status='completed'"}},
   225  				{Table: "api_cities", Alias: "cities", Conditions: []string{"cities.id=city_id"}},
   226  			},
   227  			Measures:   []Measure{{Alias: "pop", Expr: "population"}, {Expr: "count(*)"}},
   228  			Dimensions: []Dimension{{Expr: "request_at", TimeBucketizer: "hours", TimeUnit: "minute"}, {Expr: "pop", NumericBucketizer: NumericBucketizerDef{LogBase: 2}}},
   229  			TimeFilter: TimeFilter{Column: "request_at", From: "96 quarter-hours ago", To: "1 quarter-hours ago"},
   230  			Filters:    []string{`marketplace="agora"`},
   231  			Timezone:   "America/New_York",
   232  		}
   233  		runTest(sqls, res, logger)
   234  	})
   235  
   236  	ginkgo.It("parse composite measures should work", func() {
   237  		sqls := []string{
   238  			// test SubQuery
   239  			`SELECT Completed, Requested, Completed/Requested
   240  			FROM
   241  			(SELECT count(*) AS Requested
   242  			FROM trips
   243  				LEFT JOIN trips AS rush_leg
   244      				ON trips.workflow_uuid=rush_leg.workflow_uuid AND status='completed'
   245  				LEFT JOIN api_cities AS cities
   246      				ON cities.id=city_id
   247  			WHERE aql_time_filter(request_at, "96 quarter-hours ago", "1 quarter-hours ago", America/New_York) AND marketplace="agora"
   248  			GROUP BY aql_time_bucket_day(request_at, "minute", America/New_York), aql_numeric_bucket_logbase(pop, 2)) AS m1
   249  			NATURAL LEFT JOIN
   250  			(SELECT count(*) AS Completed
   251  			FROM trips
   252    				LEFT JOIN trips AS rush_leg
   253      				ON trips.workflow_uuid=rush_leg.workflow_uuid AND status='completed'
   254    				LEFT JOIN api_cities AS cities
   255      				ON cities.id=city_id
   256  			WHERE aql_time_filter(request_at, "96 quarter-hours ago", "1 quarter-hours ago", America/New_York) AND marketplace="agora" AND status='completed'
   257  			GROUP BY aql_time_bucket_day(request_at, "minute", America/New_York), aql_numeric_bucket_logbase(pop, 2)) AS m2;`,
   258  			// test WithQuery
   259  			`WITH m1 (Requested) AS (SELECT count(*) AS Requested
   260  			FROM trips
   261  				LEFT JOIN trips AS rush_leg
   262  					ON trips.workflow_uuid=rush_leg.workflow_uuid AND status='completed'
   263    				LEFT JOIN api_cities AS cities
   264  					ON cities.id=city_id
   265  			WHERE aql_time_filter(request_at, "96 quarter-hours ago", "1 quarter-hours ago", America/New_York) AND marketplace="agora"
   266  			GROUP BY aql_time_bucket_day(request_at, "minute", America/New_York), aql_numeric_bucket_logbase(pop, 2)),
   267  			m2 (Completed) AS
   268  			(SELECT count(*) AS Completed
   269  			FROM trips
   270  				LEFT JOIN trips AS rush_leg
   271  					ON trips.workflow_uuid=rush_leg.workflow_uuid AND status='completed'
   272    				LEFT JOIN api_cities AS cities
   273  					ON cities.id=city_id
   274  			WHERE aql_time_filter(request_at, "96 quarter-hours ago", "1 quarter-hours ago", America/New_York) AND marketplace="agora" AND status='completed'
   275  			GROUP BY aql_time_bucket_day(request_at, "minute", America/New_York), aql_numeric_bucket_logbase(pop, 2))
   276  			SELECT Completed, Requested, Completed/Requested
   277  			FROM m1 NATURAL LEFT JOIN m2;`,
   278  		}
   279  		res := AQLQuery{
   280  			Table: "trips",
   281  			Joins: []Join{
   282  				{Table: "trips", Alias: "rush_leg", Conditions: []string{"trips.workflow_uuid=rush_leg.workflow_uuid", "status='completed'"}},
   283  				{Table: "api_cities", Alias: "cities", Conditions: []string{"cities.id=city_id"}},
   284  			},
   285  			Measures: []Measure{
   286  				{Alias: "Completed", Expr: "count(*)", Filters: []string{"marketplace=\"agora\"", "status='completed'"}},
   287  				{Alias: "Requested", Expr: "count(*)", Filters: []string{"marketplace=\"agora\""}},
   288  				{Expr: "Completed/Requested"},
   289  			},
   290  			Dimensions:           []Dimension{{Expr: "request_at", TimeBucketizer: "day", TimeUnit: "minute"}, {Expr: "pop", NumericBucketizer: NumericBucketizerDef{LogBase: 2}}},
   291  			SupportingDimensions: []Dimension{},
   292  			SupportingMeasures:   []Measure{},
   293  			TimeFilter:           TimeFilter{Column: "request_at", From: "96 quarter-hours ago", To: "1 quarter-hours ago"},
   294  			Timezone:             "America/New_York",
   295  		}
   296  		runTest(sqls, res, logger)
   297  	})
   298  
   299  	ginkgo.It("parse supporting measures should work", func() {
   300  		sqls := []string{
   301  			// test Subquery
   302  			`SELECT Completed/Requested
   303  			FROM
   304  			(SELECT count(*) AS Requested
   305  			FROM trips
   306  				LEFT JOIN trips AS rush_leg
   307  					ON trips.workflow_uuid=rush_leg.workflow_uuid AND status='completed'
   308    				LEFT JOIN api_cities AS cities
   309  					ON cities.id=city_id
   310  			WHERE aql_time_filter(request_at, "96 quarter-hours ago", "1 quarter-hours ago", America/New_York) AND marketplace="agora"
   311  			GROUP BY aql_time_bucket_day(request_at, "minute", America/New_York), aql_numeric_bucket_logbase(pop, 2)) AS m1
   312  			NATURAL LEFT JOIN
   313  			(SELECT count(*) AS Completed
   314  			FROM trips
   315  				LEFT JOIN trips AS rush_leg
   316  					ON trips.workflow_uuid=rush_leg.workflow_uuid AND status='completed'
   317    				LEFT JOIN api_cities AS cities
   318  					ON cities.id=city_id
   319  			WHERE aql_time_filter(request_at, "96 quarter-hours ago", "1 quarter-hours ago", America/New_York) AND marketplace="agora" AND status='completed'
   320  			GROUP BY aql_time_bucket_day(request_at, "minute", America/New_York), aql_numeric_bucket_logbase(pop, 2)) AS m2;`,
   321  			// test WithQuery
   322  			`WITH m1 (Requested) AS (SELECT count(*) AS Requested
   323  			FROM trips
   324  				LEFT JOIN trips AS rush_leg
   325  					ON trips.workflow_uuid=rush_leg.workflow_uuid AND status='completed'
   326    				LEFT JOIN api_cities AS cities
   327  					ON cities.id=city_id
   328  			WHERE aql_time_filter(request_at, "96 quarter-hours ago", "1 quarter-hours ago", America/New_York) AND marketplace="agora"
   329  			GROUP BY aql_time_bucket_day(request_at, "minute", America/New_York), aql_numeric_bucket_logbase(pop, 2)),
   330  			m2 (Completed) AS
   331  			(SELECT count(*) AS Completed
   332  			FROM trips
   333  				LEFT JOIN trips AS rush_leg
   334  					ON trips.workflow_uuid=rush_leg.workflow_uuid AND status='completed'
   335    				LEFT JOIN api_cities AS cities
   336  					ON cities.id=city_id
   337  			WHERE aql_time_filter(request_at, "96 quarter-hours ago", "1 quarter-hours ago", America/New_York) AND marketplace="agora" AND status='completed'
   338  			GROUP BY aql_time_bucket_day(request_at, "minute", America/New_York), aql_numeric_bucket_logbase(pop, 2))
   339  			SELECT Completed/Requested
   340  			FROM m1 NATURAL LEFT JOIN m2;`,
   341  		}
   342  		res := AQLQuery{
   343  			Table: "trips",
   344  			Joins: []Join{
   345  				{Table: "trips", Alias: "rush_leg", Conditions: []string{"trips.workflow_uuid=rush_leg.workflow_uuid", "status='completed'"}},
   346  				{Table: "api_cities", Alias: "cities", Conditions: []string{"cities.id=city_id"}},
   347  			},
   348  			Measures:             []Measure{{Expr: "Completed/Requested"}},
   349  			TimeFilter:           TimeFilter{Column: "request_at", From: "96 quarter-hours ago", To: "1 quarter-hours ago"},
   350  			Dimensions:           []Dimension{{Expr: "request_at", TimeBucketizer: "day", TimeUnit: "minute"}, {Expr: "pop", NumericBucketizer: NumericBucketizerDef{LogBase: 2}}},
   351  			SupportingDimensions: []Dimension{},
   352  			SupportingMeasures: []Measure{
   353  				{Alias: "Requested", Expr: "count(*)", Filters: []string{"marketplace=\"agora\""}},
   354  				{Alias: "Completed", Expr: "count(*)", Filters: []string{"marketplace=\"agora\"", "status='completed'"}},
   355  			},
   356  			Timezone: "America/New_York",
   357  		}
   358  		for _, sql := range sqls {
   359  			actual, err := Parse(sql, logger)
   360  			Ω(err).ShouldNot(BeNil())
   361  			Ω(err.Error()).Should(Equal("sub query not supported yet"))
   362  			res.SQLQuery = sql
   363  			Ω(*actual).Should(BeEquivalentTo(res))
   364  		}
   365  	})
   366  
   367  	ginkgo.It("With RECURSIVE is not allowed", func() {
   368  		sqls := []string{
   369  			`WITH RECURSIVE t(n) AS (
   370  				VALUES (1)
   371  			UNION ALL
   372      			SELECT n+1 FROM t WHERE n < 100
   373  			)
   374  			SELECT sum(n) FROM t;`,
   375  		}
   376  		for _, sql := range sqls {
   377  			actual, err := Parse(sql, logger)
   378  			Ω(err).ShouldNot(BeNil())
   379  			Ω(err.Error()).Should(Equal("RECURSIVE not yet supported at (line:1, col:0)"))
   380  			Ω(actual).Should(BeNil())
   381  		}
   382  	})
   383  
   384  	ginkgo.It("Query in namedQuery should not contain With or queryNoWith", func() {
   385  		sqls := []string{
   386  			`WITH m1 (Requested) AS
   387  				(With m (Requested) AS 
   388  					SELECT count(*) AS Requested FROM trips
   389  				SELECT Requested FROM m)
   390  			SELECT Requested FROM m1;`,
   391  		}
   392  		for _, sql := range sqls {
   393  			actual, err := Parse(sql, logger)
   394  			Ω(err).ShouldNot(BeNil())
   395  			Ω(err.Error()).Should(Equal("only support 1 level with query at (line:2, col:5)"))
   396  			Ω(actual).Should(BeNil())
   397  		}
   398  	})
   399  
   400  	ginkgo.It("Only main query allows NATURAL JOIN by using With/subqueryRelation identifier", func() {
   401  		sqls := []string{
   402  			`WITH m1 (Requested) AS (SELECT count(*) AS Requested FROM trips),
   403  			m2 (Completed) AS (SELECT count(*) AS Completed	FROM trips 
   404  				NATURAL LEFT JOIN m1)
   405  			SELECT Completed, Requested, Completed/Requested
   406  			FROM m1 NATURAL LEFT JOIN m2;`,
   407  		}
   408  		for _, sql := range sqls {
   409  			actual, err := Parse(sql, logger)
   410  			Ω(err).ShouldNot(BeNil())
   411  			Ω(err.Error()).Should(Equal("natural join not supported at subquery/withQuery at (line:2, col:56)"))
   412  			Ω(actual).Should(BeNil())
   413  		}
   414  	})
   415  
   416  	ginkgo.It("Both left and right in joinRelation must be either tableName or With/subqueryRelation at the same time", func() {
   417  		sqls := []string{
   418  			`WITH m1 (f) AS (SELECT fare AS f FROM trips),
   419  			SELECT f, driverUuid, riderUuid
   420  			FROM m1 NATURAL LEFT JOIN trips;`,
   421  			`WITH m2 (f) AS (SELECT fare AS f FROM trips),
   422  			SELECT driverUuid, riderUuid, f
   423  			FROM trips NATURAL LEFT JOIN m2;`,
   424  		}
   425  		for _, sql := range sqls {
   426  			actual, err := Parse(sql, logger)
   427  			Ω(err).ShouldNot(BeNil())
   428  			Ω(err.Error()).Should(Equal("missing with query body at (line:2, col:3)"))
   429  			Ω(actual).Should(BeNil())
   430  		}
   431  	})
   432  
   433  	ginkgo.It("FROM, GROUP BY and ORDER BY clause are required to be same in the With/subqueryRelation", func() {
   434  		sqls := []string{
   435  			`WITH m1 (Requested) AS (SELECT count(*) AS Requested
   436  			FROM base_trips
   437  				LEFT JOIN trips AS rush_leg
   438  					ON trips.workflow_uuid=rush_leg.workflow_uuid AND status='completed'
   439    				LEFT JOIN api_cities AS cities
   440  					ON cities.id=city_id
   441  			WHERE aql_time_filter(request_at, "96 quarter-hours ago", "1 quarter-hours ago", America/New_York) AND marketplace="agora"
   442  			m2 (Completed) AS
   443  			(SELECT count(*) AS Completed
   444  			FROM workflow_trips
   445  				LEFT JOIN trips AS rush_leg
   446  					ON trips.workflow_uuid=rush_leg.workflow_uuid AND status='completed'
   447    				LEFT JOIN api_cities AS cities
   448  					ON cities.id=city_id
   449  			WHERE aql_time_filter(request_at, "96 quarter-hours ago", "1 quarter-hours ago", America/New_York) AND marketplace="agora" AND status='completed'
   450  			SELECT Completed/Requested
   451  			FROM m1 NATURAL LEFT JOIN m2;`,
   452  
   453  			`WITH m1 (Requested) AS (SELECT count(*) AS Requested
   454  			FROM trips
   455  				LEFT JOIN trips AS rush_leg
   456  					ON trips.workflow_uuid=rush_leg.workflow_uuid AND status='completed'
   457    				LEFT JOIN api_cities AS cities
   458  					ON cities.id=city_id
   459  			WHERE aql_time_filter(request_at, "96 quarter-hours ago", "1 quarter-hours ago", America/New_York) AND marketplace="agora"
   460  			GROUP BY aql_time_bucket_hour(request_at, "minute", America/New_York), aql_numeric_bucket_logbase(pop, 2)),
   461  			m2 (Completed) AS
   462  			(SELECT count(*) AS Completed
   463  			FROM trips
   464  				LEFT JOIN trips AS rush_leg
   465  					ON trips.workflow_uuid=rush_leg.workflow_uuid AND status='completed'
   466    				LEFT JOIN api_cities AS cities
   467  					ON cities.id=city_id
   468  			WHERE aql_time_filter(request_at, "96 quarter-hours ago", "1 quarter-hours ago", America/New_York) AND marketplace="agora" AND status='completed'
   469  			GROUP BY aql_time_bucket_day(request_at, "minute", America/New_York), aql_numeric_bucket_logbase(pop, 2))
   470  			SELECT Completed/Requested
   471  			FROM m1 NATURAL LEFT JOIN m2;`,
   472  		}
   473  		for _, sql := range sqls {
   474  			actual, err := Parse(sql, logger)
   475  			Ω(err).ShouldNot(BeNil())
   476  			Ω(actual).Should(BeNil())
   477  		}
   478  	})
   479  
   480  	ginkgo.It("The identifier of With/subqueryRelation is not allowed in expression", func() {
   481  		sqls := []string{
   482  			`WITH m1 (avg_fare) AS 
   483  				(SELECT avg(fare) AS avg_fare FROM trips)
   484  			SELECT fare FROM trips 
   485  			WHERE fare > m1.avg_fare;`,
   486  		}
   487  		for _, sql := range sqls {
   488  			actual, err := Parse(sql, logger)
   489  			Ω(err).ShouldNot(BeNil())
   490  			Ω(err.Error()).Should(Equal("subquery/withQuery identifier in expression not supported yet. (line:4, col:16)"))
   491  			Ω(actual).Should(BeNil())
   492  		}
   493  	})
   494  })