From bdb20fef9a0d5eb2497c2ce2f9b12174693cd43e Mon Sep 17 00:00:00 2001 From: dosco <832235+dosco@users.noreply.github.com> Date: Sat, 11 May 2024 12:15:36 -0700 Subject: [PATCH] fix: configuration defined OrderBy + cursor combo not working #507 --- core/internal/psql/exp.go | 22 ++++++++++++--- core/internal/psql/query.go | 12 ++++++-- core/internal/qcode/qcode.go | 23 ++++++++++++--- tests/dbint_test.go | 8 ++++++ tests/query_test.go | 54 ++++++++++++++++++++++++++++-------- 5 files changed, 98 insertions(+), 21 deletions(-) diff --git a/core/internal/psql/exp.go b/core/internal/psql/exp.go index 988280f1..53c26ecc 100644 --- a/core/internal/psql/exp.go +++ b/core/internal/psql/exp.go @@ -132,11 +132,18 @@ func (c *expContext) renderOp(ex *qcode.Exp) { table = ex.Left.Table } + var colName string + if ex.Left.ColName != "" { + colName = ex.Left.ColName + } else { + colName = ex.Left.Col.Name + } + c.w.WriteString(`((`) if ex.Left.ID == -1 { - c.colWithTable(table, ex.Left.Col.Name) + c.colWithTable(table, colName) } else { - c.colWithTableID(table, ex.Left.ID, ex.Left.Col.Name) + c.colWithTableID(table, ex.Left.ID, colName) } c.w.WriteString(`) `) } @@ -344,6 +351,13 @@ func (c *expContext) renderVal(ex *qcode.Exp) { table = ex.Right.Table } + var colName string + if ex.Right.ColName != "" { + colName = ex.Right.ColName + } else { + colName = ex.Right.Col.Name + } + pid := ex.Right.ID if ex.Right.ID != -1 { pid = ex.Right.ID @@ -354,9 +368,9 @@ func (c *expContext) renderVal(ex *qcode.Exp) { c.renderValArrayColumn(ex, table, pid) } else { if pid == -1 { - c.colWithTable(table, ex.Right.Col.Name) + c.colWithTable(table, colName) } else { - c.colWithTableID(table, pid, ex.Right.Col.Name) + c.colWithTableID(table, pid, colName) } } c.w.WriteString(`)`) diff --git a/core/internal/psql/query.go b/core/internal/psql/query.go index 235b98b8..3d04473f 100644 --- a/core/internal/psql/query.go +++ b/core/internal/psql/query.go @@ -571,7 +571,11 @@ func (c *compilerContext) renderCursorCTE(sel *qcode.Select) { int32String(c.w, int32(i+2)) c.w.WriteString(`), ',', -1), '') AS `) // c.w.WriteString(ob.Col.Type) - c.quoted(ob.Col.Name) + if ob.KeyVar != "" && ob.Key != "" { + c.quoted(ob.Col.Name + "_" + ob.Key) + } else { + c.quoted(ob.Col.Name) + } } c.w.WriteString(` FROM ((SELECT `) c.renderParam(Param{Name: "cursor", Type: "text"}) @@ -587,7 +591,11 @@ func (c *compilerContext) renderCursorCTE(sel *qcode.Select) { c.w.WriteString(`] :: `) c.w.WriteString(ob.Col.Type) c.w.WriteString(` AS `) - c.quoted(ob.Col.Name) + if ob.KeyVar != "" && ob.Key != "" { + c.quoted(ob.Col.Name + "_" + ob.Key) + } else { + c.quoted(ob.Col.Name) + } } c.w.WriteString(` FROM STRING_TO_ARRAY(`) c.renderParam(Param{Name: "cursor", Type: "text"}) diff --git a/core/internal/qcode/qcode.go b/core/internal/qcode/qcode.go index 8db64125..3ef4b5a1 100644 --- a/core/internal/qcode/qcode.go +++ b/core/internal/qcode/qcode.go @@ -166,9 +166,10 @@ type Exp struct { OrderBy bool Left struct { - ID int32 - Table string - Col sdata.DBColumn + ID int32 + Table string + Col sdata.DBColumn + ColName string } Right struct { ValType ValType @@ -176,6 +177,7 @@ type Exp struct { ID int32 Table string Col sdata.DBColumn + ColName string ListType ValType ListVal []string Path []string @@ -871,11 +873,16 @@ func (co *Compiler) addSeekPredicate(sel *Select) { obLen := len(sel.OrderBy) if obLen != 0 { + ob := sel.OrderBy[0] or = newExpOp(OpOr) isnull := newExpOp(OpIsNull) isnull.Left.Table = "__cur" - isnull.Left.Col = sel.OrderBy[0].Col + isnull.Left.Col = ob.Col + + if ob.Key != "" { + isnull.Left.ColName = ob.Col.Name + "_" + ob.Key + } or.Children = []*Exp{isnull} } @@ -895,6 +902,10 @@ func (co *Compiler) addSeekPredicate(sel *Select) { f.Right.Table = "__cur" f.Right.Col = ob.Col + if ob.Key != "" { + f.Right.ColName = ob.Col.Name + "_" + ob.Key + } + switch { case i > 0 && n != i: f.Op = OpEquals @@ -917,6 +928,10 @@ func (co *Compiler) addSeekPredicate(sel *Select) { isnull2 := newExpOp(OpIsNull) isnull2.Left.Col = ob.Col + if ob.Key != "" { + isnull1.Left.ColName = ob.Col.Name + "_" + ob.Key + } + or1 := newExpOp(OpOr) or1.Children = append(or.Children, isnull1, isnull2, f) diff --git a/tests/dbint_test.go b/tests/dbint_test.go index 7649244a..be1ac776 100644 --- a/tests/dbint_test.go +++ b/tests/dbint_test.go @@ -6,6 +6,7 @@ import ( "flag" "fmt" "os" + "regexp" "testing" "github.com/dosco/graphjin/core/v3" @@ -151,3 +152,10 @@ func stdJSON(val []byte) string { func printJSON(val []byte) { fmt.Println(stdJSON(val)) } + +var re = regexp.MustCompile(`([:,])\s|`) + +func printJSONString(val string) { + v := re.ReplaceAllString(val, `$1`) + fmt.Println(v) +} diff --git a/tests/query_test.go b/tests/query_test.go index 9716c520..6ca36ea6 100644 --- a/tests/query_test.go +++ b/tests/query_test.go @@ -106,7 +106,11 @@ func Example_queryWithUser() { func Example_queryWithDynamicOrderBy() { gql := ` query getProducts { - products(order_by: $order, where: { id: { lt: 6 } }, limit: 5) { + products( + order_by: $order, + where: { id: { lt: 6 } }, + limit: 5, + before: $cursor) { id price } @@ -124,6 +128,12 @@ func Example_queryWithDynamicOrderBy() { }}, }) + type result struct { + Products json.RawMessage `json:"products"` + Cursor string `json:"products_cursor"` + } + var val result + gj, err := core.NewGraphJin(conf, db) if err != nil { panic(err) @@ -132,23 +142,45 @@ func Example_queryWithDynamicOrderBy() { vars1 := json.RawMessage(`{ "order": "price_and_id" }`) res1, err1 := gj.GraphQL(context.Background(), gql, vars1, nil) - if err != nil { - fmt.Println(err1) - } else { - printJSON(res1.Data) + if err1 != nil { + fmt.Println(err) + return + } + + if err := json.Unmarshal(res1.Data, &val); err != nil { + fmt.Println(err) + return + } + + if val.Cursor == "" { + fmt.Println("product_cursor value missing") + return } + printJSONString(string(val.Products)) vars2 := json.RawMessage(`{ "order": "just_id" }`) res2, err2 := gj.GraphQL(context.Background(), gql, vars2, nil) - if err != nil { - fmt.Println(err2) - } else { - printJSON(res2.Data) + if err2 != nil { + fmt.Println(err) + return + } + + if err := json.Unmarshal(res2.Data, &val); err != nil { + fmt.Println(err) + return } + + if val.Cursor == "" { + fmt.Println("product_cursor value missing") + return + } + + printJSONString(string(val.Products)) + // Output: - //{"products":[{"id":5,"price":15.5},{"id":4,"price":14.5},{"id":3,"price":13.5},{"id":2,"price":12.5},{"id":1,"price":11.5}]} - //{"products":[{"id":1,"price":11.5},{"id":2,"price":12.5},{"id":3,"price":13.5},{"id":4,"price":14.5},{"id":5,"price":15.5}]} + //[{"id":5,"price":15.5},{"id":4,"price":14.5},{"id":3,"price":13.5},{"id":2,"price":12.5},{"id":1,"price":11.5}] + //[{"id":1,"price":11.5},{"id":2,"price":12.5},{"id":3,"price":13.5},{"id":4,"price":14.5},{"id":5,"price":15.5}] } func Example_queryWithNestedOrderBy() {