2
0

json_operator_test.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. package parser
  2. import (
  3. "testing"
  4. "github.com/danfragoso/pizzasql-next/pkg/lexer"
  5. )
  6. func TestParseJSONArrowChainingIsLeftAssociative(t *testing.T) {
  7. expr := parseExpr(t, "doc -> 'a' -> 0")
  8. outer, ok := expr.(*BinaryExpr)
  9. if !ok {
  10. t.Fatalf("expected *BinaryExpr, got %T", expr)
  11. }
  12. if outer.Op != lexer.TokenArrow {
  13. t.Fatalf("outer operator = %v, want ->", outer.Op)
  14. }
  15. lit, ok := outer.Right.(*LiteralExpr)
  16. if !ok || lit.Value != "0" {
  17. t.Fatalf("outer right = %#v, want literal 0", outer.Right)
  18. }
  19. inner, ok := outer.Left.(*BinaryExpr)
  20. if !ok {
  21. t.Fatalf("outer left = %T, want *BinaryExpr", outer.Left)
  22. }
  23. if inner.Op != lexer.TokenArrow {
  24. t.Fatalf("inner operator = %v, want ->", inner.Op)
  25. }
  26. ref, ok := inner.Left.(*ColumnRef)
  27. if !ok || ref.Table != "" || ref.Column != "doc" {
  28. t.Fatalf("inner left = %#v, want column doc", inner.Left)
  29. }
  30. key, ok := inner.Right.(*LiteralExpr)
  31. if !ok || key.Value != "a" {
  32. t.Fatalf("inner right = %#v, want literal 'a'", inner.Right)
  33. }
  34. }
  35. func TestParseJSONArrowPrecedence(t *testing.T) {
  36. tests := []struct {
  37. name string
  38. input string
  39. root lexer.TokenType
  40. childOp lexer.TokenType
  41. }{
  42. {"concatenation binds looser", "doc -> 'a' || 'x'", lexer.TokenConcat, lexer.TokenArrow},
  43. {"addition binds looser", "doc -> 'a' + 1", lexer.TokenPlus, lexer.TokenArrow},
  44. {"multiplication binds looser", "doc ->> 'a' * 2", lexer.TokenStar, lexer.TokenArrowText},
  45. {"bitwise binds looser", "doc -> 'a' & 1", lexer.TokenBitAnd, lexer.TokenArrow},
  46. {"comparison binds looser", "doc ->> 'a' = 'x'", lexer.TokenEq, lexer.TokenArrowText},
  47. }
  48. for _, tt := range tests {
  49. t.Run(tt.name, func(t *testing.T) {
  50. expr := parseExpr(t, tt.input)
  51. root, ok := expr.(*BinaryExpr)
  52. if !ok {
  53. t.Fatalf("expected *BinaryExpr, got %T", expr)
  54. }
  55. if root.Op != tt.root {
  56. t.Fatalf("root operator = %v, want %v", root.Op, tt.root)
  57. }
  58. child, ok := root.Left.(*BinaryExpr)
  59. if !ok {
  60. t.Fatalf("root left = %T, want *BinaryExpr", root.Left)
  61. }
  62. if child.Op != tt.childOp {
  63. t.Fatalf("left child operator = %v, want %v", child.Op, tt.childOp)
  64. }
  65. })
  66. }
  67. }
  68. func TestParseJSONArrowBindsLooserThanUnary(t *testing.T) {
  69. expr := parseExpr(t, "-doc -> 'a'")
  70. arrow, ok := expr.(*BinaryExpr)
  71. if !ok || arrow.Op != lexer.TokenArrow {
  72. t.Fatalf("expected root ->, got %#v", expr)
  73. }
  74. neg, ok := arrow.Left.(*UnaryExpr)
  75. if !ok || neg.Op != lexer.TokenMinus {
  76. t.Fatalf("arrow left = %#v, want unary minus", arrow.Left)
  77. }
  78. // The right operand may be a negative array index.
  79. expr = parseExpr(t, "doc -> -1")
  80. arrow, ok = expr.(*BinaryExpr)
  81. if !ok || arrow.Op != lexer.TokenArrow {
  82. t.Fatalf("expected root ->, got %#v", expr)
  83. }
  84. neg, ok = arrow.Right.(*UnaryExpr)
  85. if !ok || neg.Op != lexer.TokenMinus {
  86. t.Fatalf("arrow right = %#v, want unary minus", arrow.Right)
  87. }
  88. }
  89. func TestParseJSONArrowRespectsParentheses(t *testing.T) {
  90. expr := parseExpr(t, "(doc -> 'a') ->> 'b'")
  91. outer, ok := expr.(*BinaryExpr)
  92. if !ok || outer.Op != lexer.TokenArrowText {
  93. t.Fatalf("expected root ->>, got %#v", expr)
  94. }
  95. paren, ok := outer.Left.(*ParenExpr)
  96. if !ok {
  97. t.Fatalf("outer left = %T, want *ParenExpr", outer.Left)
  98. }
  99. inner, ok := paren.Expr.(*BinaryExpr)
  100. if !ok || inner.Op != lexer.TokenArrow {
  101. t.Fatalf("parenthesized expression = %#v, want ->", paren.Expr)
  102. }
  103. }