mirror of
https://github.com/pikami/cosmium.git
synced 2026-07-31 10:07:01 +01:00
c78842726b
* Support single-quoted string literals in query parsing
Add single-quoted string literal support to the NoSQL query parser,
matching Cosmos DB behavior where apostrophes are escaped by doubling
them (''). Includes parser unit tests and an API integration test.
Co-authored-by: Pijus Kamandulis <pikami@users.noreply.github.com>
* Use backslash escape for apostrophes in single-quoted strings
Cosmos DB escapes apostrophes with \' rather than SQL-style doubling.
Also fix EscapeCharacter to return proper values for \', \", and \\
which were previously producing empty substitutions.
Co-authored-by: Pijus Kamandulis <pikami@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
195 lines
5.8 KiB
Go
195 lines
5.8 KiB
Go
package nosql_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/pikami/cosmium/parsers"
|
|
testutils "github.com/pikami/cosmium/test_utils"
|
|
)
|
|
|
|
func Test_Parse_Were(t *testing.T) {
|
|
|
|
t.Run("Should parse SELECT with single WHERE condition", func(t *testing.T) {
|
|
testQueryParse(
|
|
t,
|
|
`select c.id
|
|
FROM c
|
|
WHERE c.isCool=true`,
|
|
parsers.SelectStmt{
|
|
SelectItems: []parsers.SelectItem{
|
|
{Path: []string{"c", "id"}},
|
|
},
|
|
Table: parsers.Table{SelectItem: testutils.SelectItem_Path("c")},
|
|
Filters: parsers.ComparisonExpression{
|
|
Operation: "=",
|
|
Left: parsers.SelectItem{Path: []string{"c", "isCool"}},
|
|
Right: testutils.SelectItem_Constant_Bool(true),
|
|
},
|
|
},
|
|
)
|
|
})
|
|
|
|
t.Run("Should parse SELECT with multiple WHERE conditions", func(t *testing.T) {
|
|
testQueryParse(
|
|
t,
|
|
`select c.id, c._self AS self, c._rid, c._ts
|
|
FROM c
|
|
WHERE c.id="12345" OR c.pk=123`,
|
|
parsers.SelectStmt{
|
|
SelectItems: []parsers.SelectItem{
|
|
{Path: []string{"c", "id"}},
|
|
{Path: []string{"c", "_self"}, Alias: "self"},
|
|
{Path: []string{"c", "_rid"}},
|
|
{Path: []string{"c", "_ts"}},
|
|
},
|
|
Table: parsers.Table{SelectItem: testutils.SelectItem_Path("c")},
|
|
Filters: parsers.LogicalExpression{
|
|
Operation: parsers.LogicalExpressionTypeOr,
|
|
Expressions: []interface{}{
|
|
parsers.ComparisonExpression{
|
|
Operation: "=",
|
|
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
|
Right: testutils.SelectItem_Constant_String("12345"),
|
|
},
|
|
parsers.ComparisonExpression{
|
|
Operation: "=",
|
|
Left: parsers.SelectItem{Path: []string{"c", "pk"}},
|
|
Right: testutils.SelectItem_Constant_Int(123),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
)
|
|
})
|
|
|
|
t.Run("Should parse SELECT with grouped WHERE conditions", func(t *testing.T) {
|
|
testQueryParse(
|
|
t,
|
|
`select c.id
|
|
FROM c
|
|
WHERE c.isCool=true AND (c.id = "123" OR c.id <= "456")`,
|
|
parsers.SelectStmt{
|
|
SelectItems: []parsers.SelectItem{
|
|
{Path: []string{"c", "id"}},
|
|
},
|
|
Table: parsers.Table{SelectItem: testutils.SelectItem_Path("c")},
|
|
Filters: parsers.LogicalExpression{
|
|
Operation: parsers.LogicalExpressionTypeAnd,
|
|
Expressions: []interface{}{
|
|
parsers.ComparisonExpression{
|
|
Operation: "=",
|
|
Left: parsers.SelectItem{Path: []string{"c", "isCool"}},
|
|
Right: testutils.SelectItem_Constant_Bool(true),
|
|
},
|
|
parsers.LogicalExpression{
|
|
Operation: parsers.LogicalExpressionTypeOr,
|
|
Expressions: []interface{}{
|
|
parsers.ComparisonExpression{
|
|
Operation: "=",
|
|
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
|
Right: testutils.SelectItem_Constant_String("123"),
|
|
},
|
|
parsers.ComparisonExpression{
|
|
Operation: "<=",
|
|
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
|
Right: testutils.SelectItem_Constant_String("456"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
)
|
|
})
|
|
|
|
t.Run("Should correctly parse literals in conditions", func(t *testing.T) {
|
|
testQueryParse(
|
|
t,
|
|
`select c.id
|
|
FROM c
|
|
WHERE c.boolean=true
|
|
AND c.integer=1
|
|
AND c.float=6.9
|
|
AND c.string="hello"
|
|
AND c.param=@param_id1`,
|
|
parsers.SelectStmt{
|
|
SelectItems: []parsers.SelectItem{{Path: []string{"c", "id"}, Alias: ""}},
|
|
Table: parsers.Table{SelectItem: testutils.SelectItem_Path("c")},
|
|
Filters: parsers.LogicalExpression{
|
|
Expressions: []interface{}{
|
|
parsers.ComparisonExpression{
|
|
Left: parsers.SelectItem{Path: []string{"c", "boolean"}},
|
|
Right: testutils.SelectItem_Constant_Bool(true),
|
|
Operation: "=",
|
|
},
|
|
parsers.ComparisonExpression{
|
|
Left: parsers.SelectItem{Path: []string{"c", "integer"}},
|
|
Right: testutils.SelectItem_Constant_Int(1),
|
|
Operation: "=",
|
|
},
|
|
parsers.ComparisonExpression{
|
|
Left: parsers.SelectItem{Path: []string{"c", "float"}},
|
|
Right: testutils.SelectItem_Constant_Float(6.9),
|
|
Operation: "=",
|
|
},
|
|
parsers.ComparisonExpression{
|
|
Left: parsers.SelectItem{Path: []string{"c", "string"}},
|
|
Right: testutils.SelectItem_Constant_String("hello"),
|
|
Operation: "=",
|
|
},
|
|
parsers.ComparisonExpression{
|
|
Left: parsers.SelectItem{Path: []string{"c", "param"}},
|
|
Right: testutils.SelectItem_Constant_Parameter("@param_id1"),
|
|
Operation: "=",
|
|
},
|
|
},
|
|
Operation: parsers.LogicalExpressionTypeAnd,
|
|
},
|
|
},
|
|
)
|
|
})
|
|
|
|
t.Run("Should correctly parse single-quoted string literals", func(t *testing.T) {
|
|
testQueryParse(
|
|
t,
|
|
`SELECT c.id FROM c WHERE c.id = '12345' AND c.string = 'it\'s'`,
|
|
parsers.SelectStmt{
|
|
SelectItems: []parsers.SelectItem{{Path: []string{"c", "id"}}},
|
|
Table: parsers.Table{SelectItem: testutils.SelectItem_Path("c")},
|
|
Filters: parsers.LogicalExpression{
|
|
Operation: parsers.LogicalExpressionTypeAnd,
|
|
Expressions: []interface{}{
|
|
parsers.ComparisonExpression{
|
|
Operation: "=",
|
|
Left: parsers.SelectItem{Path: []string{"c", "id"}},
|
|
Right: testutils.SelectItem_Constant_String("12345"),
|
|
},
|
|
parsers.ComparisonExpression{
|
|
Operation: "=",
|
|
Left: parsers.SelectItem{Path: []string{"c", "string"}},
|
|
Right: testutils.SelectItem_Constant_String("it's"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
)
|
|
})
|
|
|
|
t.Run("Should correctly parse NOT conditions", func(t *testing.T) {
|
|
testQueryParse(
|
|
t,
|
|
`select c.id
|
|
FROM c
|
|
WHERE NOT c.boolean`,
|
|
parsers.SelectStmt{
|
|
SelectItems: []parsers.SelectItem{{Path: []string{"c", "id"}, Alias: ""}},
|
|
Table: parsers.Table{SelectItem: testutils.SelectItem_Path("c")},
|
|
Filters: parsers.SelectItem{
|
|
Path: []string{"c", "boolean"},
|
|
Invert: true,
|
|
},
|
|
},
|
|
)
|
|
})
|
|
}
|