func newPrimaryIndex(b *bucket) (*primaryIndex, error) { ddoc := newPrimaryDDoc() meta := ast.NewFunctionCall("meta", ast.FunctionArgExpressionList{}) mdid := ast.NewDotMemberOperator(meta, ast.NewProperty("id")) inst := primaryIndex{ viewIndex{ name: PRIMARY_INDEX, using: catalog.VIEW, on: catalog.IndexKey{mdid}, ddoc: ddoc, bucket: b, }, } err := inst.putDesignDoc() if err != nil { return nil, err } err = inst.WaitForIndex() if err != nil { return nil, err } return &inst, nil }
func TestUnnest(t *testing.T) { stubSource := NewStubSource(joinerTestData) joiner := NewUnnest(ast.NewProperty("children"), "INNER", "child") joiner.SetSource(stubSource) joinerItemChannel, _ := joiner.GetChannels() stopChannel := make(misc.StopChannel) go joiner.Run(stopChannel) count := 0 for item := range joinerItemChannel { count++ _, err := item.Path("name") if err != nil { t.Errorf("Expected to find field name") } _, err = item.Path("child") if err != nil { t.Errorf("Expected to find field child") } } if count != 4 { t.Errorf("Expected %d items, got %d", 4, count) } }
func TestOrderDescending(t *testing.T) { stubSource := NewStubSource(testData) order := NewOrder([]*ast.SortExpression{ast.NewSortExpression(ast.NewProperty("age"), false)}, []string{}) order.SetSource(stubSource) orderItemChannel, _ := order.GetChannels() stopChannel := make(misc.StopChannel) go order.Run(stopChannel) count := 0 for item := range orderItemChannel { val, err := item.Path("name") if err != nil { t.Errorf("unexpected error: %v", err) } value := val.Value() if count == 0 && value != "steve" { t.Errorf("expected steve, got %v", value) } if count == len(testData)-1 && value != "dustin" { t.Errorf("expected dustin, got %v", value) } count++ } }
func TestProject(t *testing.T) { stubSource := NewStubSource(testData) project := NewProject(ast.ResultExpressionList{ast.NewResultExpressionWithAlias(ast.NewProperty("name"), "f_name")}, true) project.SetSource(stubSource) projectItemChannel, _ := project.GetChannels() stopChannel := make(misc.StopChannel) go project.Run(stopChannel) for item := range projectItemChannel { projection := item.GetAttachment("projection") projectionValue, ok := projection.(*dparval.Value) if !ok { t.Errorf("Expected item projection to be type Value") } _, err := projectionValue.Path("f_name") if err != nil { t.Errorf("unexpected error: %v", err) } } }
func newAllDocsIndex(b *bucket) *primaryIndex { meta := ast.NewFunctionCall("meta", ast.FunctionArgExpressionList{}) mdid := ast.NewDotMemberOperator(meta, ast.NewProperty("id")) ddoc := designdoc{name: "", viewname: "_all_docs"} idx := primaryIndex{ viewIndex{ name: ALLDOCS_INDEX, using: catalog.VIEW, on: catalog.IndexKey{mdid}, ddoc: &ddoc, bucket: b, }, } return &idx }
func TestFilterSome(t *testing.T) { stubSource := NewStubSource(testData) filter := NewFilter(ast.NewGreaterThanOperator(ast.NewProperty("name"), ast.NewLiteralString("n"))) filter.SetSource(stubSource) filterItemChannel, _ := filter.GetChannels() stopChannel := make(misc.StopChannel) go filter.Run(stopChannel) count := 0 for _ = range filterItemChannel { count++ } if count != 2 { t.Errorf("Expected %d items, got %d", 2, count) } }
func loadViewIndexes(b *bucket) ([]*catalog.Index, error) { rows, err := b.cbbucket.GetDDocs() if err != nil { return nil, err } inames := make([]string, 0, len(rows.Rows)) for _, row := range rows.Rows { cdoc := row.DDoc id := cdoc.Meta["id"].(string) if !strings.HasPrefix(id, "_design/ddl_") { continue } iname := strings.TrimPrefix(id, "_design/ddl_") inames = append(inames, iname) } indexes := make([]*catalog.Index, 0, len(inames)) for _, iname := range inames { ddname := "ddl_" + iname jdoc, err := getDesignDoc(b, ddname) if err != nil { return nil, err } jview, ok := jdoc.Views[iname] if !ok { return nil, errors.New("Missing view for index " + iname) } exprlist := make([]ast.Expression, 0, len(jdoc.IndexOn)) for _, ser := range jdoc.IndexOn { // HACK - remove this when Unmarshall supports META() if iname == PRIMARY_INDEX { meta := ast.NewFunctionCall("meta", ast.FunctionArgExpressionList{}) mdid := ast.NewDotMemberOperator(meta, ast.NewProperty("id")) exprlist = append(exprlist, mdid) } else { expr, err := ast.UnmarshalExpression([]byte(ser)) if err != nil { return nil, errors.New("Cannot unmarshal expression for index " + iname) } exprlist = append(exprlist, expr) } } if len(exprlist) != len(jdoc.IndexOn) { continue } ddoc := designdoc{ name: ddname, viewname: iname, mapfn: jview.Map, reducefn: jview.Reduce, } if ddoc.checksum() != jdoc.IndexChecksum { return nil, errors.New("Warning - checksum failed on index " + iname) } var index catalog.Index if iname == PRIMARY_INDEX { index = &primaryIndex{ viewIndex{ name: iname, bucket: b, using: catalog.VIEW, ddoc: &ddoc, on: exprlist, }, } indexes = append(indexes, &index) } else { index = &viewIndex{ name: iname, bucket: b, using: catalog.VIEW, ddoc: &ddoc, on: exprlist, } indexes = append(indexes, &index) } } return indexes, nil }
func TestParserASTOutput(t *testing.T) { tests := []struct { input string output ast.Statement }{ {"SELECT * FROM test WHERE true", &ast.SelectStatement{ Select: ast.ResultExpressionList{ ast.NewStarResultExpression(), }, Distinct: false, From: &ast.From{Projection: ast.NewProperty("test")}, Where: ast.NewLiteralBool(true), Limit: -1, }, }, {"SELECT * FROM :apool.test WHERE true", &ast.SelectStatement{ Select: ast.ResultExpressionList{ ast.NewStarResultExpression(), }, Distinct: false, From: &ast.From{Pool: "apool", Projection: ast.NewProperty("test")}, Where: ast.NewLiteralBool(true), Limit: -1, }, }, {"SELECT * FROM test ORDER BY foo", &ast.SelectStatement{ Select: ast.ResultExpressionList{ ast.NewStarResultExpression(), }, Distinct: false, From: &ast.From{Projection: ast.NewProperty("test")}, Where: nil, OrderBy: []*ast.SortExpression{ ast.NewSortExpression(ast.NewProperty("foo"), true), }, Limit: -1, }, }, {"SELECT * FROM test LIMIT 10 OFFSET 3", &ast.SelectStatement{ Select: ast.ResultExpressionList{ ast.NewStarResultExpression(), }, Distinct: false, From: &ast.From{Projection: ast.NewProperty("test")}, Where: nil, Limit: 10, Offset: 3, }, }, {"SELECT a FROM test", &ast.SelectStatement{ Select: ast.ResultExpressionList{ ast.NewResultExpression(ast.NewProperty("a")), }, Distinct: false, From: &ast.From{Projection: ast.NewProperty("test")}, Where: nil, Limit: -1, }, }, {"SELECT a FROM test t2", &ast.SelectStatement{ Select: ast.ResultExpressionList{ ast.NewResultExpression(ast.NewProperty("a")), }, Distinct: false, From: &ast.From{Projection: ast.NewProperty("test"), As: "t2"}, Where: nil, Limit: -1, }, }, {"SELECT 1+1*30 as steve", &ast.SelectStatement{ Select: ast.ResultExpressionList{ ast.NewResultExpressionWithAlias(ast.NewPlusOperator(ast.NewLiteralNumber(1.0), ast.NewMultiplyOperator(ast.NewLiteralNumber(1.0), ast.NewLiteralNumber(30.0))), "steve"), }, Distinct: false, From: nil, Where: nil, Limit: -1, }, }, {"SELECT 1+1*30 steve", &ast.SelectStatement{ Select: ast.ResultExpressionList{ ast.NewResultExpressionWithAlias(ast.NewPlusOperator(ast.NewLiteralNumber(1.0), ast.NewMultiplyOperator(ast.NewLiteralNumber(1.0), ast.NewLiteralNumber(30.0))), "steve"), }, Distinct: false, From: nil, Where: nil, Limit: -1, }, }, {"SELECT DISTINCT 1+1*30 as steve", &ast.SelectStatement{ Select: ast.ResultExpressionList{ ast.NewResultExpressionWithAlias(ast.NewPlusOperator(ast.NewLiteralNumber(1.0), ast.NewMultiplyOperator(ast.NewLiteralNumber(1.0), ast.NewLiteralNumber(30.0))), "steve"), }, Distinct: true, From: nil, Where: nil, Limit: -1, }, }, {"CREATE INDEX abv_idx ON beer-sample(abv) USING VIEW", &ast.CreateIndexStatement{ Method: "view", Bucket: "beer-sample", Name: "abv_idx", On: ast.ExpressionList{ast.NewProperty("abv")}, }, }, {"CREATE INDEX abv_idx ON beer-sample(abv) USING magic", &ast.CreateIndexStatement{ Method: "magic", Bucket: "beer-sample", Name: "abv_idx", On: ast.ExpressionList{ast.NewProperty("abv")}, }, }, {"CREATE INDEX abv_idx ON beer-sample(abv)", &ast.CreateIndexStatement{ Method: "", Bucket: "beer-sample", Name: "abv_idx", On: ast.ExpressionList{ast.NewProperty("abv")}, }, }, {"CREATE INDEX abv_idx ON :apool.beer-sample(abv) USING VIEW", &ast.CreateIndexStatement{ Method: "view", Pool: "apool", Bucket: "beer-sample", Name: "abv_idx", On: ast.ExpressionList{ast.NewProperty("abv")}, }, }, {"CREATE INDEX abv_idx ON :apool.beer-sample(abv) USING magic", &ast.CreateIndexStatement{ Method: "magic", Pool: "apool", Bucket: "beer-sample", Name: "abv_idx", On: ast.ExpressionList{ast.NewProperty("abv")}, }, }, {"CREATE INDEX abv_idx ON :apool.beer-sample(abv)", &ast.CreateIndexStatement{ Method: "", Pool: "apool", Bucket: "beer-sample", Name: "abv_idx", On: ast.ExpressionList{ast.NewProperty("abv")}, }, }, {"DROP INDEX beer-sample.abv", &ast.DropIndexStatement{ Bucket: "beer-sample", Name: "abv", }, }, {"DROP INDEX :apool.beer-sample.abv", &ast.DropIndexStatement{ Pool: "apool", Bucket: "beer-sample", Name: "abv", }, }, } n1qlParser := NewN1qlParser() for _, v := range tests { query, err := n1qlParser.Parse(v.input) if err != nil { t.Errorf("Valid Query Parse Failed: %v - %v", v, err) } if !reflect.DeepEqual(query, v.output) { t.Errorf("Expected %v, got %v", v.output, query) js, err := json.MarshalIndent(v.output, "", " ") if err == nil { t.Logf("Expected %v", string(js)) } js, err = json.MarshalIndent(query, "", " ") if err == nil { t.Logf("Got %v", string(js)) } } } }