diff --git a/cel2sql.go b/cel2sql.go
index cb7a486..09485fe 100644
--- a/cel2sql.go
+++ b/cel2sql.go
@@ -486,6 +486,57 @@ func (con *converter) getFieldElementType(tableName, fieldName string) string {
return ""
}
+// getArrayDimension returns the number of array dimensions for a field expression.
+// Returns 1 if no schema information is available (backward compatible default).
+// For multi-dimensional arrays, returns the detected dimension count (2 for int[][], 3 for int[][][], etc.)
+func (con *converter) getArrayDimension(expr *exprpb.Expr) int {
+ // Default to 1D arrays if we can't determine from schema
+ if con.schemas == nil {
+ return 1
+ }
+
+ // Try to extract field name from the select expression
+ selectExpr := expr.GetSelectExpr()
+ if selectExpr == nil {
+ return 1
+ }
+
+ fieldName := selectExpr.GetField()
+ operand := selectExpr.GetOperand()
+
+ // Get the type of the operand from the type map
+ operandType := con.typeMap[operand.GetId()]
+ if operandType == nil {
+ return 1
+ }
+
+ // Extract the type name (e.g., "TestTable" from the object type)
+ typeName := operandType.GetMessageType()
+ if typeName == "" {
+ return 1
+ }
+
+ // Look up the schema by type name
+ schema, ok := con.schemas[typeName]
+ if !ok {
+ return 1
+ }
+
+ // Find the field in the schema
+ field, found := schema.FindField(fieldName)
+ if !found || !field.Repeated {
+ return 1
+ }
+
+ // If dimensions is explicitly set and > 0, use it
+ if field.Dimensions > 0 {
+ return field.Dimensions
+ }
+
+ // Otherwise default to 1
+ return 1
+}
+
func (con *converter) visitCall(expr *exprpb.Expr) error {
// Check for context cancellation before processing function calls
if err := con.checkContext(); err != nil {
@@ -1770,7 +1821,10 @@ func (con *converter) visitCallFunc(expr *exprpb.Expr) error {
con.str.WriteString("), 0)")
return nil
}
- // For PostgreSQL, we need to specify the array dimension (1 for 1D arrays)
+ // For PostgreSQL, we need to specify the array dimension
+ // Detect the dimension from schema if available, otherwise default to 1
+ dimension := con.getArrayDimension(argExpr)
+
// Wrap in COALESCE to handle NULL arrays (ARRAY_LENGTH returns NULL for NULL input)
con.str.WriteString("COALESCE(ARRAY_LENGTH(")
nested := isBinaryOrTernaryOperator(argExpr)
@@ -1778,7 +1832,7 @@ func (con *converter) visitCallFunc(expr *exprpb.Expr) error {
if err != nil {
return err
}
- con.str.WriteString(", 1), 0)")
+ con.str.WriteString(fmt.Sprintf(", %d), 0)", dimension))
return nil
default:
return newConversionErrorf(errMsgUnsupportedType, "size() argument type: %s", argType.String())
diff --git a/multidim_array_test.go b/multidim_array_test.go
new file mode 100644
index 0000000..70d0ac3
--- /dev/null
+++ b/multidim_array_test.go
@@ -0,0 +1,203 @@
+package cel2sql
+
+import (
+ "testing"
+
+ "github.com/google/cel-go/cel"
+ "github.com/spandigital/cel2sql/v3/pg"
+)
+
+// TestMultiDimensionalArrays tests size() function with multi-dimensional arrays
+func TestMultiDimensionalArrays(t *testing.T) {
+ // Create schema with arrays of different dimensions
+ schema := pg.NewSchema([]pg.FieldSchema{
+ {Name: "tags", Type: "text", Repeated: true, Dimensions: 1}, // 1D array
+ {Name: "matrix", Type: "integer", Repeated: true, Dimensions: 2}, // 2D array
+ {Name: "cube", Type: "integer", Repeated: true, Dimensions: 3}, // 3D array
+ {Name: "hypercube", Type: "integer", Repeated: true, Dimensions: 4}, // 4D array
+ {Name: "simple_array", Type: "text", Repeated: true, Dimensions: 0}, // Dimension not set (defaults to 1)
+ {Name: "id", Type: "integer", Repeated: false, Dimensions: 0}, // Not an array
+ })
+
+ provider := pg.NewTypeProvider(map[string]pg.Schema{"TestTable": schema})
+
+ env, err := cel.NewEnv(
+ cel.CustomTypeProvider(provider),
+ cel.Variable("data", cel.ObjectType("TestTable")),
+ )
+ if err != nil {
+ t.Fatalf("failed to create CEL environment: %v", err)
+ }
+
+ tests := []struct {
+ name string
+ cel string
+ expectedSQL string
+ expectedDim int
+ description string
+ }{
+ {
+ name: "1D array size",
+ cel: "size(data.tags) > 0",
+ expectedSQL: "COALESCE(ARRAY_LENGTH(data.tags, 1), 0) > 0",
+ expectedDim: 1,
+ description: "1D array should use dimension 1",
+ },
+ {
+ name: "2D array size",
+ cel: "size(data.matrix) > 0",
+ expectedSQL: "COALESCE(ARRAY_LENGTH(data.matrix, 2), 0) > 0",
+ expectedDim: 2,
+ description: "2D array should use dimension 2",
+ },
+ {
+ name: "3D array size",
+ cel: "size(data.cube) == 5",
+ expectedSQL: "COALESCE(ARRAY_LENGTH(data.cube, 3), 0) = 5",
+ expectedDim: 3,
+ description: "3D array should use dimension 3",
+ },
+ {
+ name: "4D array size",
+ cel: "size(data.hypercube) < 10",
+ expectedSQL: "COALESCE(ARRAY_LENGTH(data.hypercube, 4), 0) < 10",
+ expectedDim: 4,
+ description: "4D array should use dimension 4",
+ },
+ {
+ name: "array with no dimension set defaults to 1",
+ cel: "size(data.simple_array) > 0",
+ expectedSQL: "COALESCE(ARRAY_LENGTH(data.simple_array, 1), 0) > 0",
+ expectedDim: 1,
+ description: "Array with Dimensions=0 should default to dimension 1",
+ },
+ {
+ name: "complex expression with 2D array",
+ cel: "size(data.matrix) >= 3 && size(data.matrix) <= 10",
+ expectedSQL: "COALESCE(ARRAY_LENGTH(data.matrix, 2), 0) >= 3 AND COALESCE(ARRAY_LENGTH(data.matrix, 2), 0) <= 10",
+ expectedDim: 2,
+ description: "Complex expressions should maintain correct dimension",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ ast, issues := env.Compile(tt.cel)
+ if issues != nil && issues.Err() != nil {
+ t.Fatalf("failed to compile CEL: %v", issues.Err())
+ }
+
+ sql, err := Convert(ast, WithSchemas(map[string]pg.Schema{"TestTable": schema}))
+ if err != nil {
+ t.Fatalf("failed to convert to SQL: %v", err)
+ }
+
+ if sql != tt.expectedSQL {
+ t.Errorf("unexpected SQL for %s:\n got: %s\n want: %s", tt.description, sql, tt.expectedSQL)
+ }
+
+ t.Logf("✓ %s: ARRAY_LENGTH(..., %d)", tt.description, tt.expectedDim)
+ })
+ }
+}
+
+// TestMultiDimensionalArrayBackwardCompatibility ensures that existing 1D array behavior is preserved
+func TestMultiDimensionalArrayBackwardCompatibility(t *testing.T) {
+ tests := []struct {
+ name string
+ cel string
+ expectedSQL string
+ }{
+ {
+ name: "size without schema - defaults to 1D",
+ cel: "size(string_list) > 0",
+ expectedSQL: "COALESCE(ARRAY_LENGTH(string_list, 1), 0) > 0",
+ },
+ {
+ name: "size in complex expression - defaults to 1D",
+ cel: "size(items) >= 2 && size(items) <= 5",
+ expectedSQL: "COALESCE(ARRAY_LENGTH(items, 1), 0) >= 2 AND COALESCE(ARRAY_LENGTH(items, 1), 0) <= 5",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ // Create environment with variables declared but no schema
+ env, err := cel.NewEnv(
+ cel.Variable("string_list", cel.ListType(cel.StringType)),
+ cel.Variable("items", cel.ListType(cel.IntType)),
+ )
+ if err != nil {
+ t.Fatalf("failed to create CEL environment: %v", err)
+ }
+
+ ast, issues := env.Compile(tt.cel)
+ if issues != nil && issues.Err() != nil {
+ t.Fatalf("failed to compile CEL: %v", issues.Err())
+ }
+
+ // Convert WITHOUT providing schema - should default to dimension 1
+ sql, err := Convert(ast)
+ if err != nil {
+ t.Fatalf("failed to convert to SQL: %v", err)
+ }
+
+ if sql != tt.expectedSQL {
+ t.Errorf("backward compatibility failed:\n got: %s\n want: %s", sql, tt.expectedSQL)
+ }
+
+ t.Logf("✓ Backward compatible: defaults to dimension 1 when no schema")
+ })
+ }
+}
+
+// TestExplicitDimensionOverridesDefault tests that explicitly setting Dimensions to 1 works correctly
+func TestExplicitDimensionOverridesDefault(t *testing.T) {
+ // Schema with explicitly set Dimensions=1
+ schemaExplicit := pg.NewSchema([]pg.FieldSchema{
+ {Name: "tags", Type: "text", Repeated: true, Dimensions: 1},
+ })
+
+ // Schema with Dimensions=0 (not set, should use 1 as default)
+ schemaImplicit := pg.NewSchema([]pg.FieldSchema{
+ {Name: "tags", Type: "text", Repeated: true, Dimensions: 0},
+ })
+
+ provider1 := pg.NewTypeProvider(map[string]pg.Schema{"TestTable": schemaExplicit})
+ provider2 := pg.NewTypeProvider(map[string]pg.Schema{"TestTable": schemaImplicit})
+
+ env1, _ := cel.NewEnv(
+ cel.CustomTypeProvider(provider1),
+ cel.Variable("data", cel.ObjectType("TestTable")),
+ )
+
+ env2, _ := cel.NewEnv(
+ cel.CustomTypeProvider(provider2),
+ cel.Variable("data", cel.ObjectType("TestTable")),
+ )
+
+ celExpr := "size(data.tags) > 0"
+ expectedSQL := "COALESCE(ARRAY_LENGTH(data.tags, 1), 0) > 0"
+
+ // Test with explicit Dimensions=1
+ ast1, _ := env1.Compile(celExpr)
+ sql1, err := Convert(ast1, WithSchemas(map[string]pg.Schema{"TestTable": schemaExplicit}))
+ if err != nil {
+ t.Fatalf("failed with explicit dimension: %v", err)
+ }
+ if sql1 != expectedSQL {
+ t.Errorf("explicit Dimensions=1 failed:\n got: %s\n want: %s", sql1, expectedSQL)
+ }
+
+ // Test with implicit Dimensions=0 (should default to 1)
+ ast2, _ := env2.Compile(celExpr)
+ sql2, err := Convert(ast2, WithSchemas(map[string]pg.Schema{"TestTable": schemaImplicit}))
+ if err != nil {
+ t.Fatalf("failed with implicit dimension: %v", err)
+ }
+ if sql2 != expectedSQL {
+ t.Errorf("implicit Dimensions=0 (default) failed:\n got: %s\n want: %s", sql2, expectedSQL)
+ }
+
+ t.Log("✓ Both explicit Dimensions=1 and implicit Dimensions=0 default to dimension 1")
+}
diff --git a/pg/dimension_detection_test.go b/pg/dimension_detection_test.go
new file mode 100644
index 0000000..5d7130e
--- /dev/null
+++ b/pg/dimension_detection_test.go
@@ -0,0 +1,249 @@
+package pg
+
+import "testing"
+
+// TestDetectArrayDimensions tests the detectArrayDimensions function with various PostgreSQL type strings
+func TestDetectArrayDimensions(t *testing.T) {
+ tests := []struct {
+ name string
+ pgType string
+ expected int
+ }{
+ // Non-array types
+ {
+ name: "scalar integer",
+ pgType: "integer",
+ expected: 0,
+ },
+ {
+ name: "scalar text",
+ pgType: "text",
+ expected: 0,
+ },
+ {
+ name: "scalar int4",
+ pgType: "int4",
+ expected: 0,
+ },
+ {
+ name: "empty string",
+ pgType: "",
+ expected: 0,
+ },
+
+ // 1D arrays - bracket notation
+ {
+ name: "integer[] - 1D array",
+ pgType: "integer[]",
+ expected: 1,
+ },
+ {
+ name: "text[] - 1D array",
+ pgType: "text[]",
+ expected: 1,
+ },
+ {
+ name: "varchar[] - 1D array",
+ pgType: "varchar[]",
+ expected: 1,
+ },
+
+ // 1D arrays - underscore notation
+ {
+ name: "_int4 - 1D array (underscore notation)",
+ pgType: "_int4",
+ expected: 1,
+ },
+ {
+ name: "_text - 1D array (underscore notation)",
+ pgType: "_text",
+ expected: 1,
+ },
+ {
+ name: "_varchar - 1D array (underscore notation)",
+ pgType: "_varchar",
+ expected: 1,
+ },
+ {
+ name: "_int8 - 1D array (bigint)",
+ pgType: "_int8",
+ expected: 1,
+ },
+
+ // 2D arrays
+ {
+ name: "integer[][] - 2D array",
+ pgType: "integer[][]",
+ expected: 2,
+ },
+ {
+ name: "text[][] - 2D array",
+ pgType: "text[][]",
+ expected: 2,
+ },
+ {
+ name: "_int4[] - 2D array (underscore + bracket)",
+ pgType: "_int4[]",
+ expected: 2,
+ },
+ {
+ name: "_text[] - 2D array (underscore + bracket)",
+ pgType: "_text[]",
+ expected: 2,
+ },
+
+ // 3D arrays
+ {
+ name: "integer[][][] - 3D array",
+ pgType: "integer[][][]",
+ expected: 3,
+ },
+ {
+ name: "text[][][] - 3D array",
+ pgType: "text[][][]",
+ expected: 3,
+ },
+ {
+ name: "_int4[][] - 3D array (underscore + 2 brackets)",
+ pgType: "_int4[][]",
+ expected: 3,
+ },
+
+ // 4D arrays (edge case)
+ {
+ name: "integer[][][][] - 4D array",
+ pgType: "integer[][][][]",
+ expected: 4,
+ },
+
+ // Edge cases
+ {
+ name: "just underscore",
+ pgType: "_",
+ expected: 1, // Underscore prefix = 1D array
+ },
+ {
+ name: "underscore with number",
+ pgType: "_123",
+ expected: 1,
+ },
+ {
+ name: "brackets in middle (invalid but should handle gracefully)",
+ pgType: "int[]eger",
+ expected: 0, // Won't match trailing [] pattern
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ result := detectArrayDimensions(tt.pgType)
+ if result != tt.expected {
+ t.Errorf("detectArrayDimensions(%q) = %d, expected %d", tt.pgType, result, tt.expected)
+ }
+ })
+ }
+}
+
+// TestFieldSchemaWithDimensions tests that FieldSchema properly stores dimension information
+func TestFieldSchemaWithDimensions(t *testing.T) {
+ tests := []struct {
+ name string
+ field FieldSchema
+ wantDims int
+ wantRepeat bool
+ }{
+ {
+ name: "1D array",
+ field: FieldSchema{
+ Name: "tags",
+ Type: "text",
+ Repeated: true,
+ Dimensions: 1,
+ },
+ wantDims: 1,
+ wantRepeat: true,
+ },
+ {
+ name: "2D array",
+ field: FieldSchema{
+ Name: "matrix",
+ Type: "integer",
+ Repeated: true,
+ Dimensions: 2,
+ },
+ wantDims: 2,
+ wantRepeat: true,
+ },
+ {
+ name: "3D array",
+ field: FieldSchema{
+ Name: "cube",
+ Type: "double precision",
+ Repeated: true,
+ Dimensions: 3,
+ },
+ wantDims: 3,
+ wantRepeat: true,
+ },
+ {
+ name: "scalar field",
+ field: FieldSchema{
+ Name: "id",
+ Type: "integer",
+ Repeated: false,
+ Dimensions: 0,
+ },
+ wantDims: 0,
+ wantRepeat: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if tt.field.Dimensions != tt.wantDims {
+ t.Errorf("field.Dimensions = %d, expected %d", tt.field.Dimensions, tt.wantDims)
+ }
+ if tt.field.Repeated != tt.wantRepeat {
+ t.Errorf("field.Repeated = %v, expected %v", tt.field.Repeated, tt.wantRepeat)
+ }
+ })
+ }
+}
+
+// TestSchemaWithMultiDimensionalArrays tests that Schema properly handles fields with various dimensions
+func TestSchemaWithMultiDimensionalArrays(t *testing.T) {
+ fields := []FieldSchema{
+ {Name: "id", Type: "integer", Repeated: false, Dimensions: 0},
+ {Name: "tags", Type: "text", Repeated: true, Dimensions: 1},
+ {Name: "matrix", Type: "integer", Repeated: true, Dimensions: 2},
+ {Name: "cube", Type: "float", Repeated: true, Dimensions: 3},
+ }
+
+ schema := NewSchema(fields)
+
+ // Test that we can find each field
+ tests := []struct {
+ fieldName string
+ wantDims int
+ wantFound bool
+ }{
+ {"id", 0, true},
+ {"tags", 1, true},
+ {"matrix", 2, true},
+ {"cube", 3, true},
+ {"nonexistent", 0, false},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.fieldName, func(t *testing.T) {
+ field, found := schema.FindField(tt.fieldName)
+ if found != tt.wantFound {
+ t.Errorf("FindField(%q) found = %v, expected %v", tt.fieldName, found, tt.wantFound)
+ return
+ }
+ if found && field.Dimensions != tt.wantDims {
+ t.Errorf("field %q dimensions = %d, expected %d", tt.fieldName, field.Dimensions, tt.wantDims)
+ }
+ })
+ }
+}
diff --git a/pg/provider.go b/pg/provider.go
index 3ef63c3..f48565b 100644
--- a/pg/provider.go
+++ b/pg/provider.go
@@ -41,6 +41,7 @@ type FieldSchema struct {
Name string
Type string // PostgreSQL type name (text, integer, boolean, etc.)
Repeated bool // true for arrays
+ Dimensions int // number of array dimensions (1 for integer[], 2 for integer[][], etc.)
Schema []FieldSchema // for composite types
IsJSON bool // true for json/jsonb types
IsJSONB bool // true for jsonb (vs json)
@@ -153,23 +154,24 @@ func (p *typeProvider) LoadTableSchema(ctx context.Context, tableName string) er
}
query := `
- SELECT
- column_name,
- data_type,
- is_nullable,
+ SELECT
+ column_name,
+ data_type,
+ is_nullable,
column_default,
- CASE
- WHEN data_type = 'ARRAY' THEN
- (SELECT data_type FROM information_schema.element_types
- WHERE object_name = $1
+ CASE
+ WHEN data_type = 'ARRAY' THEN
+ (SELECT data_type FROM information_schema.element_types
+ WHERE object_name = $1
AND collection_type_identifier = (
- SELECT dtd_identifier FROM information_schema.columns
+ SELECT dtd_identifier FROM information_schema.columns
WHERE table_name = $1 AND column_name = c.column_name
))
ELSE data_type
- END as element_type
+ END as element_type,
+ udt_name
FROM information_schema.columns c
- WHERE table_name = $1
+ WHERE table_name = $1
ORDER BY ordinal_position
`
@@ -183,9 +185,9 @@ func (p *typeProvider) LoadTableSchema(ctx context.Context, tableName string) er
for rows.Next() {
var columnName, dataType, isNullable string
var columnDefault *string
- var elementType string
+ var elementType, udtName string
- err := rows.Scan(&columnName, &dataType, &isNullable, &columnDefault, &elementType)
+ err := rows.Scan(&columnName, &dataType, &isNullable, &columnDefault, &elementType, &udtName)
if err != nil {
return fmt.Errorf("%w: failed to scan row: %w", ErrInvalidSchema, err)
}
@@ -194,10 +196,18 @@ func (p *typeProvider) LoadTableSchema(ctx context.Context, tableName string) er
isJSON := elementType == typeJSON || elementType == typeJSONB
isJSONB := elementType == typeJSONB
+ // Detect array dimensions from UDT name (e.g., _int4 = 1D, _int4[] = 2D)
+ dimensions := detectArrayDimensions(udtName)
+ if dimensions == 0 && isArray {
+ // Fallback: if data_type says ARRAY but we didn't detect dimensions, assume 1D
+ dimensions = 1
+ }
+
field := FieldSchema{
Name: columnName,
Type: elementType, // Use element type for arrays, or data_type for non-arrays
Repeated: isArray,
+ Dimensions: dimensions,
IsJSON: isJSON,
IsJSONB: isJSONB,
ElementType: "", // Will be set below for arrays
@@ -226,6 +236,36 @@ func (p *typeProvider) Close() {
}
}
+// detectArrayDimensions detects the number of array dimensions from a PostgreSQL type string.
+// Examples:
+// - "integer" -> 0 (not an array)
+// - "integer[]" or "_int4" -> 1 (1D array)
+// - "integer[][]" or "_int4[]" -> 2 (2D array)
+// - "integer[][][]" -> 3 (3D array)
+func detectArrayDimensions(pgType string) int {
+ if pgType == "" {
+ return 0
+ }
+
+ // Count trailing [] pairs
+ dimensions := 0
+ for i := len(pgType) - 1; i >= 1; i -= 2 {
+ if pgType[i] == ']' && pgType[i-1] == '[' {
+ dimensions++
+ } else {
+ break
+ }
+ }
+
+ // PostgreSQL also uses underscore prefix for arrays (e.g., _int4 for integer[])
+ // Underscore adds 1 dimension, so _int4 = 1D, _int4[] = 2D, _int4[][] = 3D
+ if len(pgType) > 0 && pgType[0] == '_' {
+ dimensions++
+ }
+
+ return dimensions
+}
+
// GetSchemas returns the schema map
func (p *typeProvider) GetSchemas() map[string]Schema {
return p.schemas
diff --git a/test_output.txt b/test_output.txt
new file mode 100644
index 0000000..a144597
--- /dev/null
+++ b/test_output.txt
@@ -0,0 +1,3547 @@
+go test -v -race -coverprofile=coverage.out -covermode=atomic ./...
+=== RUN TestAnalyzeQuery_JSONPathOperations
+=== RUN TestAnalyzeQuery_JSONPathOperations/simple_JSON_path_access
+=== RUN TestAnalyzeQuery_JSONPathOperations/nested_JSON_path_access
+--- PASS: TestAnalyzeQuery_JSONPathOperations (0.00s)
+ --- PASS: TestAnalyzeQuery_JSONPathOperations/simple_JSON_path_access (0.00s)
+ --- PASS: TestAnalyzeQuery_JSONPathOperations/nested_JSON_path_access (0.00s)
+=== RUN TestAnalyzeQuery_RegexOperations
+--- PASS: TestAnalyzeQuery_RegexOperations (0.00s)
+=== RUN TestAnalyzeQuery_ComparisonOperations
+=== RUN TestAnalyzeQuery_ComparisonOperations/equality_comparison
+=== RUN TestAnalyzeQuery_ComparisonOperations/range_comparison
+=== RUN TestAnalyzeQuery_ComparisonOperations/less_than_comparison
+--- PASS: TestAnalyzeQuery_ComparisonOperations (0.00s)
+ --- PASS: TestAnalyzeQuery_ComparisonOperations/equality_comparison (0.00s)
+ --- PASS: TestAnalyzeQuery_ComparisonOperations/range_comparison (0.00s)
+ --- PASS: TestAnalyzeQuery_ComparisonOperations/less_than_comparison (0.00s)
+=== RUN TestAnalyzeQuery_ArrayOperations
+--- PASS: TestAnalyzeQuery_ArrayOperations (0.00s)
+=== RUN TestAnalyzeQuery_Comprehensions
+=== RUN TestAnalyzeQuery_Comprehensions/all_comprehension
+=== RUN TestAnalyzeQuery_Comprehensions/exists_comprehension
+=== RUN TestAnalyzeQuery_Comprehensions/map_comprehension
+--- PASS: TestAnalyzeQuery_Comprehensions (0.00s)
+ --- PASS: TestAnalyzeQuery_Comprehensions/all_comprehension (0.00s)
+ --- PASS: TestAnalyzeQuery_Comprehensions/exists_comprehension (0.00s)
+ --- PASS: TestAnalyzeQuery_Comprehensions/map_comprehension (0.00s)
+=== RUN TestAnalyzeQuery_MultipleRecommendations
+--- PASS: TestAnalyzeQuery_MultipleRecommendations (0.00s)
+=== RUN TestAnalyzeQuery_NoRecommendations
+--- PASS: TestAnalyzeQuery_NoRecommendations (0.00s)
+=== RUN TestAnalyzeQuery_WithContext
+--- PASS: TestAnalyzeQuery_WithContext (0.00s)
+=== RUN TestAnalyzeQuery_IndexRecommendationPriority
+--- PASS: TestAnalyzeQuery_IndexRecommendationPriority (0.00s)
+=== RUN TestByteArraySmallValues
+=== RUN TestByteArraySmallValues/single_byte
+=== RUN TestByteArraySmallValues/two_bytes
+=== RUN TestByteArraySmallValues/four_bytes
+--- PASS: TestByteArraySmallValues (0.00s)
+ --- PASS: TestByteArraySmallValues/single_byte (0.00s)
+ --- PASS: TestByteArraySmallValues/two_bytes (0.00s)
+ --- PASS: TestByteArraySmallValues/four_bytes (0.00s)
+=== RUN TestByteArrayMaxLengthConstant
+--- PASS: TestByteArrayMaxLengthConstant (0.00s)
+=== RUN TestByteArrayParameterizedMode
+--- PASS: TestByteArrayParameterizedMode (0.00s)
+=== RUN TestByteArrayValidation
+--- PASS: TestByteArrayValidation (0.00s)
+=== RUN TestByteArrayHexEncoding
+=== RUN TestByteArrayHexEncoding/ascii_string
+=== RUN TestByteArrayHexEncoding/numeric_string
+=== RUN TestByteArrayHexEncoding/mixed_string
+--- PASS: TestByteArrayHexEncoding (0.00s)
+ --- PASS: TestByteArrayHexEncoding/ascii_string (0.00s)
+ --- PASS: TestByteArrayHexEncoding/numeric_string (0.00s)
+ --- PASS: TestByteArrayHexEncoding/mixed_string (0.00s)
+=== RUN TestByteArrayInOperations
+=== RUN TestByteArrayInOperations/byte_equality
+=== RUN TestByteArrayInOperations/byte_inequality
+=== RUN TestByteArrayInOperations/byte_with_AND
+=== RUN TestByteArrayInOperations/byte_with_OR
+--- PASS: TestByteArrayInOperations (0.00s)
+ --- PASS: TestByteArrayInOperations/byte_equality (0.00s)
+ --- PASS: TestByteArrayInOperations/byte_inequality (0.00s)
+ --- PASS: TestByteArrayInOperations/byte_with_AND (0.00s)
+ --- PASS: TestByteArrayInOperations/byte_with_OR (0.00s)
+=== RUN TestByteArrayLengthProtection
+ byte_array_test.go:238: Byte array length protection is active
+ byte_array_test.go:239: Limit: 10,000 bytes
+ byte_array_test.go:240: Error format: 'byte array exceeds maximum length of 10000 bytes (got N bytes)'
+--- PASS: TestByteArrayLengthProtection (0.00s)
+=== RUN TestByteArrayErrorMessage
+--- PASS: TestByteArrayErrorMessage (0.00s)
+=== RUN TestByteArrayDocumentation
+ byte_array_test.go:258: === Byte Array Length Limits ===
+ byte_array_test.go:259: Purpose: Prevent resource exhaustion from large hex-encoded SQL strings
+ byte_array_test.go:260: Limit: 10,000 bytes maximum
+ byte_array_test.go:261: Rationale: Each byte expands to ~4 characters in hex format
+ byte_array_test.go:262: - 10,000 bytes → ~40KB SQL output
+ byte_array_test.go:263: - 100,000 bytes → ~400KB SQL output (prevented)
+ byte_array_test.go:264:
+ byte_array_test.go:265: Protection applies to:
+ byte_array_test.go:266: - Non-parameterized mode (Convert)
+ byte_array_test.go:267:
+ byte_array_test.go:268: Protection does NOT apply to:
+ byte_array_test.go:269: - Parameterized mode (ConvertParameterized)
+ byte_array_test.go:270: Bytes are passed directly to database driver
+ byte_array_test.go:271:
+ byte_array_test.go:272: Related security features:
+ byte_array_test.go:273: - maxComprehensionDepth = 3
+ byte_array_test.go:274: - defaultMaxRecursionDepth = 100
+ byte_array_test.go:275: - defaultMaxSQLOutputLength = 50,000
+ byte_array_test.go:276:
+ byte_array_test.go:277: Security context: CWE-400 (Uncontrolled Resource Consumption)
+--- PASS: TestByteArrayDocumentation (0.00s)
+=== RUN TestByteArrayWithSchemas
+=== RUN TestByteArrayWithSchemas/bytea_comparison
+=== RUN TestByteArrayWithSchemas/uuid_comparison
+--- PASS: TestByteArrayWithSchemas (0.00s)
+ --- PASS: TestByteArrayWithSchemas/bytea_comparison (0.00s)
+ --- PASS: TestByteArrayWithSchemas/uuid_comparison (0.00s)
+=== RUN TestByteArrayEmptyValue
+--- PASS: TestByteArrayEmptyValue (0.00s)
+=== RUN TestByteArraySpecialCharacters
+=== RUN TestByteArraySpecialCharacters/null_bytes
+=== RUN TestByteArraySpecialCharacters/max_bytes
+=== RUN TestByteArraySpecialCharacters/mixed_values
+--- PASS: TestByteArraySpecialCharacters (0.00s)
+ --- PASS: TestByteArraySpecialCharacters/null_bytes (0.00s)
+ --- PASS: TestByteArraySpecialCharacters/max_bytes (0.00s)
+ --- PASS: TestByteArraySpecialCharacters/mixed_values (0.00s)
+=== RUN TestComprehensionPatternDetectionOrder
+=== RUN TestComprehensionPatternDetectionOrder/map_with_identity_transform_looks_different_from_filter
+ comprehensions_edge_cases_test.go:98: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+=== RUN TestComprehensionPatternDetectionOrder/filter_with_simple_predicate
+ comprehensions_edge_cases_test.go:92: wrong comprehension type detected: got map, want filter
+ comprehensions_edge_cases_test.go:98: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+=== RUN TestComprehensionPatternDetectionOrder/all_with_multiple_AND_conditions
+ comprehensions_edge_cases_test.go:98: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+=== RUN TestComprehensionPatternDetectionOrder/exists_with_multiple_OR_conditions
+ comprehensions_edge_cases_test.go:98: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+=== RUN TestComprehensionPatternDetectionOrder/exists_one_with_complex_predicate
+ comprehensions_edge_cases_test.go:98: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+--- FAIL: TestComprehensionPatternDetectionOrder (0.00s)
+ --- FAIL: TestComprehensionPatternDetectionOrder/map_with_identity_transform_looks_different_from_filter (0.00s)
+ --- FAIL: TestComprehensionPatternDetectionOrder/filter_with_simple_predicate (0.00s)
+ --- FAIL: TestComprehensionPatternDetectionOrder/all_with_multiple_AND_conditions (0.00s)
+ --- FAIL: TestComprehensionPatternDetectionOrder/exists_with_multiple_OR_conditions (0.00s)
+ --- FAIL: TestComprehensionPatternDetectionOrder/exists_one_with_complex_predicate (0.00s)
+=== RUN TestComprehensionWithComplexNestedExpressions
+=== RUN TestComprehensionWithComplexNestedExpressions/map_with_nested_ternary_transform
+ comprehensions_edge_cases_test.go:156: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+=== RUN TestComprehensionWithComplexNestedExpressions/filter_with_nested_logical_expression
+ comprehensions_edge_cases_test.go:156: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+=== RUN TestComprehensionWithComplexNestedExpressions/all_with_nested_parentheses
+ comprehensions_edge_cases_test.go:156: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+--- FAIL: TestComprehensionWithComplexNestedExpressions (0.00s)
+ --- FAIL: TestComprehensionWithComplexNestedExpressions/map_with_nested_ternary_transform (0.00s)
+ --- FAIL: TestComprehensionWithComplexNestedExpressions/filter_with_nested_logical_expression (0.00s)
+ --- FAIL: TestComprehensionWithComplexNestedExpressions/all_with_nested_parentheses (0.00s)
+=== RUN TestComprehensionEdgeCasesWithEmptyLists
+=== RUN TestComprehensionEdgeCasesWithEmptyLists/all_on_potentially_empty_list
+ comprehensions_edge_cases_test.go:218: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+=== RUN TestComprehensionEdgeCasesWithEmptyLists/exists_on_potentially_empty_list
+ comprehensions_edge_cases_test.go:218: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+=== RUN TestComprehensionEdgeCasesWithEmptyLists/filter_on_potentially_empty_list
+ comprehensions_edge_cases_test.go:218: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+=== RUN TestComprehensionEdgeCasesWithEmptyLists/map_on_potentially_empty_list
+ comprehensions_edge_cases_test.go:218: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+--- FAIL: TestComprehensionEdgeCasesWithEmptyLists (0.00s)
+ --- FAIL: TestComprehensionEdgeCasesWithEmptyLists/all_on_potentially_empty_list (0.00s)
+ --- FAIL: TestComprehensionEdgeCasesWithEmptyLists/exists_on_potentially_empty_list (0.00s)
+ --- FAIL: TestComprehensionEdgeCasesWithEmptyLists/filter_on_potentially_empty_list (0.00s)
+ --- FAIL: TestComprehensionEdgeCasesWithEmptyLists/map_on_potentially_empty_list (0.00s)
+=== RUN TestComprehensionWithChainedOperations
+=== RUN TestComprehensionWithChainedOperations/filter_then_map_(chained)
+ comprehensions_edge_cases_test.go:280: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+=== RUN TestComprehensionWithChainedOperations/map_then_filter_(chained)
+ comprehensions_edge_cases_test.go:280: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+=== RUN TestComprehensionWithChainedOperations/exists_with_negation
+ comprehensions_edge_cases_test.go:280: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+=== RUN TestComprehensionWithChainedOperations/all_with_negation
+ comprehensions_edge_cases_test.go:280: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+--- FAIL: TestComprehensionWithChainedOperations (0.00s)
+ --- FAIL: TestComprehensionWithChainedOperations/filter_then_map_(chained) (0.00s)
+ --- FAIL: TestComprehensionWithChainedOperations/map_then_filter_(chained) (0.00s)
+ --- FAIL: TestComprehensionWithChainedOperations/exists_with_negation (0.00s)
+ --- FAIL: TestComprehensionWithChainedOperations/all_with_negation (0.00s)
+=== RUN TestComprehensionWithVariableNameEdgeCases
+=== RUN TestComprehensionWithVariableNameEdgeCases/single_letter_variable_name
+ comprehensions_edge_cases_test.go:337: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+=== RUN TestComprehensionWithVariableNameEdgeCases/longer_variable_name
+ comprehensions_edge_cases_test.go:337: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+=== RUN TestComprehensionWithVariableNameEdgeCases/underscore_in_variable_name
+ comprehensions_edge_cases_test.go:337: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+--- FAIL: TestComprehensionWithVariableNameEdgeCases (0.00s)
+ --- FAIL: TestComprehensionWithVariableNameEdgeCases/single_letter_variable_name (0.00s)
+ --- FAIL: TestComprehensionWithVariableNameEdgeCases/longer_variable_name (0.00s)
+ --- FAIL: TestComprehensionWithVariableNameEdgeCases/underscore_in_variable_name (0.00s)
+=== RUN TestComprehensionWithMapFilter
+=== RUN TestComprehensionWithMapFilter/map_with_filter_-_CEL_syntax
+ comprehensions_edge_cases_test.go:393: failed to compile CEL: ERROR: :1:18: found no matching overload for '_?_:_' applied to '(int, list(bool), list(bool))'
+ | table.numbers.map(x, x * 2, x > 0)
+ | .................^
+=== RUN TestComprehensionWithMapFilter/regular_map_without_filter
+ comprehensions_edge_cases_test.go:420: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+=== RUN TestComprehensionWithMapFilter/regular_filter
+ comprehensions_edge_cases_test.go:414: wrong comprehension type: got map, want filter
+ comprehensions_edge_cases_test.go:420: failed to convert to SQL: invalid field name: invalid field name: field name "table" is a reserved SQL keyword and cannot be used without quoting
+--- FAIL: TestComprehensionWithMapFilter (0.00s)
+ --- FAIL: TestComprehensionWithMapFilter/map_with_filter_-_CEL_syntax (0.00s)
+ --- FAIL: TestComprehensionWithMapFilter/regular_map_without_filter (0.00s)
+ --- FAIL: TestComprehensionWithMapFilter/regular_filter (0.00s)
+=== RUN TestMaxSQLOutputLength
+=== RUN TestMaxSQLOutputLength/within_default_limit_-_simple_expression
+=== RUN TestMaxSQLOutputLength/within_custom_limit_-_small
+=== RUN TestMaxSQLOutputLength/exceeds_custom_limit_-_moderate_expression
+=== RUN TestMaxSQLOutputLength/large_array_literal_within_limit
+=== RUN TestMaxSQLOutputLength/very_large_expression_exceeds_default_limit
+=== RUN TestMaxSQLOutputLength/high_custom_limit_allows_large_expression
+--- PASS: TestMaxSQLOutputLength (0.76s)
+ --- PASS: TestMaxSQLOutputLength/within_default_limit_-_simple_expression (0.00s)
+ --- PASS: TestMaxSQLOutputLength/within_custom_limit_-_small (0.00s)
+ --- PASS: TestMaxSQLOutputLength/exceeds_custom_limit_-_moderate_expression (0.00s)
+ --- PASS: TestMaxSQLOutputLength/large_array_literal_within_limit (0.01s)
+ --- PASS: TestMaxSQLOutputLength/very_large_expression_exceeds_default_limit (0.69s)
+ --- PASS: TestMaxSQLOutputLength/high_custom_limit_allows_large_expression (0.06s)
+=== RUN TestMaxOutputLengthWithOtherOptions
+=== RUN TestMaxOutputLengthWithOtherOptions/all_options_together
+time=2025-10-31T08:26:15.933+02:00 level=DEBUG msg="starting CEL to SQL conversion"
+time=2025-10-31T08:26:15.933+02:00 level=DEBUG msg="binary operator conversion" cel_op=_>_ sql_op=>
+time=2025-10-31T08:26:15.933+02:00 level=DEBUG msg="binary operator conversion" cel_op=_&&_ sql_op=AND
+time=2025-10-31T08:26:15.933+02:00 level=DEBUG msg="binary operator conversion" cel_op="_==_" sql_op="="
+time=2025-10-31T08:26:15.933+02:00 level=DEBUG msg="conversion completed" sql="x > 5 AND name = 'test'" duration=239.334µs
+=== RUN TestMaxOutputLengthWithOtherOptions/maxOutputLength_with_context
+=== RUN TestMaxOutputLengthWithOtherOptions/maxOutputLength_with_schemas
+=== RUN TestMaxOutputLengthWithOtherOptions/maxOutputLength_with_maxDepth
+--- PASS: TestMaxOutputLengthWithOtherOptions (0.00s)
+ --- PASS: TestMaxOutputLengthWithOtherOptions/all_options_together (0.00s)
+ --- PASS: TestMaxOutputLengthWithOtherOptions/maxOutputLength_with_context (0.00s)
+ --- PASS: TestMaxOutputLengthWithOtherOptions/maxOutputLength_with_schemas (0.00s)
+ --- PASS: TestMaxOutputLengthWithOtherOptions/maxOutputLength_with_maxDepth (0.00s)
+=== RUN TestOutputLengthErrorMessage
+--- PASS: TestOutputLengthErrorMessage (0.73s)
+=== RUN TestOutputLengthResetBetweenCalls
+--- PASS: TestOutputLengthResetBetweenCalls (0.07s)
+=== RUN TestLargeArrayLiterals
+=== RUN TestLargeArrayLiterals/small_array_within_limit
+=== RUN TestLargeArrayLiterals/medium_array_within_limit
+=== RUN TestLargeArrayLiterals/large_array_within_limit
+=== RUN TestLargeArrayLiterals/huge_array_exceeds_limit
+=== RUN TestLargeArrayLiterals/array_exceeds_custom_low_limit
+--- PASS: TestLargeArrayLiterals (1.15s)
+ --- PASS: TestLargeArrayLiterals/small_array_within_limit (0.00s)
+ --- PASS: TestLargeArrayLiterals/medium_array_within_limit (0.01s)
+ --- PASS: TestLargeArrayLiterals/large_array_within_limit (0.05s)
+ --- PASS: TestLargeArrayLiterals/huge_array_exceeds_limit (1.09s)
+ --- PASS: TestLargeArrayLiterals/array_exceeds_custom_low_limit (0.00s)
+=== RUN TestLongStringConcatenations
+=== RUN TestLongStringConcatenations/small_concatenation
+=== RUN TestLongStringConcatenations/medium_concatenation
+=== RUN TestLongStringConcatenations/large_concatenation_within_limit
+=== RUN TestLongStringConcatenations/very_large_concatenation_exceeds_default
+=== RUN TestLongStringConcatenations/concatenation_exceeds_custom_limit
+--- PASS: TestLongStringConcatenations (0.01s)
+ --- PASS: TestLongStringConcatenations/small_concatenation (0.00s)
+ --- PASS: TestLongStringConcatenations/medium_concatenation (0.00s)
+ --- PASS: TestLongStringConcatenations/large_concatenation_within_limit (0.00s)
+ --- PASS: TestLongStringConcatenations/very_large_concatenation_exceeds_default (0.01s)
+ --- PASS: TestLongStringConcatenations/concatenation_exceeds_custom_limit (0.00s)
+=== RUN TestMaxOutputLengthWithComprehensions
+=== RUN TestMaxOutputLengthWithComprehensions/simple_all_comprehension
+=== RUN TestMaxOutputLengthWithComprehensions/simple_exists_comprehension
+=== RUN TestMaxOutputLengthWithComprehensions/comprehension_with_low_custom_limit
+=== RUN TestMaxOutputLengthWithComprehensions/nested_comprehension
+--- PASS: TestMaxOutputLengthWithComprehensions (0.00s)
+ --- PASS: TestMaxOutputLengthWithComprehensions/simple_all_comprehension (0.00s)
+ --- PASS: TestMaxOutputLengthWithComprehensions/simple_exists_comprehension (0.00s)
+ --- PASS: TestMaxOutputLengthWithComprehensions/comprehension_with_low_custom_limit (0.00s)
+ --- PASS: TestMaxOutputLengthWithComprehensions/nested_comprehension (0.00s)
+=== RUN TestParameterizedWithOutputLength
+=== RUN TestParameterizedWithOutputLength/parameterized_within_limit
+=== RUN TestParameterizedWithOutputLength/parameterized_exceeds_custom_limit
+--- PASS: TestParameterizedWithOutputLength (0.01s)
+ --- PASS: TestParameterizedWithOutputLength/parameterized_within_limit (0.00s)
+ --- PASS: TestParameterizedWithOutputLength/parameterized_exceeds_custom_limit (0.01s)
+=== RUN TestIssue40_LikeEscapeClause
+=== RUN TestIssue40_LikeEscapeClause/startsWith_with_literal_includes_ESCAPE
+=== RUN TestIssue40_LikeEscapeClause/endsWith_with_literal_includes_ESCAPE
+=== RUN TestIssue40_LikeEscapeClause/startsWith_with_special_chars_includes_ESCAPE
+=== RUN TestIssue40_LikeEscapeClause/endsWith_with_special_chars_includes_ESCAPE
+--- PASS: TestIssue40_LikeEscapeClause (0.00s)
+ --- PASS: TestIssue40_LikeEscapeClause/startsWith_with_literal_includes_ESCAPE (0.00s)
+ --- PASS: TestIssue40_LikeEscapeClause/endsWith_with_literal_includes_ESCAPE (0.00s)
+ --- PASS: TestIssue40_LikeEscapeClause/startsWith_with_special_chars_includes_ESCAPE (0.00s)
+ --- PASS: TestIssue40_LikeEscapeClause/endsWith_with_special_chars_includes_ESCAPE (0.00s)
+=== RUN TestIssue43_VariableLikeEscaping
+=== RUN TestIssue43_VariableLikeEscaping/startsWith_with_variable_uses_REPLACE_for_backslash
+=== RUN TestIssue43_VariableLikeEscaping/startsWith_with_variable_uses_REPLACE_for_percent
+=== RUN TestIssue43_VariableLikeEscaping/startsWith_with_variable_uses_REPLACE_for_underscore
+=== RUN TestIssue43_VariableLikeEscaping/endsWith_with_variable_uses_REPLACE
+=== RUN TestIssue43_VariableLikeEscaping/startsWith_with_variable_includes_all_escapes_in_order
+--- PASS: TestIssue43_VariableLikeEscaping (0.00s)
+ --- PASS: TestIssue43_VariableLikeEscaping/startsWith_with_variable_uses_REPLACE_for_backslash (0.00s)
+ --- PASS: TestIssue43_VariableLikeEscaping/startsWith_with_variable_uses_REPLACE_for_percent (0.00s)
+ --- PASS: TestIssue43_VariableLikeEscaping/startsWith_with_variable_uses_REPLACE_for_underscore (0.00s)
+ --- PASS: TestIssue43_VariableLikeEscaping/endsWith_with_variable_uses_REPLACE (0.00s)
+ --- PASS: TestIssue43_VariableLikeEscaping/startsWith_with_variable_includes_all_escapes_in_order (0.00s)
+=== RUN TestIssue48_JSONComprehensionValidation
+=== RUN TestIssue48_JSONComprehensionValidation/all()_comprehension_has_no_type_check
+=== RUN TestIssue48_JSONComprehensionValidation/exists()_comprehension_has_no_type_check
+=== RUN TestIssue48_JSONComprehensionValidation/exists_one()_comprehension_has_no_type_check
+=== RUN TestIssue48_JSONComprehensionValidation/filter()_comprehension_has_no_type_check
+=== RUN TestIssue48_JSONComprehensionValidation/map()_comprehension_has_no_type_check
+--- PASS: TestIssue48_JSONComprehensionValidation (0.00s)
+ --- PASS: TestIssue48_JSONComprehensionValidation/all()_comprehension_has_no_type_check (0.00s)
+ --- PASS: TestIssue48_JSONComprehensionValidation/exists()_comprehension_has_no_type_check (0.00s)
+ --- PASS: TestIssue48_JSONComprehensionValidation/exists_one()_comprehension_has_no_type_check (0.00s)
+ --- PASS: TestIssue48_JSONComprehensionValidation/filter()_comprehension_has_no_type_check (0.00s)
+ --- PASS: TestIssue48_JSONComprehensionValidation/map()_comprehension_has_no_type_check (0.00s)
+=== RUN TestIssue48_ComprehensionWithoutPredicate
+--- PASS: TestIssue48_ComprehensionWithoutPredicate (0.00s)
+=== RUN TestPhase1Integration
+=== RUN TestPhase1Integration/Combined_LIKE_escaping_and_comprehension
+=== RUN TestPhase1Integration/Variable_LIKE_with_comprehension
+--- PASS: TestPhase1Integration (0.00s)
+ --- PASS: TestPhase1Integration/Combined_LIKE_escaping_and_comprehension (0.00s)
+ --- PASS: TestPhase1Integration/Variable_LIKE_with_comprehension (0.00s)
+=== RUN TestPhase1WithContext
+--- PASS: TestPhase1WithContext (0.00s)
+=== RUN TestMaxRecursionDepth
+=== RUN TestMaxRecursionDepth/within_default_limit
+=== RUN TestMaxRecursionDepth/exceeds_default_limit
+=== RUN TestMaxRecursionDepth/within_custom_limit
+=== RUN TestMaxRecursionDepth/exceeds_custom_limit
+=== RUN TestMaxRecursionDepth/very_deep_with_high_custom_limit
+=== RUN TestMaxRecursionDepth/shallow_expression_with_low_limit
+--- PASS: TestMaxRecursionDepth (0.05s)
+ --- PASS: TestMaxRecursionDepth/within_default_limit (0.01s)
+ --- PASS: TestMaxRecursionDepth/exceeds_default_limit (0.02s)
+ --- PASS: TestMaxRecursionDepth/within_custom_limit (0.00s)
+ --- PASS: TestMaxRecursionDepth/exceeds_custom_limit (0.01s)
+ --- PASS: TestMaxRecursionDepth/very_deep_with_high_custom_limit (0.02s)
+ --- PASS: TestMaxRecursionDepth/shallow_expression_with_low_limit (0.00s)
+=== RUN TestMaxDepthWithOtherOptions
+=== RUN TestMaxDepthWithOtherOptions/all_options_together
+time=2025-10-31T08:26:17.969+02:00 level=DEBUG msg="starting CEL to SQL conversion"
+time=2025-10-31T08:26:17.969+02:00 level=DEBUG msg="binary operator conversion" cel_op=_+_ sql_op=+
+time=2025-10-31T08:26:17.969+02:00 level=DEBUG msg="binary operator conversion" cel_op=_+_ sql_op=+
+time=2025-10-31T08:26:17.969+02:00 level=DEBUG msg="binary operator conversion" cel_op=_+_ sql_op=+
+time=2025-10-31T08:26:17.969+02:00 level=DEBUG msg="conversion completed" sql="x + 1 + 2 + 3" duration=193.208µs
+=== RUN TestMaxDepthWithOtherOptions/maxDepth_with_context
+=== RUN TestMaxDepthWithOtherOptions/maxDepth_with_schemas
+=== RUN TestMaxDepthWithOtherOptions/maxDepth_with_logger
+time=2025-10-31T08:26:17.970+02:00 level=DEBUG msg="starting CEL to SQL conversion"
+time=2025-10-31T08:26:17.970+02:00 level=DEBUG msg="binary operator conversion" cel_op="_==_" sql_op="="
+time=2025-10-31T08:26:17.970+02:00 level=DEBUG msg="conversion completed" sql="x = 10" duration=41.334µs
+--- PASS: TestMaxDepthWithOtherOptions (0.00s)
+ --- PASS: TestMaxDepthWithOtherOptions/all_options_together (0.00s)
+ --- PASS: TestMaxDepthWithOtherOptions/maxDepth_with_context (0.00s)
+ --- PASS: TestMaxDepthWithOtherOptions/maxDepth_with_schemas (0.00s)
+ --- PASS: TestMaxDepthWithOtherOptions/maxDepth_with_logger (0.00s)
+=== RUN TestRecursionDepthErrorMessage
+--- PASS: TestRecursionDepthErrorMessage (0.02s)
+=== RUN TestDeeplyNestedExpressions
+=== RUN TestDeeplyNestedExpressions/nested_AND_conditions
+=== RUN TestDeeplyNestedExpressions/nested_OR_conditions
+=== RUN TestDeeplyNestedExpressions/nested_function_calls
+=== RUN TestDeeplyNestedExpressions/deeply_nested_ternary
+=== RUN TestDeeplyNestedExpressions/exceeds_limit_nested_arithmetic
+--- PASS: TestDeeplyNestedExpressions (0.05s)
+ --- PASS: TestDeeplyNestedExpressions/nested_AND_conditions (0.01s)
+ --- PASS: TestDeeplyNestedExpressions/nested_OR_conditions (0.01s)
+ --- PASS: TestDeeplyNestedExpressions/nested_function_calls (0.00s)
+ --- PASS: TestDeeplyNestedExpressions/deeply_nested_ternary (0.01s)
+ --- PASS: TestDeeplyNestedExpressions/exceeds_limit_nested_arithmetic (0.02s)
+=== RUN TestDepthResetBetweenCalls
+--- PASS: TestDepthResetBetweenCalls (0.01s)
+=== RUN TestMaxDepthWithComprehensions
+=== RUN TestMaxDepthWithComprehensions/simple_all_comprehension
+=== RUN TestMaxDepthWithComprehensions/simple_exists_comprehension
+=== RUN TestMaxDepthWithComprehensions/nested_comprehension_in_condition
+--- PASS: TestMaxDepthWithComprehensions (0.00s)
+ --- PASS: TestMaxDepthWithComprehensions/simple_all_comprehension (0.00s)
+ --- PASS: TestMaxDepthWithComprehensions/simple_exists_comprehension (0.00s)
+ --- PASS: TestMaxDepthWithComprehensions/nested_comprehension_in_condition (0.00s)
+=== RUN TestValidateFieldName
+=== RUN TestValidateFieldName/simple_lowercase
+=== RUN TestValidateFieldName/simple_uppercase
+=== RUN TestValidateFieldName/mixed_case
+=== RUN TestValidateFieldName/with_underscore
+=== RUN TestValidateFieldName/starts_with_underscore
+=== RUN TestValidateFieldName/with_numbers
+=== RUN TestValidateFieldName/underscore_and_numbers
+=== RUN TestValidateFieldName/max_length_(63_chars)
+=== RUN TestValidateFieldName/SQL_injection_with_semicolon
+=== RUN TestValidateFieldName/SQL_injection_with_comment
+=== RUN TestValidateFieldName/SQL_injection_with_quotes
+=== RUN TestValidateFieldName/SQL_injection_with_double_dash
+=== RUN TestValidateFieldName/starts_with_number
+=== RUN TestValidateFieldName/contains_space
+=== RUN TestValidateFieldName/contains_hyphen
+=== RUN TestValidateFieldName/contains_dot
+=== RUN TestValidateFieldName/contains_special_characters
+=== RUN TestValidateFieldName/contains_newline
+=== RUN TestValidateFieldName/contains_tab
+=== RUN TestValidateFieldName/empty_string
+=== RUN TestValidateFieldName/exceeds_max_length_(64_chars)
+=== RUN TestValidateFieldName/way_too_long_(200_chars)
+=== RUN TestValidateFieldName/reserved_keyword:_select
+=== RUN TestValidateFieldName/reserved_keyword:_SELECT_(uppercase)
+=== RUN TestValidateFieldName/reserved_keyword:_from
+=== RUN TestValidateFieldName/reserved_keyword:_where
+=== RUN TestValidateFieldName/reserved_keyword:_and
+=== RUN TestValidateFieldName/reserved_keyword:_or
+=== RUN TestValidateFieldName/reserved_keyword:_not
+=== RUN TestValidateFieldName/reserved_keyword:_null
+=== RUN TestValidateFieldName/reserved_keyword:_true
+=== RUN TestValidateFieldName/reserved_keyword:_false
+=== RUN TestValidateFieldName/reserved_keyword:_union
+=== RUN TestValidateFieldName/reserved_keyword:_drop
+=== RUN TestValidateFieldName/reserved_keyword:_insert
+=== RUN TestValidateFieldName/reserved_keyword:_update
+=== RUN TestValidateFieldName/reserved_keyword:_delete
+=== RUN TestValidateFieldName/reserved_keyword:_table
+=== RUN TestValidateFieldName/reserved_keyword:_create
+=== RUN TestValidateFieldName/reserved_keyword:_alter
+=== RUN TestValidateFieldName/single_character
+=== RUN TestValidateFieldName/single_underscore
+=== RUN TestValidateFieldName/all_underscores
+--- PASS: TestValidateFieldName (0.00s)
+ --- PASS: TestValidateFieldName/simple_lowercase (0.00s)
+ --- PASS: TestValidateFieldName/simple_uppercase (0.00s)
+ --- PASS: TestValidateFieldName/mixed_case (0.00s)
+ --- PASS: TestValidateFieldName/with_underscore (0.00s)
+ --- PASS: TestValidateFieldName/starts_with_underscore (0.00s)
+ --- PASS: TestValidateFieldName/with_numbers (0.00s)
+ --- PASS: TestValidateFieldName/underscore_and_numbers (0.00s)
+ --- PASS: TestValidateFieldName/max_length_(63_chars) (0.00s)
+ --- PASS: TestValidateFieldName/SQL_injection_with_semicolon (0.00s)
+ --- PASS: TestValidateFieldName/SQL_injection_with_comment (0.00s)
+ --- PASS: TestValidateFieldName/SQL_injection_with_quotes (0.00s)
+ --- PASS: TestValidateFieldName/SQL_injection_with_double_dash (0.00s)
+ --- PASS: TestValidateFieldName/starts_with_number (0.00s)
+ --- PASS: TestValidateFieldName/contains_space (0.00s)
+ --- PASS: TestValidateFieldName/contains_hyphen (0.00s)
+ --- PASS: TestValidateFieldName/contains_dot (0.00s)
+ --- PASS: TestValidateFieldName/contains_special_characters (0.00s)
+ --- PASS: TestValidateFieldName/contains_newline (0.00s)
+ --- PASS: TestValidateFieldName/contains_tab (0.00s)
+ --- PASS: TestValidateFieldName/empty_string (0.00s)
+ --- PASS: TestValidateFieldName/exceeds_max_length_(64_chars) (0.00s)
+ --- PASS: TestValidateFieldName/way_too_long_(200_chars) (0.00s)
+ --- PASS: TestValidateFieldName/reserved_keyword:_select (0.00s)
+ --- PASS: TestValidateFieldName/reserved_keyword:_SELECT_(uppercase) (0.00s)
+ --- PASS: TestValidateFieldName/reserved_keyword:_from (0.00s)
+ --- PASS: TestValidateFieldName/reserved_keyword:_where (0.00s)
+ --- PASS: TestValidateFieldName/reserved_keyword:_and (0.00s)
+ --- PASS: TestValidateFieldName/reserved_keyword:_or (0.00s)
+ --- PASS: TestValidateFieldName/reserved_keyword:_not (0.00s)
+ --- PASS: TestValidateFieldName/reserved_keyword:_null (0.00s)
+ --- PASS: TestValidateFieldName/reserved_keyword:_true (0.00s)
+ --- PASS: TestValidateFieldName/reserved_keyword:_false (0.00s)
+ --- PASS: TestValidateFieldName/reserved_keyword:_union (0.00s)
+ --- PASS: TestValidateFieldName/reserved_keyword:_drop (0.00s)
+ --- PASS: TestValidateFieldName/reserved_keyword:_insert (0.00s)
+ --- PASS: TestValidateFieldName/reserved_keyword:_update (0.00s)
+ --- PASS: TestValidateFieldName/reserved_keyword:_delete (0.00s)
+ --- PASS: TestValidateFieldName/reserved_keyword:_table (0.00s)
+ --- PASS: TestValidateFieldName/reserved_keyword:_create (0.00s)
+ --- PASS: TestValidateFieldName/reserved_keyword:_alter (0.00s)
+ --- PASS: TestValidateFieldName/single_character (0.00s)
+ --- PASS: TestValidateFieldName/single_underscore (0.00s)
+ --- PASS: TestValidateFieldName/all_underscores (0.00s)
+=== RUN TestValidateFieldName_AllReservedKeywords
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_all
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_and
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_any
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_array
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_as
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_case
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_cast
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_check
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_create
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_cross
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_current_date
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_default
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_delete
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_distinct
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_drop
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_else
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_end
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_except
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_false
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_for
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_from
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_group
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_having
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_in
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_inner
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_insert
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_intersect
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_into
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_is
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_join
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_left
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_like
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_limit
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_natural
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_not
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_null
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_offset
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_on
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_or
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_order
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_outer
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_primary
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_references
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_right
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_select
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_table
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_then
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_to
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_true
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_union
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_unique
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_update
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_user
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_using
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_when
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_where
+=== RUN TestValidateFieldName_AllReservedKeywords/keyword_with
+--- PASS: TestValidateFieldName_AllReservedKeywords (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_all (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_and (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_any (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_array (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_as (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_case (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_cast (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_check (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_create (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_cross (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_current_date (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_default (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_delete (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_distinct (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_drop (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_else (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_end (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_except (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_false (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_for (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_from (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_group (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_having (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_in (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_inner (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_insert (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_intersect (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_into (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_is (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_join (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_left (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_like (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_limit (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_natural (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_not (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_null (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_offset (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_on (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_or (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_order (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_outer (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_primary (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_references (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_right (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_select (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_table (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_then (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_to (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_true (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_union (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_unique (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_update (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_user (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_using (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_when (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_where (0.00s)
+ --- PASS: TestValidateFieldName_AllReservedKeywords/keyword_with (0.00s)
+=== RUN TestEscapeJSONFieldName
+=== RUN TestEscapeJSONFieldName/no_quotes
+=== RUN TestEscapeJSONFieldName/single_quote_at_start
+=== RUN TestEscapeJSONFieldName/single_quote_in_middle
+=== RUN TestEscapeJSONFieldName/single_quote_at_end
+=== RUN TestEscapeJSONFieldName/multiple_single_quotes
+=== RUN TestEscapeJSONFieldName/SQL_injection_attempt
+=== RUN TestEscapeJSONFieldName/empty_string
+=== RUN TestEscapeJSONFieldName/only_single_quote
+=== RUN TestEscapeJSONFieldName/double_quotes_not_affected
+--- PASS: TestEscapeJSONFieldName (0.00s)
+ --- PASS: TestEscapeJSONFieldName/no_quotes (0.00s)
+ --- PASS: TestEscapeJSONFieldName/single_quote_at_start (0.00s)
+ --- PASS: TestEscapeJSONFieldName/single_quote_in_middle (0.00s)
+ --- PASS: TestEscapeJSONFieldName/single_quote_at_end (0.00s)
+ --- PASS: TestEscapeJSONFieldName/multiple_single_quotes (0.00s)
+ --- PASS: TestEscapeJSONFieldName/SQL_injection_attempt (0.00s)
+ --- PASS: TestEscapeJSONFieldName/empty_string (0.00s)
+ --- PASS: TestEscapeJSONFieldName/only_single_quote (0.00s)
+ --- PASS: TestEscapeJSONFieldName/double_quotes_not_affected (0.00s)
+=== RUN TestConvert
+=== RUN TestConvert/startsWith
+=== RUN TestConvert/endsWith
+=== RUN TestConvert/matches
+=== RUN TestConvert/matches_function_style
+=== RUN TestConvert/matches_with_word_boundary
+=== RUN TestConvert/matches_with_digit_class
+=== RUN TestConvert/matches_with_word_class
+=== RUN TestConvert/matches_complex_pattern
+=== RUN TestConvert/contains
+=== RUN TestConvert/&&
+=== RUN TestConvert/||
+=== RUN TestConvert/()
+=== RUN TestConvert/IF
+=== RUN TestConvert/==
+=== RUN TestConvert/!=
+=== RUN TestConvert/IS_NULL
+=== RUN TestConvert/IS_NOT_TRUE
+=== RUN TestConvert/<
+=== RUN TestConvert/>=
+=== RUN TestConvert/NOT
+=== RUN TestConvert/-
+=== RUN TestConvert/list
+=== RUN TestConvert/list_var
+=== RUN TestConvert/array_index_overflow
+=== RUN TestConvert/array_index_negative
+=== RUN TestConvert/map
+=== RUN TestConvert/map_var
+=== RUN TestConvert/invalidFieldType
+=== RUN TestConvert/invalidFieldName
+=== RUN TestConvert/add
+=== RUN TestConvert/concatString
+=== RUN TestConvert/concatList
+=== RUN TestConvert/modulo
+=== RUN TestConvert/date
+=== RUN TestConvert/time
+=== RUN TestConvert/datetime
+=== RUN TestConvert/timestamp
+=== RUN TestConvert/duration_second
+=== RUN TestConvert/duration_minute
+=== RUN TestConvert/duration_hour
+=== RUN TestConvert/interval
+=== RUN TestConvert/date_add
+=== RUN TestConvert/date_sub
+=== RUN TestConvert/time_add
+=== RUN TestConvert/time_sub
+=== RUN TestConvert/datetime_add
+=== RUN TestConvert/datetime_sub
+=== RUN TestConvert/timestamp_add
+=== RUN TestConvert/timestamp_sub
+=== RUN TestConvert/timestamp_getSeconds
+=== RUN TestConvert/"timestamp_getHours_withTimezone
+=== RUN TestConvert/date_getFullYear
+=== RUN TestConvert/datetime_getMonth
+=== RUN TestConvert/datetime_getDayOfMonth
+=== RUN TestConvert/time_getMinutes
+=== RUN TestConvert/fieldSelect
+=== RUN TestConvert/fieldSelect_startsWith
+=== RUN TestConvert/fieldSelect_add
+=== RUN TestConvert/fieldSelect_concatString
+=== RUN TestConvert/fieldSelect_in
+=== RUN TestConvert/cast_bool
+=== RUN TestConvert/cast_bytes
+=== RUN TestConvert/cast_int
+=== RUN TestConvert/cast_string
+=== RUN TestConvert/cast_string_from_timestamp
+=== RUN TestConvert/cast_int_epoch
+=== RUN TestConvert/size_string
+=== RUN TestConvert/size_bytes
+=== RUN TestConvert/size_list
+=== RUN TestConvert/size_list_comparison
+--- PASS: TestConvert (0.03s)
+ --- PASS: TestConvert/startsWith (0.00s)
+ --- PASS: TestConvert/endsWith (0.00s)
+ --- PASS: TestConvert/matches (0.00s)
+ --- PASS: TestConvert/matches_function_style (0.00s)
+ --- PASS: TestConvert/matches_with_word_boundary (0.00s)
+ --- PASS: TestConvert/matches_with_digit_class (0.00s)
+ --- PASS: TestConvert/matches_with_word_class (0.00s)
+ --- PASS: TestConvert/matches_complex_pattern (0.00s)
+ --- PASS: TestConvert/contains (0.00s)
+ --- PASS: TestConvert/&& (0.00s)
+ --- PASS: TestConvert/|| (0.00s)
+ --- PASS: TestConvert/() (0.00s)
+ --- PASS: TestConvert/IF (0.00s)
+ --- PASS: TestConvert/== (0.00s)
+ --- PASS: TestConvert/!= (0.00s)
+ --- PASS: TestConvert/IS_NULL (0.00s)
+ --- PASS: TestConvert/IS_NOT_TRUE (0.00s)
+ --- PASS: TestConvert/< (0.00s)
+ --- PASS: TestConvert/>= (0.00s)
+ --- PASS: TestConvert/NOT (0.00s)
+ --- PASS: TestConvert/- (0.00s)
+ --- PASS: TestConvert/list (0.00s)
+ --- PASS: TestConvert/list_var (0.00s)
+ --- PASS: TestConvert/array_index_overflow (0.00s)
+ --- PASS: TestConvert/array_index_negative (0.00s)
+ --- PASS: TestConvert/map (0.00s)
+ --- PASS: TestConvert/map_var (0.00s)
+ --- PASS: TestConvert/invalidFieldType (0.00s)
+ --- PASS: TestConvert/invalidFieldName (0.00s)
+ --- PASS: TestConvert/add (0.00s)
+ --- PASS: TestConvert/concatString (0.00s)
+ --- PASS: TestConvert/concatList (0.00s)
+ --- PASS: TestConvert/modulo (0.00s)
+ --- PASS: TestConvert/date (0.00s)
+ --- PASS: TestConvert/time (0.00s)
+ --- PASS: TestConvert/datetime (0.00s)
+ --- PASS: TestConvert/timestamp (0.00s)
+ --- PASS: TestConvert/duration_second (0.00s)
+ --- PASS: TestConvert/duration_minute (0.00s)
+ --- PASS: TestConvert/duration_hour (0.00s)
+ --- PASS: TestConvert/interval (0.00s)
+ --- PASS: TestConvert/date_add (0.00s)
+ --- PASS: TestConvert/date_sub (0.00s)
+ --- PASS: TestConvert/time_add (0.00s)
+ --- PASS: TestConvert/time_sub (0.00s)
+ --- PASS: TestConvert/datetime_add (0.00s)
+ --- PASS: TestConvert/datetime_sub (0.00s)
+ --- PASS: TestConvert/timestamp_add (0.00s)
+ --- PASS: TestConvert/timestamp_sub (0.00s)
+ --- PASS: TestConvert/timestamp_getSeconds (0.00s)
+ --- PASS: TestConvert/"timestamp_getHours_withTimezone (0.00s)
+ --- PASS: TestConvert/date_getFullYear (0.00s)
+ --- PASS: TestConvert/datetime_getMonth (0.00s)
+ --- PASS: TestConvert/datetime_getDayOfMonth (0.00s)
+ --- PASS: TestConvert/time_getMinutes (0.00s)
+ --- PASS: TestConvert/fieldSelect (0.00s)
+ --- PASS: TestConvert/fieldSelect_startsWith (0.00s)
+ --- PASS: TestConvert/fieldSelect_add (0.00s)
+ --- PASS: TestConvert/fieldSelect_concatString (0.00s)
+ --- PASS: TestConvert/fieldSelect_in (0.00s)
+ --- PASS: TestConvert/cast_bool (0.00s)
+ --- PASS: TestConvert/cast_bytes (0.00s)
+ --- PASS: TestConvert/cast_int (0.00s)
+ --- PASS: TestConvert/cast_string (0.00s)
+ --- PASS: TestConvert/cast_string_from_timestamp (0.00s)
+ --- PASS: TestConvert/cast_int_epoch (0.00s)
+ --- PASS: TestConvert/size_string (0.00s)
+ --- PASS: TestConvert/size_bytes (0.00s)
+ --- PASS: TestConvert/size_list (0.00s)
+ --- PASS: TestConvert/size_list_comparison (0.00s)
+=== RUN TestNullByteRejection
+=== RUN TestNullByteRejection/null_byte_at_start
+=== RUN TestNullByteRejection/null_byte_in_middle
+=== RUN TestNullByteRejection/null_byte_at_end
+=== RUN TestNullByteRejection/only_null_byte
+=== RUN TestNullByteRejection/multiple_null_bytes
+=== RUN TestNullByteRejection/valid_string_without_null_byte
+--- PASS: TestNullByteRejection (0.00s)
+ --- PASS: TestNullByteRejection/null_byte_at_start (0.00s)
+ --- PASS: TestNullByteRejection/null_byte_in_middle (0.00s)
+ --- PASS: TestNullByteRejection/null_byte_at_end (0.00s)
+ --- PASS: TestNullByteRejection/only_null_byte (0.00s)
+ --- PASS: TestNullByteRejection/multiple_null_bytes (0.00s)
+ --- PASS: TestNullByteRejection/valid_string_without_null_byte (0.00s)
+=== RUN TestNullByteInLikePatterns
+=== RUN TestNullByteInLikePatterns/startsWith_with_null_byte_at_start
+=== RUN TestNullByteInLikePatterns/startsWith_with_null_byte_in_middle
+=== RUN TestNullByteInLikePatterns/startsWith_with_only_null_byte
+=== RUN TestNullByteInLikePatterns/endsWith_with_null_byte_at_end
+=== RUN TestNullByteInLikePatterns/endsWith_with_null_byte_in_middle
+=== RUN TestNullByteInLikePatterns/endsWith_with_only_null_byte
+=== RUN TestNullByteInLikePatterns/startsWith_valid_pattern
+=== RUN TestNullByteInLikePatterns/endsWith_valid_pattern
+--- PASS: TestNullByteInLikePatterns (0.00s)
+ --- PASS: TestNullByteInLikePatterns/startsWith_with_null_byte_at_start (0.00s)
+ --- PASS: TestNullByteInLikePatterns/startsWith_with_null_byte_in_middle (0.00s)
+ --- PASS: TestNullByteInLikePatterns/startsWith_with_only_null_byte (0.00s)
+ --- PASS: TestNullByteInLikePatterns/endsWith_with_null_byte_at_end (0.00s)
+ --- PASS: TestNullByteInLikePatterns/endsWith_with_null_byte_in_middle (0.00s)
+ --- PASS: TestNullByteInLikePatterns/endsWith_with_only_null_byte (0.00s)
+ --- PASS: TestNullByteInLikePatterns/startsWith_valid_pattern (0.00s)
+ --- PASS: TestNullByteInLikePatterns/endsWith_valid_pattern (0.00s)
+=== RUN TestNullByteInRegexPatterns
+=== RUN TestNullByteInRegexPatterns/matches_with_only_null_byte
+=== RUN TestNullByteInRegexPatterns/matches_with_null_byte_at_start
+=== RUN TestNullByteInRegexPatterns/matches_with_null_byte_at_end
+=== RUN TestNullByteInRegexPatterns/matches_with_null_byte_in_middle
+=== RUN TestNullByteInRegexPatterns/matches_function_style_with_null_byte
+=== RUN TestNullByteInRegexPatterns/matches_with_multiple_null_bytes
+=== RUN TestNullByteInRegexPatterns/matches_with_valid_pattern
+=== RUN TestNullByteInRegexPatterns/matches_with_valid_complex_pattern
+--- PASS: TestNullByteInRegexPatterns (0.00s)
+ --- PASS: TestNullByteInRegexPatterns/matches_with_only_null_byte (0.00s)
+ --- PASS: TestNullByteInRegexPatterns/matches_with_null_byte_at_start (0.00s)
+ --- PASS: TestNullByteInRegexPatterns/matches_with_null_byte_at_end (0.00s)
+ --- PASS: TestNullByteInRegexPatterns/matches_with_null_byte_in_middle (0.00s)
+ --- PASS: TestNullByteInRegexPatterns/matches_function_style_with_null_byte (0.00s)
+ --- PASS: TestNullByteInRegexPatterns/matches_with_multiple_null_bytes (0.00s)
+ --- PASS: TestNullByteInRegexPatterns/matches_with_valid_pattern (0.00s)
+ --- PASS: TestNullByteInRegexPatterns/matches_with_valid_complex_pattern (0.00s)
+=== RUN TestNestedComprehensionDepthLimit
+=== RUN TestNestedComprehensionDepthLimit/single_level_all
+=== RUN TestNestedComprehensionDepthLimit/single_level_exists
+=== RUN TestNestedComprehensionDepthLimit/single_level_filter
+=== RUN TestNestedComprehensionDepthLimit/single_level_map
+=== RUN TestNestedComprehensionDepthLimit/double_nested_exists_in_all
+=== RUN TestNestedComprehensionDepthLimit/double_nested_filter_in_map
+=== RUN TestNestedComprehensionDepthLimit/triple_nested_at_limit
+=== RUN TestNestedComprehensionDepthLimit/triple_nested_mixed_types
+=== RUN TestNestedComprehensionDepthLimit/quadruple_nested_exceeds_limit
+=== RUN TestNestedComprehensionDepthLimit/complex_nested_exceeds_limit
+=== RUN TestNestedComprehensionDepthLimit/deeply_nested_exists_chain
+--- PASS: TestNestedComprehensionDepthLimit (0.01s)
+ --- PASS: TestNestedComprehensionDepthLimit/single_level_all (0.00s)
+ --- PASS: TestNestedComprehensionDepthLimit/single_level_exists (0.00s)
+ --- PASS: TestNestedComprehensionDepthLimit/single_level_filter (0.00s)
+ --- PASS: TestNestedComprehensionDepthLimit/single_level_map (0.00s)
+ --- PASS: TestNestedComprehensionDepthLimit/double_nested_exists_in_all (0.00s)
+ --- PASS: TestNestedComprehensionDepthLimit/double_nested_filter_in_map (0.00s)
+ --- PASS: TestNestedComprehensionDepthLimit/triple_nested_at_limit (0.00s)
+ --- PASS: TestNestedComprehensionDepthLimit/triple_nested_mixed_types (0.00s)
+ --- PASS: TestNestedComprehensionDepthLimit/quadruple_nested_exceeds_limit (0.00s)
+ --- PASS: TestNestedComprehensionDepthLimit/complex_nested_exceeds_limit (0.00s)
+ --- PASS: TestNestedComprehensionDepthLimit/deeply_nested_exists_chain (0.00s)
+=== RUN TestComprehensionDepthWithSchemas
+=== RUN TestComprehensionDepthWithSchemas/issue_example_similar
+=== RUN TestComprehensionDepthWithSchemas/issue_example_triple_nested
+=== RUN TestComprehensionDepthWithSchemas/too_deep_version
+--- PASS: TestComprehensionDepthWithSchemas (0.00s)
+ --- PASS: TestComprehensionDepthWithSchemas/issue_example_similar (0.00s)
+ --- PASS: TestComprehensionDepthWithSchemas/issue_example_triple_nested (0.00s)
+ --- PASS: TestComprehensionDepthWithSchemas/too_deep_version (0.00s)
+=== RUN TestComprehensionDepthResetBetweenCalls
+--- PASS: TestComprehensionDepthResetBetweenCalls (0.00s)
+=== RUN TestComprehensionDepthErrorMessage
+--- PASS: TestComprehensionDepthErrorMessage (0.00s)
+=== RUN TestComprehensionDepthWithMixedExpressions
+=== RUN TestComprehensionDepthWithMixedExpressions/comprehension_with_deep_arithmetic
+=== RUN TestComprehensionDepthWithMixedExpressions/comprehension_with_deep_conditionals
+=== RUN TestComprehensionDepthWithMixedExpressions/nested_comprehension_with_deep_expressions
+=== RUN TestComprehensionDepthWithMixedExpressions/triple_nested_with_expressions
+=== RUN TestComprehensionDepthWithMixedExpressions/quadruple_nested_even_with_simple_predicates
+--- PASS: TestComprehensionDepthWithMixedExpressions (0.01s)
+ --- PASS: TestComprehensionDepthWithMixedExpressions/comprehension_with_deep_arithmetic (0.00s)
+ --- PASS: TestComprehensionDepthWithMixedExpressions/comprehension_with_deep_conditionals (0.00s)
+ --- PASS: TestComprehensionDepthWithMixedExpressions/nested_comprehension_with_deep_expressions (0.00s)
+ --- PASS: TestComprehensionDepthWithMixedExpressions/triple_nested_with_expressions (0.00s)
+ --- PASS: TestComprehensionDepthWithMixedExpressions/quadruple_nested_even_with_simple_predicates (0.00s)
+=== RUN TestComprehensionDepthBoundaryConditions
+=== RUN TestComprehensionDepthBoundaryConditions/depth_1
+=== RUN TestComprehensionDepthBoundaryConditions/depth_2
+=== RUN TestComprehensionDepthBoundaryConditions/depth_3_at_limit
+=== RUN TestComprehensionDepthBoundaryConditions/depth_4_exceeds
+=== RUN TestComprehensionDepthBoundaryConditions/depth_5_exceeds
+--- PASS: TestComprehensionDepthBoundaryConditions (0.01s)
+ --- PASS: TestComprehensionDepthBoundaryConditions/depth_1 (0.00s)
+ --- PASS: TestComprehensionDepthBoundaryConditions/depth_2 (0.00s)
+ --- PASS: TestComprehensionDepthBoundaryConditions/depth_3_at_limit (0.00s)
+ --- PASS: TestComprehensionDepthBoundaryConditions/depth_4_exceeds (0.00s)
+ --- PASS: TestComprehensionDepthBoundaryConditions/depth_5_exceeds (0.00s)
+=== RUN TestExistsOneComprehension
+=== RUN TestExistsOneComprehension/exists_one_with_integer_array
+ comprehensions_coverage_test.go:66: Generated SQL: (SELECT COUNT(*) FROM UNNEST(record.scores) AS s WHERE s > 90) = 1
+=== RUN TestExistsOneComprehension/exists_one_with_string_array
+ comprehensions_coverage_test.go:66: Generated SQL: (SELECT COUNT(*) FROM UNNEST(record.tags) AS t WHERE t = 'urgent') = 1
+=== RUN TestExistsOneComprehension/exists_one_with_multiple_conditions
+ comprehensions_coverage_test.go:66: Generated SQL: (SELECT COUNT(*) FROM UNNEST(record.scores) AS s WHERE s >= 80 AND s <= 90) = 1
+--- PASS: TestExistsOneComprehension (0.00s)
+ --- PASS: TestExistsOneComprehension/exists_one_with_integer_array (0.00s)
+ --- PASS: TestExistsOneComprehension/exists_one_with_string_array (0.00s)
+ --- PASS: TestExistsOneComprehension/exists_one_with_multiple_conditions (0.00s)
+=== RUN TestFilterComprehension
+=== RUN TestFilterComprehension/filter_integer_array
+ comprehensions_coverage_test.go:130: Generated SQL: ARRAY(SELECT s FROM UNNEST(record.scores) AS s WHERE s > 70)
+=== RUN TestFilterComprehension/filter_string_array
+ comprehensions_coverage_test.go:130: Generated SQL: ARRAY(SELECT t FROM UNNEST(record.tags) AS t WHERE t LIKE 'high%' ESCAPE E'\\')
+=== RUN TestFilterComprehension/filter_with_multiple_conditions
+ comprehensions_coverage_test.go:130: Generated SQL: ARRAY(SELECT s FROM UNNEST(record.scores) AS s WHERE s >= 60 AND s < 90)
+=== RUN TestFilterComprehension/filter_double_array
+ comprehensions_coverage_test.go:130: Generated SQL: ARRAY(SELECT v FROM UNNEST(record.values) AS v WHERE v > 0.5)
+--- PASS: TestFilterComprehension (0.00s)
+ --- PASS: TestFilterComprehension/filter_integer_array (0.00s)
+ --- PASS: TestFilterComprehension/filter_string_array (0.00s)
+ --- PASS: TestFilterComprehension/filter_with_multiple_conditions (0.00s)
+ --- PASS: TestFilterComprehension/filter_double_array (0.00s)
+=== RUN TestJSONArrayComprehensions
+=== RUN TestJSONArrayComprehensions/exists_one_on_json_array
+ comprehensions_coverage_test.go:184: Generated SQL for exists_one on JSON array field: (SELECT COUNT(*) FROM UNNEST(record.metadata.items) AS i WHERE i.active) = 1
+=== RUN TestJSONArrayComprehensions/filter_on_json_array
+ comprehensions_coverage_test.go:184: Generated SQL for filter on JSON array field: ARRAY(SELECT i FROM UNNEST(record.metadata.items) AS i WHERE i.score > 50)
+--- PASS: TestJSONArrayComprehensions (0.00s)
+ --- PASS: TestJSONArrayComprehensions/exists_one_on_json_array (0.00s)
+ --- PASS: TestJSONArrayComprehensions/filter_on_json_array (0.00s)
+=== RUN TestNestedComprehensions
+=== RUN TestNestedComprehensions/nested_exists_one
+ comprehensions_coverage_test.go:236: Generated SQL for nested exists with exists_one: EXISTS (SELECT 1 FROM UNNEST(numbers) AS list WHERE (SELECT COUNT(*) FROM UNNEST(list) AS n WHERE n = 5) = 1)
+=== RUN TestNestedComprehensions/filter_then_exists_one
+ comprehensions_coverage_test.go:236: Generated SQL for filter containing exists_one: ARRAY(SELECT list FROM UNNEST(numbers) AS list WHERE (SELECT COUNT(*) FROM UNNEST(list) AS n WHERE n > 0) = 1)
+--- PASS: TestNestedComprehensions (0.00s)
+ --- PASS: TestNestedComprehensions/nested_exists_one (0.00s)
+ --- PASS: TestNestedComprehensions/filter_then_exists_one (0.00s)
+=== RUN TestComprehensionZeroCoverageEdgeCases
+=== RUN TestComprehensionZeroCoverageEdgeCases/exists_one_no_matches
+ comprehensions_coverage_test.go:289: Generated SQL for exists_one when no elements match (should return false): (SELECT COUNT(*) FROM UNNEST(record.items) AS i WHERE i > 1000000) = 1
+=== RUN TestComprehensionZeroCoverageEdgeCases/filter_no_matches
+ comprehensions_coverage_test.go:289: Generated SQL for filter when no elements match (should return empty array): ARRAY(SELECT i FROM UNNEST(record.items) AS i WHERE i < 0)
+=== RUN TestComprehensionZeroCoverageEdgeCases/exists_one_all_match
+ comprehensions_coverage_test.go:289: Generated SQL for exists_one when multiple elements match (should return false): (SELECT COUNT(*) FROM UNNEST(record.items) AS i WHERE i >= 0) = 1
+--- PASS: TestComprehensionZeroCoverageEdgeCases (0.00s)
+ --- PASS: TestComprehensionZeroCoverageEdgeCases/exists_one_no_matches (0.00s)
+ --- PASS: TestComprehensionZeroCoverageEdgeCases/filter_no_matches (0.00s)
+ --- PASS: TestComprehensionZeroCoverageEdgeCases/exists_one_all_match (0.00s)
+=== RUN TestComprehensionImplementation
+=== RUN TestComprehensionImplementation/all_comprehension
+ comprehensions_test.go:103: Generated SQL for ALL comprehension should generate NOT EXISTS with UNNEST: NOT EXISTS (SELECT 1 FROM UNNEST(ARRAY[ROW(60000), ROW(40000)]) AS e WHERE NOT (e.salary > 50000))
+=== RUN TestComprehensionImplementation/exists_comprehension
+ comprehensions_test.go:103: Generated SQL for EXISTS comprehension should generate EXISTS with UNNEST: EXISTS (SELECT 1 FROM UNNEST(ARRAY[ROW('Engineering'), ROW('Sales')]) AS e WHERE e.department = 'Engineering')
+=== RUN TestComprehensionImplementation/exists_one_comprehension
+ comprehensions_test.go:103: Generated SQL for EXISTS_ONE comprehension should generate COUNT query: (SELECT COUNT(*) FROM UNNEST(ARRAY[ROW('CEO'), ROW('CTO')]) AS e WHERE e.role = 'CEO') = 1
+=== RUN TestComprehensionImplementation/map_comprehension
+ comprehensions_test.go:103: Generated SQL for MAP comprehension should generate ARRAY SELECT: ARRAY(SELECT e.name FROM UNNEST(ARRAY[ROW('John'), ROW('Jane')]) AS e)
+=== RUN TestComprehensionImplementation/filter_comprehension
+ comprehensions_test.go:103: Generated SQL for FILTER comprehension should generate ARRAY SELECT with WHERE: ARRAY(SELECT e FROM UNNEST(ARRAY[ROW(TRUE), ROW(FALSE)]) AS e WHERE e.active)
+=== RUN TestComprehensionImplementation/list_all
+ comprehensions_test.go:103: Generated SQL for ALL comprehension on simple list should work: NOT EXISTS (SELECT 1 FROM UNNEST(ARRAY[1, 2, 3, 4]) AS x WHERE NOT (x > 0))
+=== RUN TestComprehensionImplementation/list_exists
+ comprehensions_test.go:103: Generated SQL for EXISTS comprehension on simple list should work: EXISTS (SELECT 1 FROM UNNEST(ARRAY[1, 2, 3, 4]) AS x WHERE x > 3)
+=== RUN TestComprehensionImplementation/map_with_filter
+--- PASS: TestComprehensionImplementation (0.01s)
+ --- PASS: TestComprehensionImplementation/all_comprehension (0.00s)
+ --- PASS: TestComprehensionImplementation/exists_comprehension (0.00s)
+ --- PASS: TestComprehensionImplementation/exists_one_comprehension (0.00s)
+ --- PASS: TestComprehensionImplementation/map_comprehension (0.00s)
+ --- PASS: TestComprehensionImplementation/filter_comprehension (0.00s)
+ --- PASS: TestComprehensionImplementation/list_all (0.00s)
+ --- PASS: TestComprehensionImplementation/list_exists (0.00s)
+ --- PASS: TestComprehensionImplementation/map_with_filter (0.00s)
+=== RUN TestNonComprehensionExpressionsStillWork
+=== RUN TestNonComprehensionExpressionsStillWork/simple_comparison
+=== RUN TestNonComprehensionExpressionsStillWork/string_equality
+=== RUN TestNonComprehensionExpressionsStillWork/boolean_field
+=== RUN TestNonComprehensionExpressionsStillWork/logical_and
+--- PASS: TestNonComprehensionExpressionsStillWork (0.00s)
+ --- PASS: TestNonComprehensionExpressionsStillWork/simple_comparison (0.00s)
+ --- PASS: TestNonComprehensionExpressionsStillWork/string_equality (0.00s)
+ --- PASS: TestNonComprehensionExpressionsStillWork/boolean_field (0.00s)
+ --- PASS: TestNonComprehensionExpressionsStillWork/logical_and (0.00s)
+=== RUN TestComprehensionWithPostgreSQLSchemas
+=== RUN TestComprehensionWithPostgreSQLSchemas/all_high_earners
+ comprehensions_test.go:252: Expression: employees.all(e, e.salary > 80000)
+ comprehensions_test.go:253: Generated SQL: NOT EXISTS (SELECT 1 FROM UNNEST(employees) AS e WHERE NOT (e.salary > 80000))
+=== RUN TestComprehensionWithPostgreSQLSchemas/exists_senior
+ comprehensions_test.go:252: Expression: employees.exists(e, e.age > 50)
+ comprehensions_test.go:253: Generated SQL: EXISTS (SELECT 1 FROM UNNEST(employees) AS e WHERE e.age > 50)
+=== RUN TestComprehensionWithPostgreSQLSchemas/exists_one_admin
+ comprehensions_test.go:252: Expression: employees.exists_one(e, e.name == 'admin')
+ comprehensions_test.go:253: Generated SQL: (SELECT COUNT(*) FROM UNNEST(employees) AS e WHERE e.name = 'admin') = 1
+=== RUN TestComprehensionWithPostgreSQLSchemas/map_names
+ comprehensions_test.go:252: Expression: employees.map(e, e.name)
+ comprehensions_test.go:253: Generated SQL: ARRAY(SELECT e.name FROM UNNEST(employees) AS e)
+=== RUN TestComprehensionWithPostgreSQLSchemas/filter_active
+ comprehensions_test.go:252: Expression: employees.filter(e, e.active)
+ comprehensions_test.go:253: Generated SQL: ARRAY(SELECT e FROM UNNEST(employees) AS e WHERE e.active)
+=== RUN TestComprehensionWithPostgreSQLSchemas/filter_by_age
+ comprehensions_test.go:252: Expression: employees.filter(e, e.age >= 25 && e.age <= 65)
+ comprehensions_test.go:253: Generated SQL: ARRAY(SELECT e FROM UNNEST(employees) AS e WHERE e.age >= 25 AND e.age <= 65)
+=== RUN TestComprehensionWithPostgreSQLSchemas/map_emails_active
+ comprehensions_test.go:252: Expression: employees.filter(e, e.active).map(e, e.email)
+ comprehensions_test.go:253: Generated SQL: ARRAY(SELECT e.email FROM UNNEST(ARRAY(SELECT e FROM UNNEST(employees) AS e WHERE e.active)) AS e)
+=== RUN TestComprehensionWithPostgreSQLSchemas/all_have_email
+ comprehensions_test.go:252: Expression: employees.all(e, e.email != '')
+ comprehensions_test.go:253: Generated SQL: NOT EXISTS (SELECT 1 FROM UNNEST(employees) AS e WHERE NOT (e.email != ''))
+=== RUN TestComprehensionWithPostgreSQLSchemas/exists_high_score
+ comprehensions_test.go:252: Expression: emp.scores.exists(s, s > 90)
+ comprehensions_test.go:253: Generated SQL: EXISTS (SELECT 1 FROM UNNEST(emp.scores) AS s WHERE s > 90)
+=== RUN TestComprehensionWithPostgreSQLSchemas/all_scores_passing
+ comprehensions_test.go:252: Expression: emp.scores.all(s, s >= 60)
+ comprehensions_test.go:253: Generated SQL: NOT EXISTS (SELECT 1 FROM UNNEST(emp.scores) AS s WHERE NOT (s >= 60))
+--- PASS: TestComprehensionWithPostgreSQLSchemas (0.01s)
+ --- PASS: TestComprehensionWithPostgreSQLSchemas/all_high_earners (0.00s)
+ --- PASS: TestComprehensionWithPostgreSQLSchemas/exists_senior (0.00s)
+ --- PASS: TestComprehensionWithPostgreSQLSchemas/exists_one_admin (0.00s)
+ --- PASS: TestComprehensionWithPostgreSQLSchemas/map_names (0.00s)
+ --- PASS: TestComprehensionWithPostgreSQLSchemas/filter_active (0.00s)
+ --- PASS: TestComprehensionWithPostgreSQLSchemas/filter_by_age (0.00s)
+ --- PASS: TestComprehensionWithPostgreSQLSchemas/map_emails_active (0.00s)
+ --- PASS: TestComprehensionWithPostgreSQLSchemas/all_have_email (0.00s)
+ --- PASS: TestComprehensionWithPostgreSQLSchemas/exists_high_score (0.00s)
+ --- PASS: TestComprehensionWithPostgreSQLSchemas/all_scores_passing (0.00s)
+=== RUN TestComprehensionWithNestedStructures
+=== RUN TestComprehensionWithNestedStructures/filter_by_city
+ comprehensions_test.go:338: Expression: employees.filter(e, e.address.city == 'New York')
+ comprehensions_test.go:339: Generated SQL: ARRAY(SELECT e FROM UNNEST(employees) AS e WHERE e.address.city = 'New York')
+=== RUN TestComprehensionWithNestedStructures/exists_skill
+ comprehensions_test.go:338: Expression: employees.exists(e, e.skills.exists(s, s == 'Go'))
+ comprehensions_test.go:339: Generated SQL: EXISTS (SELECT 1 FROM UNNEST(employees) AS e WHERE EXISTS (SELECT 1 FROM UNNEST(e.skills) AS s WHERE s = 'Go'))
+=== RUN TestComprehensionWithNestedStructures/map_cities
+ comprehensions_test.go:338: Expression: employees.map(e, e.address.city)
+ comprehensions_test.go:339: Generated SQL: ARRAY(SELECT e.address.city FROM UNNEST(employees) AS e)
+--- PASS: TestComprehensionWithNestedStructures (0.00s)
+ --- PASS: TestComprehensionWithNestedStructures/filter_by_city (0.00s)
+ --- PASS: TestComprehensionWithNestedStructures/exists_skill (0.00s)
+ --- PASS: TestComprehensionWithNestedStructures/map_cities (0.00s)
+=== RUN TestComprehensionEdgeCases
+=== RUN TestComprehensionEdgeCases/all_empty_list
+ comprehensions_test.go:391: Expression: [].all(x, x > 0)
+ comprehensions_test.go:392: Generated SQL: NOT EXISTS (SELECT 1 FROM UNNEST(ARRAY[]) AS x WHERE NOT (x > 0))
+=== RUN TestComprehensionEdgeCases/exists_empty_list
+ comprehensions_test.go:391: Expression: [].exists(x, x > 0)
+ comprehensions_test.go:392: Generated SQL: EXISTS (SELECT 1 FROM UNNEST(ARRAY[]) AS x WHERE x > 0)
+=== RUN TestComprehensionEdgeCases/filter_empty_list
+ comprehensions_test.go:391: Expression: [].filter(x, x > 0)
+ comprehensions_test.go:392: Generated SQL: ARRAY(SELECT x FROM UNNEST(ARRAY[]) AS x WHERE x > 0)
+=== RUN TestComprehensionEdgeCases/map_empty_list
+ comprehensions_test.go:391: Expression: [].map(x, x * 2)
+ comprehensions_test.go:392: Generated SQL: ARRAY(SELECT x * 2 FROM UNNEST(ARRAY[]) AS x)
+=== RUN TestComprehensionEdgeCases/complex_predicate
+ comprehensions_test.go:391: Expression: [1, 2, 3, 4, 5].all(x, x > 0 && x < 10 && x % 2 == 0 || x == 1)
+ comprehensions_test.go:392: Generated SQL: NOT EXISTS (SELECT 1 FROM UNNEST(ARRAY[1, 2, 3, 4, 5]) AS x WHERE NOT (x > 0 AND x < 10 AND MOD(x, 2) = 0 OR x = 1))
+--- PASS: TestComprehensionEdgeCases (0.00s)
+ --- PASS: TestComprehensionEdgeCases/all_empty_list (0.00s)
+ --- PASS: TestComprehensionEdgeCases/exists_empty_list (0.00s)
+ --- PASS: TestComprehensionEdgeCases/filter_empty_list (0.00s)
+ --- PASS: TestComprehensionEdgeCases/map_empty_list (0.00s)
+ --- PASS: TestComprehensionEdgeCases/complex_predicate (0.00s)
+=== RUN TestConvertWithContext_NilContext
+--- PASS: TestConvertWithContext_NilContext (0.00s)
+=== RUN TestConvertWithContext_ActiveContext
+--- PASS: TestConvertWithContext_ActiveContext (0.00s)
+=== RUN TestConvertWithContext_CancelledContext
+--- PASS: TestConvertWithContext_CancelledContext (0.00s)
+=== RUN TestConvertWithContext_Timeout
+--- PASS: TestConvertWithContext_Timeout (0.01s)
+=== RUN TestConvertWithContext_ComplexExpression
+--- PASS: TestConvertWithContext_ComplexExpression (0.00s)
+=== RUN TestConvertWithContext_MultipleOptions
+--- PASS: TestConvertWithContext_MultipleOptions (0.00s)
+=== RUN TestConvertWithContext_LongRunningConversion
+--- PASS: TestConvertWithContext_LongRunningConversion (0.01s)
+=== RUN TestConstEdgeCases
+=== RUN TestConstEdgeCases/max_int64
+ edgecase_coverage_test.go:137: Generated SQL: 9223372036854775807 > 0
+=== RUN TestConstEdgeCases/min_int64
+ edgecase_coverage_test.go:137: Generated SQL: -9223372036854775808 < 0
+=== RUN TestConstEdgeCases/zero_integer
+ edgecase_coverage_test.go:137: Generated SQL: 0 = 0
+=== RUN TestConstEdgeCases/zero_double
+ edgecase_coverage_test.go:137: Generated SQL: 0 = 0
+=== RUN TestConstEdgeCases/negative_zero
+ edgecase_coverage_test.go:137: Generated SQL: -0 < 1
+=== RUN TestConstEdgeCases/very_large_double
+ edgecase_coverage_test.go:137: Generated SQL: 1.7976931348623157e+308 > 0
+=== RUN TestConstEdgeCases/very_small_positive_double
+ edgecase_coverage_test.go:137: Generated SQL: 2.2250738585072014e-308 > 0
+=== RUN TestConstEdgeCases/negative_double
+ edgecase_coverage_test.go:137: Generated SQL: -123.456 < 0
+=== RUN TestConstEdgeCases/empty_string
+ edgecase_coverage_test.go:137: Generated SQL: '' = ''
+=== RUN TestConstEdgeCases/string_with_quotes
+ edgecase_coverage_test.go:137: Generated SQL: 'it''s working' = 'it''s working'
+=== RUN TestConstEdgeCases/string_with_backslash
+ edgecase_coverage_test.go:137: Generated SQL: 'path\to\file' != ''
+=== RUN TestConstEdgeCases/unicode_string
+ edgecase_coverage_test.go:137: Generated SQL: 'Hello 世界 🌍' != ''
+=== RUN TestConstEdgeCases/null_value
+ edgecase_coverage_test.go:137: Generated SQL: NULL IS NULL
+=== RUN TestConstEdgeCases/true_bool
+ edgecase_coverage_test.go:137: Generated SQL: TRUE IS TRUE
+=== RUN TestConstEdgeCases/false_bool
+ edgecase_coverage_test.go:137: Generated SQL: FALSE IS FALSE
+=== RUN TestConstEdgeCases/bytes_value
+ edgecase_coverage_test.go:137: Generated SQL: '\x68656c6c6f' != '\x'
+=== RUN TestConstEdgeCases/uint64_value
+ edgecase_coverage_test.go:137: Generated SQL: 18446744073709551615 > 0
+--- PASS: TestConstEdgeCases (0.01s)
+ --- PASS: TestConstEdgeCases/max_int64 (0.00s)
+ --- PASS: TestConstEdgeCases/min_int64 (0.00s)
+ --- PASS: TestConstEdgeCases/zero_integer (0.00s)
+ --- PASS: TestConstEdgeCases/zero_double (0.00s)
+ --- PASS: TestConstEdgeCases/negative_zero (0.00s)
+ --- PASS: TestConstEdgeCases/very_large_double (0.00s)
+ --- PASS: TestConstEdgeCases/very_small_positive_double (0.00s)
+ --- PASS: TestConstEdgeCases/negative_double (0.00s)
+ --- PASS: TestConstEdgeCases/empty_string (0.00s)
+ --- PASS: TestConstEdgeCases/string_with_quotes (0.00s)
+ --- PASS: TestConstEdgeCases/string_with_backslash (0.00s)
+ --- PASS: TestConstEdgeCases/unicode_string (0.00s)
+ --- PASS: TestConstEdgeCases/null_value (0.00s)
+ --- PASS: TestConstEdgeCases/true_bool (0.00s)
+ --- PASS: TestConstEdgeCases/false_bool (0.00s)
+ --- PASS: TestConstEdgeCases/bytes_value (0.00s)
+ --- PASS: TestConstEdgeCases/uint64_value (0.00s)
+=== RUN TestStringFunctionEdgeCases
+=== RUN TestStringFunctionEdgeCases/contains_empty_string
+ edgecase_coverage_test.go:238: Generated SQL: POSITION('' IN text) > 0
+=== RUN TestStringFunctionEdgeCases/contains_special_chars
+ edgecase_coverage_test.go:238: Generated SQL: POSITION('100%' IN text) > 0
+=== RUN TestStringFunctionEdgeCases/contains_with_underscore
+ edgecase_coverage_test.go:238: Generated SQL: POSITION('_test' IN text) > 0
+=== RUN TestStringFunctionEdgeCases/startsWith_empty
+ edgecase_coverage_test.go:238: Generated SQL: text LIKE REPLACE(REPLACE(REPLACE('', '\\', '\\\\'), '%', '\%'), '_', '\_') || '%' ESCAPE E'\\'
+=== RUN TestStringFunctionEdgeCases/startsWith_percent
+ edgecase_coverage_test.go:238: Generated SQL: text LIKE '50\%%' ESCAPE E'\\'
+=== RUN TestStringFunctionEdgeCases/startsWith_underscore
+ edgecase_coverage_test.go:238: Generated SQL: text LIKE '\_prefix%' ESCAPE E'\\'
+=== RUN TestStringFunctionEdgeCases/startsWith_backslash
+ edgecase_coverage_test.go:238: Generated SQL: text LIKE '\\path%' ESCAPE E'\\'
+=== RUN TestStringFunctionEdgeCases/endsWith_empty
+ edgecase_coverage_test.go:238: Generated SQL: text LIKE '%' || REPLACE(REPLACE(REPLACE('', '\\', '\\\\'), '%', '\%'), '_', '\_') ESCAPE E'\\'
+=== RUN TestStringFunctionEdgeCases/endsWith_percent
+ edgecase_coverage_test.go:238: Generated SQL: text LIKE '%100\%' ESCAPE E'\\'
+=== RUN TestStringFunctionEdgeCases/endsWith_underscore
+ edgecase_coverage_test.go:238: Generated SQL: text LIKE '%suffix\_' ESCAPE E'\\'
+=== RUN TestStringFunctionEdgeCases/contains_unicode
+ edgecase_coverage_test.go:238: Generated SQL: POSITION('世界' IN text) > 0
+=== RUN TestStringFunctionEdgeCases/multiple_contains
+ edgecase_coverage_test.go:238: Generated SQL: POSITION('foo' IN text) > 0 AND POSITION('bar' IN text) > 0
+--- PASS: TestStringFunctionEdgeCases (0.00s)
+ --- PASS: TestStringFunctionEdgeCases/contains_empty_string (0.00s)
+ --- PASS: TestStringFunctionEdgeCases/contains_special_chars (0.00s)
+ --- PASS: TestStringFunctionEdgeCases/contains_with_underscore (0.00s)
+ --- PASS: TestStringFunctionEdgeCases/startsWith_empty (0.00s)
+ --- PASS: TestStringFunctionEdgeCases/startsWith_percent (0.00s)
+ --- PASS: TestStringFunctionEdgeCases/startsWith_underscore (0.00s)
+ --- PASS: TestStringFunctionEdgeCases/startsWith_backslash (0.00s)
+ --- PASS: TestStringFunctionEdgeCases/endsWith_empty (0.00s)
+ --- PASS: TestStringFunctionEdgeCases/endsWith_percent (0.00s)
+ --- PASS: TestStringFunctionEdgeCases/endsWith_underscore (0.00s)
+ --- PASS: TestStringFunctionEdgeCases/contains_unicode (0.00s)
+ --- PASS: TestStringFunctionEdgeCases/multiple_contains (0.00s)
+=== RUN TestBinaryOperatorEdgeCases
+=== RUN TestBinaryOperatorEdgeCases/bool_comparison_equals
+ edgecase_coverage_test.go:370: Generated SQL: TRUE IS FALSE
+=== RUN TestBinaryOperatorEdgeCases/bool_comparison_not_equals
+ edgecase_coverage_test.go:370: Generated SQL: TRUE IS NOT FALSE
+=== RUN TestBinaryOperatorEdgeCases/string_concatenation
+ edgecase_coverage_test.go:370: Generated SQL: 'hello' || ' world'
+=== RUN TestBinaryOperatorEdgeCases/list_concatenation
+ edgecase_coverage_test.go:370: Generated SQL: ARRAY[1, 2] || ARRAY[3, 4]
+=== RUN TestBinaryOperatorEdgeCases/modulo_operator
+ edgecase_coverage_test.go:370: Generated SQL: MOD(a, b) = 0
+=== RUN TestBinaryOperatorEdgeCases/division_operator
+ edgecase_coverage_test.go:370: Generated SQL: a / b > 0
+=== RUN TestBinaryOperatorEdgeCases/logical_or
+ edgecase_coverage_test.go:370: Generated SQL: a > 10 OR b < 5
+=== RUN TestBinaryOperatorEdgeCases/logical_and
+ edgecase_coverage_test.go:370: Generated SQL: a > 10 AND b < 5
+=== RUN TestBinaryOperatorEdgeCases/nested_operators
+ edgecase_coverage_test.go:370: Generated SQL: (a + b) * (a - b)
+=== RUN TestBinaryOperatorEdgeCases/comparison_chain
+ edgecase_coverage_test.go:370: Generated SQL: a < b AND b < 100
+=== RUN TestBinaryOperatorEdgeCases/in_operator_with_list
+ edgecase_coverage_test.go:370: Generated SQL: data.name = ANY(ARRAY['admin', 'user'])
+=== RUN TestBinaryOperatorEdgeCases/in_operator_with_array_field
+ edgecase_coverage_test.go:370: Generated SQL: 'test' = ANY(data.tags)
+=== RUN TestBinaryOperatorEdgeCases/negation_operator
+ edgecase_coverage_test.go:370: Generated SQL: NOT (a > 10)
+=== RUN TestBinaryOperatorEdgeCases/less_than_or_equal
+ edgecase_coverage_test.go:370: Generated SQL: a <= b
+=== RUN TestBinaryOperatorEdgeCases/greater_than_or_equal
+ edgecase_coverage_test.go:370: Generated SQL: a >= b
+--- PASS: TestBinaryOperatorEdgeCases (0.01s)
+ --- PASS: TestBinaryOperatorEdgeCases/bool_comparison_equals (0.00s)
+ --- PASS: TestBinaryOperatorEdgeCases/bool_comparison_not_equals (0.00s)
+ --- PASS: TestBinaryOperatorEdgeCases/string_concatenation (0.00s)
+ --- PASS: TestBinaryOperatorEdgeCases/list_concatenation (0.00s)
+ --- PASS: TestBinaryOperatorEdgeCases/modulo_operator (0.00s)
+ --- PASS: TestBinaryOperatorEdgeCases/division_operator (0.00s)
+ --- PASS: TestBinaryOperatorEdgeCases/logical_or (0.00s)
+ --- PASS: TestBinaryOperatorEdgeCases/logical_and (0.00s)
+ --- PASS: TestBinaryOperatorEdgeCases/nested_operators (0.00s)
+ --- PASS: TestBinaryOperatorEdgeCases/comparison_chain (0.00s)
+ --- PASS: TestBinaryOperatorEdgeCases/in_operator_with_list (0.00s)
+ --- PASS: TestBinaryOperatorEdgeCases/in_operator_with_array_field (0.00s)
+ --- PASS: TestBinaryOperatorEdgeCases/negation_operator (0.00s)
+ --- PASS: TestBinaryOperatorEdgeCases/less_than_or_equal (0.00s)
+ --- PASS: TestBinaryOperatorEdgeCases/greater_than_or_equal (0.00s)
+=== RUN TestIdentifierEdgeCases
+=== RUN TestIdentifierEdgeCases/identifier_score
+ edgecase_coverage_test.go:452: Generated SQL for Identifier 'score' (may need numeric casting in JSON context): record.score > 10
+=== RUN TestIdentifierEdgeCases/identifier_value
+ edgecase_coverage_test.go:452: Generated SQL for Identifier 'value' (may need numeric casting in JSON context): record.value > 0
+=== RUN TestIdentifierEdgeCases/identifier_count
+ edgecase_coverage_test.go:452: Generated SQL for Identifier 'count': record.count = 5
+=== RUN TestIdentifierEdgeCases/identifier_amount
+ edgecase_coverage_test.go:452: Generated SQL for Identifier 'amount': record.amount >= 100
+=== RUN TestIdentifierEdgeCases/simple_identifier
+ edgecase_coverage_test.go:452: Generated SQL for Simple identifier access: record.id > 0
+--- PASS: TestIdentifierEdgeCases (0.00s)
+ --- PASS: TestIdentifierEdgeCases/identifier_score (0.00s)
+ --- PASS: TestIdentifierEdgeCases/identifier_value (0.00s)
+ --- PASS: TestIdentifierEdgeCases/identifier_count (0.00s)
+ --- PASS: TestIdentifierEdgeCases/identifier_amount (0.00s)
+ --- PASS: TestIdentifierEdgeCases/simple_identifier (0.00s)
+=== RUN TestCallFuncEdgeCases
+=== RUN TestCallFuncEdgeCases/type_conversion_int
+ edgecase_coverage_test.go:531: Generated SQL for int() type conversion: CAST('123' AS BIGINT) > 100
+=== RUN TestCallFuncEdgeCases/type_conversion_double
+ edgecase_coverage_test.go:531: Generated SQL for double() type conversion: CAST('3.14' AS DOUBLE PRECISION) > 3
+=== RUN TestCallFuncEdgeCases/type_conversion_string
+ edgecase_coverage_test.go:531: Generated SQL for string() type conversion: CAST(123 AS TEXT) = '123'
+=== RUN TestCallFuncEdgeCases/type_conversion_bool
+ edgecase_coverage_test.go:531: Generated SQL for bool() type conversion: CAST('true' AS BOOLEAN) IS TRUE
+--- PASS: TestCallFuncEdgeCases (0.00s)
+ --- PASS: TestCallFuncEdgeCases/type_conversion_int (0.00s)
+ --- PASS: TestCallFuncEdgeCases/type_conversion_double (0.00s)
+ --- PASS: TestCallFuncEdgeCases/type_conversion_string (0.00s)
+ --- PASS: TestCallFuncEdgeCases/type_conversion_bool (0.00s)
+=== RUN TestSpecialDoubleValues
+=== RUN TestSpecialDoubleValues/positive_infinity_comparison
+ edgecase_coverage_test.go:584: Generated SQL: x < 1.7976931348623157e+308
+=== RUN TestSpecialDoubleValues/negative_infinity_comparison
+ edgecase_coverage_test.go:584: Generated SQL: x > -1.7976931348623157e+308
+=== RUN TestSpecialDoubleValues/scientific_notation_small
+ edgecase_coverage_test.go:584: Generated SQL: x > 1.23e-100
+=== RUN TestSpecialDoubleValues/scientific_notation_large
+ edgecase_coverage_test.go:584: Generated SQL: x < 9.87e+200
+--- PASS: TestSpecialDoubleValues (0.00s)
+ --- PASS: TestSpecialDoubleValues/positive_infinity_comparison (0.00s)
+ --- PASS: TestSpecialDoubleValues/negative_infinity_comparison (0.00s)
+ --- PASS: TestSpecialDoubleValues/scientific_notation_small (0.00s)
+ --- PASS: TestSpecialDoubleValues/scientific_notation_large (0.00s)
+=== RUN TestComplexNestedExpressions
+=== RUN TestComplexNestedExpressions/deeply_nested_arithmetic
+ edgecase_coverage_test.go:639: Generated SQL for Deeply nested arithmetic operations: (a + b) * (c - a) / (b * c + 1)
+=== RUN TestComplexNestedExpressions/complex_boolean_logic
+ edgecase_coverage_test.go:639: Generated SQL for Complex boolean logic with mixed operators: a > 10 AND b < 20 OR c = 5 AND a != b
+=== RUN TestComplexNestedExpressions/mixed_string_and_numeric
+ edgecase_coverage_test.go:639: Generated SQL for Mixed string and numeric operations: POSITION('hello' IN text) > 0 AND a > 0 OR POSITION('test' IN text) > 0 AND b < 100
+=== RUN TestComplexNestedExpressions/nested_ternary_style
+ edgecase_coverage_test.go:639: Generated SQL for Ternary-style expression with comparison: (CASE WHEN a > b THEN a ELSE b END) > c
+=== RUN TestComplexNestedExpressions/parenthesized_expressions
+ edgecase_coverage_test.go:639: Generated SQL for Multiple levels of parenthesized expressions: a + b > c * 2 AND a - c < b + 1
+--- PASS: TestComplexNestedExpressions (0.00s)
+ --- PASS: TestComplexNestedExpressions/deeply_nested_arithmetic (0.00s)
+ --- PASS: TestComplexNestedExpressions/complex_boolean_logic (0.00s)
+ --- PASS: TestComplexNestedExpressions/mixed_string_and_numeric (0.00s)
+ --- PASS: TestComplexNestedExpressions/nested_ternary_style (0.00s)
+ --- PASS: TestComplexNestedExpressions/parenthesized_expressions (0.00s)
+=== RUN TestErrorMessageSanitization
+=== RUN TestErrorMessageSanitization/valid_expression_should_not_error
+=== RUN TestErrorMessageSanitization/valid_identifier_expression
+--- PASS: TestErrorMessageSanitization (0.00s)
+ --- PASS: TestErrorMessageSanitization/valid_expression_should_not_error (0.00s)
+ --- PASS: TestErrorMessageSanitization/valid_identifier_expression (0.00s)
+=== RUN TestConversionErrorStructure
+=== RUN TestConversionErrorStructure/basic_conversion_error
+--- PASS: TestConversionErrorStructure (0.00s)
+ --- PASS: TestConversionErrorStructure/basic_conversion_error (0.00s)
+=== RUN TestErrorMessagesForCommonPatterns
+=== RUN TestErrorMessagesForCommonPatterns/unsupported_size()_argument_type
+--- PASS: TestErrorMessagesForCommonPatterns (0.00s)
+ --- PASS: TestErrorMessagesForCommonPatterns/unsupported_size()_argument_type (0.00s)
+=== RUN TestProviderErrors
+=== RUN TestProviderErrors/enum_value_error_should_not_leak_enum_name
+=== RUN TestProviderErrors/new_value_error_should_not_leak_type_name
+--- PASS: TestProviderErrors (0.00s)
+ --- PASS: TestProviderErrors/enum_value_error_should_not_leak_enum_name (0.00s)
+ --- PASS: TestProviderErrors/new_value_error_should_not_leak_type_name (0.00s)
+=== RUN TestErrorWrapping
+--- PASS: TestErrorWrapping (0.00s)
+=== RUN TestErrorMessagesNoSensitiveInfo
+=== RUN TestErrorMessagesNoSensitiveInfo/obj.name
+=== RUN TestErrorMessagesNoSensitiveInfo/obj.age_>_18
+=== RUN TestErrorMessagesNoSensitiveInfo/obj.unknown_field_==_"test"
+--- PASS: TestErrorMessagesNoSensitiveInfo (0.00s)
+ --- PASS: TestErrorMessagesNoSensitiveInfo/obj.name (0.00s)
+ --- PASS: TestErrorMessagesNoSensitiveInfo/obj.age_>_18 (0.00s)
+ --- PASS: TestErrorMessagesNoSensitiveInfo/obj.unknown_field_==_"test" (0.00s)
+=== RUN TestContextCancellationError
+--- PASS: TestContextCancellationError (0.00s)
+=== RUN TestErrorInterface
+--- PASS: TestErrorInterface (0.00s)
+=== RUN TestEXPLAINValidation
+2025/10/31 08:26:18 github.com/testcontainers/testcontainers-go - Connected to docker:
+ Server Version: 28.4.0
+ API Version: 1.51
+ Operating System: Docker Desktop
+ Total Memory: 7837 MB
+ Labels:
+ com.docker.desktop.address=unix:///Users/richardwooding/Library/Containers/com.docker.docker/Data/docker-cli.sock
+ Testcontainers for Go Version: v0.38.0
+ Resolved Docker Host: unix:///var/run/docker.sock
+ Resolved Docker Socket Path: /var/run/docker.sock
+ Test SessionID: 7dd9e19bf9b85ae429b118db0b8b19122cea258e87959ab4cc7b9aa2d249cca3
+ Test ProcessID: 606f2816-db1e-45ad-9bae-5e4649d24fe0
+2025/10/31 08:26:18 🐳 Creating container for image postgres:17-alpine
+2025/10/31 08:26:18 ⏳ Waiting for Reaper "26d01e78" to be ready
+2025/10/31 08:26:18 🔥 Reaper obtained from Docker for this test session 26d01e78
+2025/10/31 08:26:18 ✅ Container created: ab509da101ff
+2025/10/31 08:26:18 🐳 Starting container: ab509da101ff
+2025/10/31 08:26:18 ✅ Container started: ab509da101ff
+2025/10/31 08:26:18 ⏳ Waiting for container id ab509da101ff image: postgres:17-alpine. Waiting for: &{timeout: Log:database system is ready to accept connections IsRegexp:false Occurrence:2 PollInterval:100ms check: submatchCallback: re: log:[]}
+2025/10/31 08:26:19 🔔 Container is ready: ab509da101ff
+=== RUN TestEXPLAINValidation/Simple_equality_condition
+ explain_validation_test.go:210: CEL Expression: email == "alice@example.com"
+ explain_validation_test.go:211: Generated SQL WHERE clause: email = 'alice@example.com'
+ explain_validation_test.go:216: EXPLAIN Query: EXPLAIN SELECT * FROM users WHERE email = 'alice@example.com'
+ explain_validation_test.go:233: Plan: Bitmap Heap Scan on users (cost=4.16..9.50 rows=2 width=153)
+ explain_validation_test.go:233: Plan: Recheck Cond: (email = 'alice@example.com'::text)
+ explain_validation_test.go:233: Plan: -> Bitmap Index Scan on idx_users_email (cost=0.00..4.16 rows=2 width=0)
+ explain_validation_test.go:233: Plan: Index Cond: (email = 'alice@example.com'::text)
+ explain_validation_test.go:253: ✓ EXPLAIN validation passed: Basic WHERE clause should produce valid query plan
+=== RUN TestEXPLAINValidation/Multiple_AND_conditions
+ explain_validation_test.go:210: CEL Expression: age > 25 && active == true
+ explain_validation_test.go:211: Generated SQL WHERE clause: age > 25 AND active IS TRUE
+ explain_validation_test.go:216: EXPLAIN Query: EXPLAIN SELECT * FROM users WHERE age > 25 AND active IS TRUE
+ explain_validation_test.go:233: Plan: Seq Scan on users (cost=0.00..15.62 rows=75 width=153)
+ explain_validation_test.go:233: Plan: Filter: ((active IS TRUE) AND (age > 25))
+ explain_validation_test.go:253: ✓ EXPLAIN validation passed: Multiple conditions should be optimizable
+=== RUN TestEXPLAINValidation/OR_conditions
+ explain_validation_test.go:210: CEL Expression: age < 30 || score > 90.0
+ explain_validation_test.go:211: Generated SQL WHERE clause: age < 30 OR (score)::numeric > 90
+ explain_validation_test.go:216: EXPLAIN Query: EXPLAIN SELECT * FROM users WHERE age < 30 OR (score)::numeric > 90
+ explain_validation_test.go:233: Plan: Seq Scan on users (cost=0.00..17.88 rows=250 width=153)
+ explain_validation_test.go:233: Plan: Filter: ((age < 30) OR ((score)::numeric > '90'::numeric))
+ explain_validation_test.go:253: ✓ EXPLAIN validation passed: OR conditions should produce valid plan
+=== RUN TestEXPLAINValidation/Array_membership
+ explain_validation_test.go:210: CEL Expression: "admin" in tags
+ explain_validation_test.go:211: Generated SQL WHERE clause: 'admin' = ANY(tags)
+ explain_validation_test.go:216: EXPLAIN Query: EXPLAIN SELECT * FROM users WHERE 'admin' = ANY(tags)
+ explain_validation_test.go:233: Plan: Seq Scan on users (cost=0.00..20.12 rows=2 width=153)
+ explain_validation_test.go:233: Plan: Filter: ('admin'::text = ANY (tags))
+ explain_validation_test.go:253: ✓ EXPLAIN validation passed: Array operations should be valid
+=== RUN TestEXPLAINValidation/Complex_nested_condition
+ explain_validation_test.go:210: CEL Expression: (age > 25 && active) || (score > 90.0 && !active)
+ explain_validation_test.go:211: Generated SQL WHERE clause: age > 25 AND active OR (score)::numeric > 90 AND NOT active
+ explain_validation_test.go:216: EXPLAIN Query: EXPLAIN SELECT * FROM users WHERE age > 25 AND active OR (score)::numeric > 90 AND NOT active
+ explain_validation_test.go:233: Plan: Seq Scan on users (cost=0.00..17.88 rows=138 width=153)
+ explain_validation_test.go:233: Plan: Filter: (((age > 25) AND active) OR (((score)::numeric > '90'::numeric) AND (NOT active)))
+ explain_validation_test.go:253: ✓ EXPLAIN validation passed: Complex nested boolean logic should be optimizable
+=== RUN TestEXPLAINValidation/String_operations
+ explain_validation_test.go:210: CEL Expression: name.contains("li")
+ explain_validation_test.go:211: Generated SQL WHERE clause: POSITION('li' IN name) > 0
+ explain_validation_test.go:216: EXPLAIN Query: EXPLAIN SELECT * FROM users WHERE POSITION('li' IN name) > 0
+ explain_validation_test.go:233: Plan: Seq Scan on users (cost=0.00..16.75 rows=150 width=153)
+ explain_validation_test.go:233: Plan: Filter: (POSITION(('li'::text) IN (name)) > 0)
+ explain_validation_test.go:253: ✓ EXPLAIN validation passed: String functions should produce valid plans
+=== RUN TestEXPLAINValidation/Timestamp_comparison
+ explain_validation_test.go:210: CEL Expression: created_at > timestamp("2024-01-01T00:00:00Z")
+ explain_validation_test.go:211: Generated SQL WHERE clause: created_at > CAST('2024-01-01T00:00:00Z' AS TIMESTAMP WITH TIME ZONE)
+ explain_validation_test.go:216: EXPLAIN Query: EXPLAIN SELECT * FROM users WHERE created_at > CAST('2024-01-01T00:00:00Z' AS TIMESTAMP WITH TIME ZONE)
+ explain_validation_test.go:233: Plan: Seq Scan on users (cost=0.00..15.62 rows=150 width=153)
+ explain_validation_test.go:233: Plan: Filter: (created_at > '2024-01-01 00:00:00+00'::timestamp with time zone)
+ explain_validation_test.go:253: ✓ EXPLAIN validation passed: Timestamp operations should be valid
+2025/10/31 08:26:19 🐳 Stopping container: ab509da101ff
+2025/10/31 08:26:19 ✅ Container stopped: ab509da101ff
+2025/10/31 08:26:19 🐳 Terminating container: ab509da101ff
+2025/10/31 08:26:19 🚫 Container terminated: ab509da101ff
+--- PASS: TestEXPLAINValidation (1.46s)
+ --- PASS: TestEXPLAINValidation/Simple_equality_condition (0.00s)
+ --- PASS: TestEXPLAINValidation/Multiple_AND_conditions (0.00s)
+ --- PASS: TestEXPLAINValidation/OR_conditions (0.00s)
+ --- PASS: TestEXPLAINValidation/Array_membership (0.00s)
+ --- PASS: TestEXPLAINValidation/Complex_nested_condition (0.00s)
+ --- PASS: TestEXPLAINValidation/String_operations (0.00s)
+ --- PASS: TestEXPLAINValidation/Timestamp_comparison (0.00s)
+=== RUN TestEXPLAINAnalyzeValidation
+2025/10/31 08:26:19 🐳 Creating container for image postgres:17-alpine
+2025/10/31 08:26:19 ✅ Container created: 71fc70b81359
+2025/10/31 08:26:19 🐳 Starting container: 71fc70b81359
+2025/10/31 08:26:19 ✅ Container started: 71fc70b81359
+2025/10/31 08:26:19 ⏳ Waiting for container id 71fc70b81359 image: postgres:17-alpine. Waiting for: &{timeout: Log:database system is ready to accept connections IsRegexp:false Occurrence:2 PollInterval:100ms check: submatchCallback: re: log:[]}
+2025/10/31 08:26:20 🔔 Container is ready: 71fc70b81359
+=== RUN TestEXPLAINAnalyzeValidation/Filter_by_price_range
+ explain_validation_test.go:380: CEL Expression: price > 50.0 && price < 500.0
+ explain_validation_test.go:381: Generated SQL WHERE clause: price > 50 AND price < 500
+ explain_validation_test.go:386: EXPLAIN ANALYZE Query: EXPLAIN ANALYZE SELECT * FROM products WHERE price > 50 AND price < 500
+ explain_validation_test.go:404: Plan: Seq Scan on products (cost=0.00..21.55 rows=4 width=77) (actual time=0.004..0.004 rows=2 loops=1)
+ explain_validation_test.go:404: Plan: Filter: ((price > '50'::double precision) AND (price < '500'::double precision))
+ explain_validation_test.go:404: Plan: Rows Removed by Filter: 2
+ explain_validation_test.go:404: Plan: Planning Time: 0.037 ms
+ explain_validation_test.go:404: Plan: Execution Time: 0.009 ms
+ explain_validation_test.go:424: ✓ EXPLAIN ANALYZE validation passed: Price range filtering should return correct count
+ explain_validation_test.go:436: ✓ Row count validation passed: expected 2, got 2
+=== RUN TestEXPLAINAnalyzeValidation/Filter_by_stock_status
+ explain_validation_test.go:380: CEL Expression: in_stock == true
+ explain_validation_test.go:381: Generated SQL WHERE clause: in_stock IS TRUE
+ explain_validation_test.go:386: EXPLAIN ANALYZE Query: EXPLAIN ANALYZE SELECT * FROM products WHERE in_stock IS TRUE
+ explain_validation_test.go:404: Plan: Seq Scan on products (cost=0.00..17.70 rows=385 width=77) (actual time=0.004..0.005 rows=3 loops=1)
+ explain_validation_test.go:404: Plan: Filter: (in_stock IS TRUE)
+ explain_validation_test.go:404: Plan: Rows Removed by Filter: 1
+ explain_validation_test.go:404: Plan: Planning Time: 0.019 ms
+ explain_validation_test.go:404: Plan: Execution Time: 0.010 ms
+ explain_validation_test.go:424: ✓ EXPLAIN ANALYZE validation passed: Boolean filtering should work correctly
+ explain_validation_test.go:436: ✓ Row count validation passed: expected 3, got 3
+=== RUN TestEXPLAINAnalyzeValidation/Array_membership
+ explain_validation_test.go:380: CEL Expression: "electronics" in categories
+ explain_validation_test.go:381: Generated SQL WHERE clause: 'electronics' = ANY(categories)
+ explain_validation_test.go:386: EXPLAIN ANALYZE Query: EXPLAIN ANALYZE SELECT * FROM products WHERE 'electronics' = ANY(categories)
+ explain_validation_test.go:404: Plan: Seq Scan on products (cost=0.00..27.32 rows=4 width=77) (actual time=0.007..0.008 rows=2 loops=1)
+ explain_validation_test.go:404: Plan: Filter: ('electronics'::text = ANY (categories))
+ explain_validation_test.go:404: Plan: Rows Removed by Filter: 2
+ explain_validation_test.go:404: Plan: Planning Time: 0.184 ms
+ explain_validation_test.go:404: Plan: Execution Time: 0.013 ms
+ explain_validation_test.go:424: ✓ EXPLAIN ANALYZE validation passed: Array membership check should return correct results
+ explain_validation_test.go:436: ✓ Row count validation passed: expected 2, got 2
+=== RUN TestEXPLAINAnalyzeValidation/Complex_condition
+ explain_validation_test.go:380: CEL Expression: in_stock && price < 300.0
+ explain_validation_test.go:381: Generated SQL WHERE clause: in_stock AND price < 300
+ explain_validation_test.go:386: EXPLAIN ANALYZE Query: EXPLAIN ANALYZE SELECT * FROM products WHERE in_stock AND price < 300
+ explain_validation_test.go:404: Plan: Seq Scan on products (cost=0.00..19.62 rows=128 width=77) (actual time=0.006..0.007 rows=2 loops=1)
+ explain_validation_test.go:404: Plan: Filter: (in_stock AND (price < '300'::double precision))
+ explain_validation_test.go:404: Plan: Rows Removed by Filter: 2
+ explain_validation_test.go:404: Plan: Planning Time: 0.041 ms
+ explain_validation_test.go:404: Plan: Execution Time: 0.013 ms
+ explain_validation_test.go:424: ✓ EXPLAIN ANALYZE validation passed: Complex conditions should execute correctly
+ explain_validation_test.go:436: ✓ Row count validation passed: expected 2, got 2
+2025/10/31 08:26:20 🐳 Stopping container: 71fc70b81359
+2025/10/31 08:26:20 ✅ Container stopped: 71fc70b81359
+2025/10/31 08:26:20 🐳 Terminating container: 71fc70b81359
+2025/10/31 08:26:20 🚫 Container terminated: 71fc70b81359
+--- PASS: TestEXPLAINAnalyzeValidation (1.10s)
+ --- PASS: TestEXPLAINAnalyzeValidation/Filter_by_price_range (0.00s)
+ --- PASS: TestEXPLAINAnalyzeValidation/Filter_by_stock_status (0.00s)
+ --- PASS: TestEXPLAINAnalyzeValidation/Array_membership (0.00s)
+ --- PASS: TestEXPLAINAnalyzeValidation/Complex_condition (0.00s)
+=== RUN TestFieldNameValidation_Integration
+=== RUN TestFieldNameValidation_Integration/valid_simple_field
+=== RUN TestFieldNameValidation_Integration/valid_field_with_numbers
+=== RUN TestFieldNameValidation_Integration/reserved_keyword:_select
+=== RUN TestFieldNameValidation_Integration/reserved_keyword:_where
+=== RUN TestFieldNameValidation_Integration/reserved_keyword:_from
+=== RUN TestFieldNameValidation_Integration/reserved_keyword:_union
+=== RUN TestFieldNameValidation_Integration/reserved_keyword:_drop
+--- PASS: TestFieldNameValidation_Integration (0.01s)
+ --- PASS: TestFieldNameValidation_Integration/valid_simple_field (0.00s)
+ --- PASS: TestFieldNameValidation_Integration/valid_field_with_numbers (0.00s)
+ --- PASS: TestFieldNameValidation_Integration/reserved_keyword:_select (0.00s)
+ --- PASS: TestFieldNameValidation_Integration/reserved_keyword:_where (0.00s)
+ --- PASS: TestFieldNameValidation_Integration/reserved_keyword:_from (0.00s)
+ --- PASS: TestFieldNameValidation_Integration/reserved_keyword:_union (0.00s)
+ --- PASS: TestFieldNameValidation_Integration/reserved_keyword:_drop (0.00s)
+=== RUN TestFieldNameValidation_Identifiers
+=== RUN TestFieldNameValidation_Identifiers/valid_identifier
+=== RUN TestFieldNameValidation_Identifiers/valid_identifier_with_underscore
+=== RUN TestFieldNameValidation_Identifiers/reserved_keyword_identifier
+=== RUN TestFieldNameValidation_Identifiers/reserved_keyword:_table
+--- PASS: TestFieldNameValidation_Identifiers (0.00s)
+ --- PASS: TestFieldNameValidation_Identifiers/valid_identifier (0.00s)
+ --- PASS: TestFieldNameValidation_Identifiers/valid_identifier_with_underscore (0.00s)
+ --- PASS: TestFieldNameValidation_Identifiers/reserved_keyword_identifier (0.00s)
+ --- PASS: TestFieldNameValidation_Identifiers/reserved_keyword:_table (0.00s)
+=== RUN TestFieldNameValidation_MaxLength
+=== RUN TestFieldNameValidation_MaxLength/field_length_validation_exists
+ field_validation_test.go:203: Comprehensive length validation tests are in utils_test.go
+ field_validation_test.go:204: This confirms validation is integrated into the conversion pipeline
+--- PASS: TestFieldNameValidation_MaxLength (0.00s)
+ --- PASS: TestFieldNameValidation_MaxLength/field_length_validation_exists (0.00s)
+=== RUN TestFieldNameValidation_PreventsSQLInjection
+=== RUN TestFieldNameValidation_PreventsSQLInjection/cannot_use_semicolon_in_field_name
+=== RUN TestFieldNameValidation_PreventsSQLInjection/cannot_use_spaces_in_field_name
+=== NAME TestFieldNameValidation_PreventsSQLInjection
+ field_validation_test.go:250: Note: Comprehensive field name validation tests are in utils_test.go
+ field_validation_test.go:251: This test verifies CEL provides first line of defense against injection
+--- PASS: TestFieldNameValidation_PreventsSQLInjection (0.00s)
+ --- PASS: TestFieldNameValidation_PreventsSQLInjection/cannot_use_semicolon_in_field_name (0.00s)
+ --- PASS: TestFieldNameValidation_PreventsSQLInjection/cannot_use_spaces_in_field_name (0.00s)
+=== RUN TestFieldNameValidation_EdgeCases
+=== RUN TestFieldNameValidation_EdgeCases/single_character
+=== RUN TestFieldNameValidation_EdgeCases/single_underscore
+=== RUN TestFieldNameValidation_EdgeCases/all_underscores
+=== RUN TestFieldNameValidation_EdgeCases/starts_with_underscore
+=== RUN TestFieldNameValidation_EdgeCases/all_caps
+=== RUN TestFieldNameValidation_EdgeCases/mixed_case
+--- PASS: TestFieldNameValidation_EdgeCases (0.00s)
+ --- PASS: TestFieldNameValidation_EdgeCases/single_character (0.00s)
+ --- PASS: TestFieldNameValidation_EdgeCases/single_underscore (0.00s)
+ --- PASS: TestFieldNameValidation_EdgeCases/all_underscores (0.00s)
+ --- PASS: TestFieldNameValidation_EdgeCases/starts_with_underscore (0.00s)
+ --- PASS: TestFieldNameValidation_EdgeCases/all_caps (0.00s)
+ --- PASS: TestFieldNameValidation_EdgeCases/mixed_case (0.00s)
+=== RUN TestJSONFieldContains
+=== RUN TestJSONFieldContains/json_field_contains_string
+ final_coverage_test.go:59: Generated SQL: POSITION('important' IN doc.tags) > 0
+=== RUN TestJSONFieldContains/json_nested_field_contains
+ final_coverage_test.go:59: Generated SQL: POSITION('value' IN doc.metadata->>'items') > 0
+--- PASS: TestJSONFieldContains (0.00s)
+ --- PASS: TestJSONFieldContains/json_field_contains_string (0.00s)
+ --- PASS: TestJSONFieldContains/json_nested_field_contains (0.00s)
+=== RUN TestNestedJSONHasOperations
+=== RUN TestNestedJSONHasOperations/nested_json_has_two_levels
+ final_coverage_test.go:145: Generated SQL for has() with two-level nested JSON path: jsonb_extract_path_text(record.metadata, 'user', 'name') IS NOT NULL
+=== RUN TestNestedJSONHasOperations/nested_json_has_three_levels
+ final_coverage_test.go:145: Generated SQL for has() with three-level nested JSON path: jsonb_extract_path_text(record.metadata, 'settings', 'permissions', 'read') IS NOT NULL
+=== RUN TestNestedJSONHasOperations/nested_json_has_properties
+ final_coverage_test.go:145: Generated SQL for has() on different JSON column: jsonb_extract_path_text(record.properties, 'config', 'enabled') IS NOT NULL
+=== RUN TestNestedJSONHasOperations/nested_json_has_deep_path
+ final_coverage_test.go:145: Generated SQL for has() with deeply nested path (5 levels): jsonb_extract_path_text(record.metadata, 'a', 'b', 'c', 'd', 'e') IS NOT NULL
+--- PASS: TestNestedJSONHasOperations (0.00s)
+ --- PASS: TestNestedJSONHasOperations/nested_json_has_two_levels (0.00s)
+ --- PASS: TestNestedJSONHasOperations/nested_json_has_three_levels (0.00s)
+ --- PASS: TestNestedJSONHasOperations/nested_json_has_properties (0.00s)
+ --- PASS: TestNestedJSONHasOperations/nested_json_has_deep_path (0.00s)
+=== RUN TestAdditionalFunctionTypes
+=== RUN TestAdditionalFunctionTypes/extract_year_from_timestamp
+ final_coverage_test.go:258: Generated SQL for getFullYear() on timestamp: EXTRACT(YEAR FROM record.created) = 2024
+=== RUN TestAdditionalFunctionTypes/extract_month_from_timestamp
+ final_coverage_test.go:258: Generated SQL for getMonth() on timestamp: EXTRACT(MONTH FROM record.created) - 1 = 11
+=== RUN TestAdditionalFunctionTypes/extract_day_from_timestamp
+ final_coverage_test.go:258: Generated SQL for getDate() on timestamp: EXTRACT(DAY FROM record.created) = 15
+=== RUN TestAdditionalFunctionTypes/extract_hours_from_timestamp
+ final_coverage_test.go:258: Generated SQL for getHours() on timestamp: EXTRACT(HOUR FROM record.created) >= 9
+=== RUN TestAdditionalFunctionTypes/extract_minutes_from_timestamp
+ final_coverage_test.go:258: Generated SQL for getMinutes() on timestamp: EXTRACT(MINUTE FROM record.created) < 30
+=== RUN TestAdditionalFunctionTypes/extract_seconds_from_timestamp
+ final_coverage_test.go:258: Generated SQL for getSeconds() on timestamp: EXTRACT(SECOND FROM record.created) > 0
+=== RUN TestAdditionalFunctionTypes/extract_day_of_week
+ final_coverage_test.go:258: Generated SQL for getDayOfWeek() on timestamp: (EXTRACT(DOW FROM record.created) + 6) % 7 = 1
+=== RUN TestAdditionalFunctionTypes/extract_day_of_year
+ final_coverage_test.go:258: Generated SQL for getDayOfYear() on timestamp: EXTRACT(DOY FROM record.created) - 1 > 100
+--- PASS: TestAdditionalFunctionTypes (0.00s)
+ --- PASS: TestAdditionalFunctionTypes/extract_year_from_timestamp (0.00s)
+ --- PASS: TestAdditionalFunctionTypes/extract_month_from_timestamp (0.00s)
+ --- PASS: TestAdditionalFunctionTypes/extract_day_from_timestamp (0.00s)
+ --- PASS: TestAdditionalFunctionTypes/extract_hours_from_timestamp (0.00s)
+ --- PASS: TestAdditionalFunctionTypes/extract_minutes_from_timestamp (0.00s)
+ --- PASS: TestAdditionalFunctionTypes/extract_seconds_from_timestamp (0.00s)
+ --- PASS: TestAdditionalFunctionTypes/extract_day_of_week (0.00s)
+ --- PASS: TestAdditionalFunctionTypes/extract_day_of_year (0.00s)
+=== RUN TestBinaryOperatorAdditionalCases
+=== RUN TestBinaryOperatorAdditionalCases/bytes_concatenation
+ final_coverage_test.go:316: Generated SQL: '\x68656c6c6f' || '\x20776f726c64' != '\x'
+=== RUN TestBinaryOperatorAdditionalCases/json_numeric_comparison_cast
+ final_coverage_test.go:316: Generated SQL: (record.metadata->>'count')::numeric > 100
+=== RUN TestBinaryOperatorAdditionalCases/json_nested_numeric_comparison
+ final_coverage_test.go:316: Generated SQL: (record.metadata->'stats'->>'total')::numeric < 1000
+--- PASS: TestBinaryOperatorAdditionalCases (0.00s)
+ --- PASS: TestBinaryOperatorAdditionalCases/bytes_concatenation (0.00s)
+ --- PASS: TestBinaryOperatorAdditionalCases/json_numeric_comparison_cast (0.00s)
+ --- PASS: TestBinaryOperatorAdditionalCases/json_nested_numeric_comparison (0.00s)
+=== RUN TestIdentifierWithNumericCasting
+=== RUN TestIdentifierWithNumericCasting/json_comprehension_with_score
+ final_coverage_test.go:382: Generated SQL for Comprehension with 'score' iterator (may need numeric cast): NOT EXISTS (SELECT 1 FROM UNNEST(doc.items) AS score WHERE NOT ((score)::numeric > 50))
+=== RUN TestIdentifierWithNumericCasting/json_comprehension_with_value
+ final_coverage_test.go:382: Generated SQL for Comprehension with 'value' iterator (may need numeric cast): EXISTS (SELECT 1 FROM UNNEST(doc.items) AS value WHERE (value)::numeric >= 100)
+=== RUN TestIdentifierWithNumericCasting/json_comprehension_with_amount
+ final_coverage_test.go:382: Generated SQL for Comprehension with 'amount' iterator (may need numeric cast): ARRAY(SELECT (amount)::numeric FROM UNNEST(doc.items) AS amount WHERE (amount)::numeric > 0)
+--- PASS: TestIdentifierWithNumericCasting (0.00s)
+ --- PASS: TestIdentifierWithNumericCasting/json_comprehension_with_score (0.00s)
+ --- PASS: TestIdentifierWithNumericCasting/json_comprehension_with_value (0.00s)
+ --- PASS: TestIdentifierWithNumericCasting/json_comprehension_with_amount (0.00s)
+=== RUN TestJSONColumnReferenceEdgeCases
+=== RUN TestJSONColumnReferenceEdgeCases/has_on_structure_column
+ final_coverage_test.go:462: Generated SQL for has() on 'structure' JSON column (known column name): jsonb_extract_path_text(asset.structure, 'level', 'parent') IS NOT NULL
+=== RUN TestJSONColumnReferenceEdgeCases/has_on_taxonomy_column
+ final_coverage_test.go:462: Generated SQL for has() on 'taxonomy' JSON column: jsonb_extract_path_text(asset.taxonomy, 'category', 'main') IS NOT NULL
+=== RUN TestJSONColumnReferenceEdgeCases/has_on_analytics_column
+ final_coverage_test.go:462: Generated SQL for has() on 'analytics' JSON column: jsonb_extract_path_text(asset.analytics, 'views', 'total') IS NOT NULL
+=== RUN TestJSONColumnReferenceEdgeCases/has_on_classification_column
+ final_coverage_test.go:462: Generated SQL for has() on 'classification' JSON column: jsonb_extract_path_text(asset.classification, 'level', 'value') IS NOT NULL
+--- PASS: TestJSONColumnReferenceEdgeCases (0.00s)
+ --- PASS: TestJSONColumnReferenceEdgeCases/has_on_structure_column (0.00s)
+ --- PASS: TestJSONColumnReferenceEdgeCases/has_on_taxonomy_column (0.00s)
+ --- PASS: TestJSONColumnReferenceEdgeCases/has_on_analytics_column (0.00s)
+ --- PASS: TestJSONColumnReferenceEdgeCases/has_on_classification_column (0.00s)
+=== RUN TestJSONFieldNameEscaping_SingleQuote
+=== RUN TestJSONFieldNameEscaping_SingleQuote/JSON_field_with_single_quote_in_name
+=== RUN TestJSONFieldNameEscaping_SingleQuote/Nested_JSON_access
+--- PASS: TestJSONFieldNameEscaping_SingleQuote (0.00s)
+ --- PASS: TestJSONFieldNameEscaping_SingleQuote/JSON_field_with_single_quote_in_name (0.00s)
+ --- PASS: TestJSONFieldNameEscaping_SingleQuote/Nested_JSON_access (0.00s)
+=== RUN TestJSONFieldNameEscaping_Documentation
+ json_escaping_test.go:70: This test documents that JSON field names are escaped in generated SQL
+ json_escaping_test.go:71: Single quotes in field names would be escaped by doubling them: ' -> ''
+ json_escaping_test.go:72: The escapeJSONFieldName() function in utils.go handles this escaping
+ json_escaping_test.go:73: All JSON path operators (->, ->>, ?) use escapeJSONFieldName() for security
+--- PASS: TestJSONFieldNameEscaping_Documentation (0.00s)
+=== RUN TestJSONFieldNameEscaping_HasFunction
+=== RUN TestJSONFieldNameEscaping_HasFunction/has()_with_JSON_field
+ json_escaping_test.go:118: Generated SQL: jsonb_extract_path_text(obj, 'settings', 'theme') IS NOT NULL
+--- PASS: TestJSONFieldNameEscaping_HasFunction (0.00s)
+ --- PASS: TestJSONFieldNameEscaping_HasFunction/has()_with_JSON_field (0.00s)
+=== RUN TestEscapeJSONFieldNameFunction
+ json_escaping_test.go:128: The escapeJSONFieldName() function in utils.go escapes single quotes
+ json_escaping_test.go:129: Example: "user's name" -> "user''s name"
+ json_escaping_test.go:130: This prevents SQL injection when field names contain single quotes
+ json_escaping_test.go:131: The function is used in:
+ json_escaping_test.go:132: - cel2sql.go: visitSelect() for -> and ->> operators
+ json_escaping_test.go:133: - cel2sql.go: visitHasFunction() for ? and -> operators
+ json_escaping_test.go:134: - cel2sql.go: visitNestedJSONHas() for jsonb_extract_path_text()
+ json_escaping_test.go:135: - json.go: buildJSONPathForArray() for nested JSON paths
+ json_escaping_test.go:136: - json.go: buildJSONPathInternal() for all JSON path construction
+--- PASS: TestEscapeJSONFieldNameFunction (0.00s)
+=== RUN TestJSONFieldNameEscaping_SecurityImplications
+ json_escaping_test.go:141: Security Impact: SQL Injection Prevention
+ json_escaping_test.go:142:
+ json_escaping_test.go:143: Without escaping, a field name like: user' OR '1'='1
+ json_escaping_test.go:144: Would generate SQL like: col->'user' OR '1'='1'
+ json_escaping_test.go:145: Breaking out of the string literal and injecting SQL
+ json_escaping_test.go:146:
+ json_escaping_test.go:147: With escaping, the same field name becomes: user'' OR ''1''=''1
+ json_escaping_test.go:148: And generates safe SQL: col->'user'' OR ''1''=''1'
+ json_escaping_test.go:149: The single quotes are escaped, treating the whole thing as a field name
+ json_escaping_test.go:150:
+ json_escaping_test.go:151: This fix addresses CWE-89: SQL Injection
+ json_escaping_test.go:152: By ensuring all field names in JSON operators are properly escaped
+--- PASS: TestJSONFieldNameEscaping_SecurityImplications (0.00s)
+=== RUN TestGeneratedSQLAgainstPostgreSQL
+2025/10/31 08:26:20 🐳 Creating container for image postgres:17-alpine
+2025/10/31 08:26:20 ✅ Container created: 3bf4a2f226b9
+2025/10/31 08:26:20 🐳 Starting container: 3bf4a2f226b9
+2025/10/31 08:26:20 ✅ Container started: 3bf4a2f226b9
+2025/10/31 08:26:20 ⏳ Waiting for container id 3bf4a2f226b9 image: postgres:17-alpine. Waiting for: &{timeout: Log:database system is ready to accept connections IsRegexp:false Occurrence:2 PollInterval:100ms check: submatchCallback: re: log:[]}
+2025/10/31 08:26:21 🔔 Container is ready: 3bf4a2f226b9
+=== RUN TestGeneratedSQLAgainstPostgreSQL/Simple_JSON_field_access
+ json_integration_validation_test.go:122: CEL Expression: obj.metadata.user_name == "test"
+ json_integration_validation_test.go:123: Generated SQL WHERE clause: obj.metadata->>'user_name' = 'test'
+ json_integration_validation_test.go:128: Full SQL Query: SELECT * FROM obj WHERE obj.metadata->>'user_name' = 'test'
+ json_integration_validation_test.go:144: ✓ Generated SQL works correctly and returns expected results
+=== RUN TestGeneratedSQLAgainstPostgreSQL/Nested_JSON_access
+ json_integration_validation_test.go:122: CEL Expression: obj.metadata.settings.theme == "dark"
+ json_integration_validation_test.go:123: Generated SQL WHERE clause: obj.metadata->'settings'->>'theme' = 'dark'
+ json_integration_validation_test.go:128: Full SQL Query: SELECT * FROM obj WHERE obj.metadata->'settings'->>'theme' = 'dark'
+ json_integration_validation_test.go:144: ✓ Generated SQL works correctly and returns expected results
+2025/10/31 08:26:21 🐳 Stopping container: 3bf4a2f226b9
+2025/10/31 08:26:21 ✅ Container stopped: 3bf4a2f226b9
+2025/10/31 08:26:21 🐳 Terminating container: 3bf4a2f226b9
+2025/10/31 08:26:21 🚫 Container terminated: 3bf4a2f226b9
+--- PASS: TestGeneratedSQLAgainstPostgreSQL (1.06s)
+ --- PASS: TestGeneratedSQLAgainstPostgreSQL/Simple_JSON_field_access (0.00s)
+ --- PASS: TestGeneratedSQLAgainstPostgreSQL/Nested_JSON_access (0.00s)
+=== RUN TestJSONBFieldDetection
+=== RUN TestJSONBFieldDetection/jsonb_field_access
+ json_jsonb_coverage_test.go:70: Generated SQL for Access JSONB field - should use ->> operator: record.jsonb_data->>'name' = 'test'
+=== RUN TestJSONBFieldDetection/jsonb_nested_access
+ json_jsonb_coverage_test.go:70: Generated SQL for Nested JSONB field access: (record.jsonb_metadata->'user'->>'id')::numeric > 0
+=== RUN TestJSONBFieldDetection/has_on_jsonb
+ json_jsonb_coverage_test.go:70: Generated SQL for has() function on JSONB field: jsonb_extract_path_text(record, 'jsonb_data', 'active') IS NOT NULL
+=== RUN TestJSONBFieldDetection/json_field_access
+ json_jsonb_coverage_test.go:70: Generated SQL for Access JSON (not JSONB) field: record.json_data->>'status' = 'ok'
+--- PASS: TestJSONBFieldDetection (0.00s)
+ --- PASS: TestJSONBFieldDetection/jsonb_field_access (0.00s)
+ --- PASS: TestJSONBFieldDetection/jsonb_nested_access (0.00s)
+ --- PASS: TestJSONBFieldDetection/has_on_jsonb (0.00s)
+ --- PASS: TestJSONBFieldDetection/json_field_access (0.00s)
+=== RUN TestArrayFieldDetection
+=== RUN TestArrayFieldDetection/int_array_comprehension
+ json_jsonb_coverage_test.go:134: Generated SQL for Comprehension on integer array: NOT EXISTS (SELECT 1 FROM UNNEST(data.int_array) AS x WHERE NOT (x > 0))
+=== RUN TestArrayFieldDetection/text_array_comprehension
+ json_jsonb_coverage_test.go:134: Generated SQL for Comprehension on text array: EXISTS (SELECT 1 FROM UNNEST(data.text_array) AS x WHERE x LIKE 'prefix%' ESCAPE E'\\')
+=== RUN TestArrayFieldDetection/double_array_comprehension
+ json_jsonb_coverage_test.go:134: Generated SQL for Filter on double precision array: ARRAY(SELECT x FROM UNNEST(data.double_array) AS x WHERE x >= 0.5)
+=== RUN TestArrayFieldDetection/array_exists_one
+ json_jsonb_coverage_test.go:134: Generated SQL for exists_one on integer array: (SELECT COUNT(*) FROM UNNEST(data.int_array) AS x WHERE x = 42) = 1
+--- PASS: TestArrayFieldDetection (0.00s)
+ --- PASS: TestArrayFieldDetection/int_array_comprehension (0.00s)
+ --- PASS: TestArrayFieldDetection/text_array_comprehension (0.00s)
+ --- PASS: TestArrayFieldDetection/double_array_comprehension (0.00s)
+ --- PASS: TestArrayFieldDetection/array_exists_one (0.00s)
+=== RUN TestJSONBWithArrays
+ json_jsonb_coverage_test.go:144: JSONB array .size() operations not yet fully supported
+--- SKIP: TestJSONBWithArrays (0.00s)
+=== RUN TestSchemaEdgeCases
+=== RUN TestSchemaEdgeCases/valid_jsonb_field
+ json_jsonb_coverage_test.go:243: Generated SQL for Valid JSONB field access: table1.data->>'name' = 'test'
+=== RUN TestSchemaEdgeCases/valid_array_field
+ json_jsonb_coverage_test.go:243: Generated SQL for Valid array field comprehension: EXISTS (SELECT 1 FROM UNNEST(table1.array_field) AS x WHERE x = 'value')
+--- PASS: TestSchemaEdgeCases (0.00s)
+ --- PASS: TestSchemaEdgeCases/valid_jsonb_field (0.00s)
+ --- PASS: TestSchemaEdgeCases/valid_array_field (0.00s)
+=== RUN TestNoSchemaProvided
+=== RUN TestNoSchemaProvided/no_schema_field_access
+ json_jsonb_coverage_test.go:286: Generated SQL without schema for Field access without schema: data.name = 'test'
+=== RUN TestNoSchemaProvided/no_schema_has_function
+ json_jsonb_coverage_test.go:286: Generated SQL without schema for has() without schema: data.field IS NOT NULL
+--- PASS: TestNoSchemaProvided (0.00s)
+ --- PASS: TestNoSchemaProvided/no_schema_field_access (0.00s)
+ --- PASS: TestNoSchemaProvided/no_schema_has_function (0.00s)
+=== RUN TestPostgreSQLJSONOperatorValidation
+2025/10/31 08:26:21 🐳 Creating container for image postgres:17-alpine
+2025/10/31 08:26:21 ✅ Container created: 048dbaafbe74
+2025/10/31 08:26:21 🐳 Starting container: 048dbaafbe74
+2025/10/31 08:26:22 ✅ Container started: 048dbaafbe74
+2025/10/31 08:26:22 ⏳ Waiting for container id 048dbaafbe74 image: postgres:17-alpine. Waiting for: &{timeout: Log:database system is ready to accept connections IsRegexp:false Occurrence:2 PollInterval:100ms check: submatchCallback: re: log:[]}
+2025/10/31 08:26:22 🔔 Container is ready: 048dbaafbe74
+=== RUN TestPostgreSQLJSONOperatorValidation/Correct:_table.column->>'field'
+ json_operator_validation_test.go:122: ✓ Query works correctly: SELECT * FROM test_table WHERE metadata->>'user_name' = 'test'
+=== RUN TestPostgreSQLJSONOperatorValidation/WRONG:_table->>'column'->>'field'
+ json_operator_validation_test.go:125: ✓ Query fails as expected: SELECT * FROM test_table WHERE test_table->>'metadata'->>'user_name' = 'test'
+ json_operator_validation_test.go:126: Error: pq: operator does not exist: test_table ->> unknown
+=== RUN TestPostgreSQLJSONOperatorValidation/Correct_nested:_table.column->'intermediate'->>'final'
+ json_operator_validation_test.go:122: ✓ Query works correctly: SELECT * FROM test_table WHERE metadata->'settings'->>'theme' = 'dark'
+=== RUN TestPostgreSQLJSONOperatorValidation/WRONG_nested:_table.column->>'intermediate'->>'final'
+ json_operator_validation_test.go:125: ✓ Query fails as expected: SELECT * FROM test_table WHERE metadata->>'settings'->>'theme' = 'dark'
+ json_operator_validation_test.go:126: Error: pq: operator does not exist: text ->> unknown
+=== RUN TestPostgreSQLJSONOperatorValidation/WRONG_nested:_table->>'column'->'intermediate'->>'final'
+ json_operator_validation_test.go:125: ✓ Query fails as expected: SELECT * FROM test_table WHERE test_table->>'metadata'->'settings'->>'theme' = 'dark'
+ json_operator_validation_test.go:126: Error: pq: operator does not exist: test_table ->> unknown
+=== NAME TestPostgreSQLJSONOperatorValidation
+ json_operator_validation_test.go:132:
+ === VALIDATION RESULTS ===
+ json_operator_validation_test.go:133: For CEL expression: obj.metadata.user_name
+ json_operator_validation_test.go:134: Where obj is a table with a JSONB column 'metadata'
+ json_operator_validation_test.go:135: Correct SQL: obj.metadata->>'user_name'
+ json_operator_validation_test.go:136: NOT: obj->>'metadata'->>'user_name'
+ json_operator_validation_test.go:137:
+ json_operator_validation_test.go:138: For CEL expression: obj.metadata.settings.theme
+ json_operator_validation_test.go:139: Correct SQL: obj.metadata->'settings'->>'theme'
+ json_operator_validation_test.go:140: NOT: obj->>'metadata'->'settings'->>'theme'
+ json_operator_validation_test.go:141: NOT: obj.metadata->>'settings'->>'theme'
+2025/10/31 08:26:22 🐳 Stopping container: 048dbaafbe74
+2025/10/31 08:26:22 ✅ Container stopped: 048dbaafbe74
+2025/10/31 08:26:22 🐳 Terminating container: 048dbaafbe74
+2025/10/31 08:26:22 🚫 Container terminated: 048dbaafbe74
+--- PASS: TestPostgreSQLJSONOperatorValidation (1.04s)
+ --- PASS: TestPostgreSQLJSONOperatorValidation/Correct:_table.column->>'field' (0.00s)
+ --- PASS: TestPostgreSQLJSONOperatorValidation/WRONG:_table->>'column'->>'field' (0.00s)
+ --- PASS: TestPostgreSQLJSONOperatorValidation/Correct_nested:_table.column->'intermediate'->>'final' (0.00s)
+ --- PASS: TestPostgreSQLJSONOperatorValidation/WRONG_nested:_table.column->>'intermediate'->>'final' (0.00s)
+ --- PASS: TestPostgreSQLJSONOperatorValidation/WRONG_nested:_table->>'column'->'intermediate'->>'final' (0.00s)
+=== RUN TestLoggingWithoutExplicitLogger
+--- PASS: TestLoggingWithoutExplicitLogger (0.00s)
+=== RUN TestLoggingWithJSONHandler
+--- PASS: TestLoggingWithJSONHandler (0.00s)
+=== RUN TestLoggingJSONPathDetection
+--- PASS: TestLoggingJSONPathDetection (0.00s)
+=== RUN TestLoggingComprehensions
+--- PASS: TestLoggingComprehensions (0.00s)
+=== RUN TestLoggingOperatorConversion
+--- PASS: TestLoggingOperatorConversion (0.00s)
+=== RUN TestLoggingRegexConversion
+--- PASS: TestLoggingRegexConversion (0.00s)
+=== RUN TestLoggingSchemaLookup
+--- PASS: TestLoggingSchemaLookup (0.00s)
+=== RUN TestLoggingErrorContext
+--- PASS: TestLoggingErrorContext (0.00s)
+=== RUN TestLoggingPerformanceMetrics
+--- PASS: TestLoggingPerformanceMetrics (0.00s)
+=== RUN TestLoggingWithContext
+--- PASS: TestLoggingWithContext (0.00s)
+=== RUN TestLoggingTextHandler
+--- PASS: TestLoggingTextHandler (0.00s)
+=== RUN TestOperatorsIntegration
+2025/10/31 08:26:22 🐳 Creating container for image postgres:17-alpine
+2025/10/31 08:26:23 ✅ Container created: dd7d641b2f97
+2025/10/31 08:26:23 🐳 Starting container: dd7d641b2f97
+2025/10/31 08:26:23 ✅ Container started: dd7d641b2f97
+2025/10/31 08:26:23 ⏳ Waiting for container id dd7d641b2f97 image: postgres:17-alpine. Waiting for: &{timeout: Log:database system is ready to accept connections IsRegexp:false Occurrence:2 PollInterval:100ms check: submatchCallback: re: log:[]}
+2025/10/31 08:26:23 🔔 Container is ready: dd7d641b2f97
+=== RUN TestOperatorsIntegration/Equality_string
+ operators_integration_test.go:329: CEL Expression: text_val == "hello"
+ operators_integration_test.go:330: Generated SQL WHERE clause: text_val = 'hello'
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE text_val = 'hello'
+ operators_integration_test.go:345: ✓ Operator validation passed: String equality comparison (expected 1 rows, got 1 rows)
+=== RUN TestOperatorsIntegration/Equality_integer
+ operators_integration_test.go:329: CEL Expression: int_val == 20
+ operators_integration_test.go:330: Generated SQL WHERE clause: int_val = 20
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE int_val = 20
+ operators_integration_test.go:345: ✓ Operator validation passed: Integer equality comparison (expected 1 rows, got 1 rows)
+=== RUN TestOperatorsIntegration/Equality_float
+ operators_integration_test.go:329: CEL Expression: float_val == 10.5
+ operators_integration_test.go:330: Generated SQL WHERE clause: float_val = 10.5
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE float_val = 10.5
+ operators_integration_test.go:345: ✓ Operator validation passed: Float equality comparison (expected 1 rows, got 1 rows)
+=== RUN TestOperatorsIntegration/Equality_boolean
+ operators_integration_test.go:329: CEL Expression: bool_val == true
+ operators_integration_test.go:330: Generated SQL WHERE clause: bool_val IS TRUE
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE bool_val IS TRUE
+ operators_integration_test.go:345: ✓ Operator validation passed: Boolean equality comparison (expected 3 rows, got 3 rows)
+=== RUN TestOperatorsIntegration/Not_equal
+ operators_integration_test.go:329: CEL Expression: text_val != "hello"
+ operators_integration_test.go:330: Generated SQL WHERE clause: text_val != 'hello'
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE text_val != 'hello'
+ operators_integration_test.go:345: ✓ Operator validation passed: Not equal comparison (expected 4 rows, got 4 rows)
+=== RUN TestOperatorsIntegration/Less_than
+ operators_integration_test.go:329: CEL Expression: int_val < 15
+ operators_integration_test.go:330: Generated SQL WHERE clause: int_val < 15
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE int_val < 15
+ operators_integration_test.go:345: ✓ Operator validation passed: Less than comparison (expected 2 rows, got 2 rows)
+=== RUN TestOperatorsIntegration/Less_than_or_equal
+ operators_integration_test.go:329: CEL Expression: int_val <= 15
+ operators_integration_test.go:330: Generated SQL WHERE clause: int_val <= 15
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE int_val <= 15
+ operators_integration_test.go:345: ✓ Operator validation passed: Less than or equal comparison (expected 3 rows, got 3 rows)
+=== RUN TestOperatorsIntegration/Greater_than
+ operators_integration_test.go:329: CEL Expression: int_val > 15
+ operators_integration_test.go:330: Generated SQL WHERE clause: int_val > 15
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE int_val > 15
+ operators_integration_test.go:345: ✓ Operator validation passed: Greater than comparison (expected 2 rows, got 2 rows)
+=== RUN TestOperatorsIntegration/Greater_than_or_equal
+ operators_integration_test.go:329: CEL Expression: int_val >= 15
+ operators_integration_test.go:330: Generated SQL WHERE clause: int_val >= 15
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE int_val >= 15
+ operators_integration_test.go:345: ✓ Operator validation passed: Greater than or equal comparison (expected 3 rows, got 3 rows)
+=== RUN TestOperatorsIntegration/Logical_AND
+ operators_integration_test.go:329: CEL Expression: int_val > 10 && bool_val == true
+ operators_integration_test.go:330: Generated SQL WHERE clause: int_val > 10 AND bool_val IS TRUE
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE int_val > 10 AND bool_val IS TRUE
+ operators_integration_test.go:345: ✓ Operator validation passed: Logical AND operator (expected 2 rows, got 2 rows)
+=== RUN TestOperatorsIntegration/Logical_OR
+ operators_integration_test.go:329: CEL Expression: int_val < 10 || bool_val == false
+ operators_integration_test.go:330: Generated SQL WHERE clause: int_val < 10 OR bool_val IS FALSE
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE int_val < 10 OR bool_val IS FALSE
+ operators_integration_test.go:345: ✓ Operator validation passed: Logical OR operator (expected 2 rows, got 2 rows)
+=== RUN TestOperatorsIntegration/Logical_NOT
+ operators_integration_test.go:329: CEL Expression: !bool_val
+ operators_integration_test.go:330: Generated SQL WHERE clause: NOT bool_val
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE NOT bool_val
+ operators_integration_test.go:345: ✓ Operator validation passed: Logical NOT operator (expected 2 rows, got 2 rows)
+=== RUN TestOperatorsIntegration/Complex_logical_expression
+ operators_integration_test.go:329: CEL Expression: (int_val > 10 && bool_val) || int_val < 10
+ operators_integration_test.go:330: Generated SQL WHERE clause: int_val > 10 AND bool_val OR int_val < 10
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE int_val > 10 AND bool_val OR int_val < 10
+ operators_integration_test.go:345: ✓ Operator validation passed: Complex nested logical operators (expected 3 rows, got 3 rows)
+=== RUN TestOperatorsIntegration/Addition
+ operators_integration_test.go:329: CEL Expression: int_val + 10 == 20
+ operators_integration_test.go:330: Generated SQL WHERE clause: int_val + 10 = 20
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE int_val + 10 = 20
+ operators_integration_test.go:345: ✓ Operator validation passed: Addition operator (expected 1 rows, got 1 rows)
+=== RUN TestOperatorsIntegration/Subtraction
+ operators_integration_test.go:329: CEL Expression: int_val - 5 == 15
+ operators_integration_test.go:330: Generated SQL WHERE clause: int_val - 5 = 15
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE int_val - 5 = 15
+ operators_integration_test.go:345: ✓ Operator validation passed: Subtraction operator (expected 1 rows, got 1 rows)
+=== RUN TestOperatorsIntegration/Multiplication
+ operators_integration_test.go:329: CEL Expression: int_val * 2 == 20
+ operators_integration_test.go:330: Generated SQL WHERE clause: int_val * 2 = 20
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE int_val * 2 = 20
+ operators_integration_test.go:345: ✓ Operator validation passed: Multiplication operator (expected 1 rows, got 1 rows)
+=== RUN TestOperatorsIntegration/Division
+ operators_integration_test.go:329: CEL Expression: int_val / 2 == 10
+ operators_integration_test.go:330: Generated SQL WHERE clause: int_val / 2 = 10
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE int_val / 2 = 10
+ operators_integration_test.go:345: ✓ Operator validation passed: Division operator (expected 1 rows, got 1 rows)
+=== RUN TestOperatorsIntegration/Modulo
+ operators_integration_test.go:329: CEL Expression: int_val % 10 == 0
+ operators_integration_test.go:330: Generated SQL WHERE clause: MOD(int_val, 10) = 0
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE MOD(int_val, 10) = 0
+ operators_integration_test.go:345: ✓ Operator validation passed: Modulo operator (expected 3 rows, got 3 rows)
+=== RUN TestOperatorsIntegration/Complex_arithmetic
+ operators_integration_test.go:329: CEL Expression: (int_val * 2) + 5 > 30
+ operators_integration_test.go:330: Generated SQL WHERE clause: int_val * 2 + 5 > 30
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE int_val * 2 + 5 > 30
+ operators_integration_test.go:345: ✓ Operator validation passed: Complex arithmetic expression (expected 3 rows, got 3 rows)
+=== RUN TestOperatorsIntegration/String_concatenation
+ operators_integration_test.go:329: CEL Expression: text_val + "!" == "hello!"
+ operators_integration_test.go:330: Generated SQL WHERE clause: text_val || '!' = 'hello!'
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE text_val || '!' = 'hello!'
+ operators_integration_test.go:345: ✓ Operator validation passed: String concatenation operator (expected 1 rows, got 1 rows)
+=== RUN TestOperatorsIntegration/String_contains
+ operators_integration_test.go:329: CEL Expression: text_val.contains("world")
+ operators_integration_test.go:330: Generated SQL WHERE clause: POSITION('world' IN text_val) > 0
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE POSITION('world' IN text_val) > 0
+ operators_integration_test.go:345: ✓ Operator validation passed: String contains function (expected 2 rows, got 2 rows)
+=== RUN TestOperatorsIntegration/String_startsWith
+ operators_integration_test.go:329: CEL Expression: text_val.startsWith("hello")
+ operators_integration_test.go:330: Generated SQL WHERE clause: text_val LIKE 'hello%' ESCAPE E'\\'
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE text_val LIKE 'hello%' ESCAPE E'\\'
+ operators_integration_test.go:345: ✓ Operator validation passed: String startsWith function (expected 2 rows, got 2 rows)
+=== RUN TestOperatorsIntegration/String_endsWith
+ operators_integration_test.go:329: CEL Expression: text_val.endsWith("world")
+ operators_integration_test.go:330: Generated SQL WHERE clause: text_val LIKE '%world' ESCAPE E'\\'
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE text_val LIKE '%world' ESCAPE E'\\'
+ operators_integration_test.go:345: ✓ Operator validation passed: String endsWith function (expected 2 rows, got 2 rows)
+=== RUN TestOperatorsIntegration/String_matches_regex
+ operators_integration_test.go:329: CEL Expression: text_val.matches(r"^hello")
+ operators_integration_test.go:330: Generated SQL WHERE clause: text_val ~ '^hello'
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE text_val ~ '^hello'
+ operators_integration_test.go:345: ✓ Operator validation passed: String regex matching (expected 2 rows, got 2 rows)
+=== RUN TestOperatorsIntegration/Array_membership_-_in
+ operators_integration_test.go:329: CEL Expression: "a" in array_val
+ operators_integration_test.go:330: Generated SQL WHERE clause: 'a' = ANY(array_val)
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE 'a' = ANY(array_val)
+ operators_integration_test.go:345: ✓ Operator validation passed: Array membership with 'in' operator (expected 2 rows, got 2 rows)
+=== RUN TestOperatorsIntegration/Array_membership_-_multiple_values
+ operators_integration_test.go:329: CEL Expression: "b" in array_val || "x" in array_val
+ operators_integration_test.go:330: Generated SQL WHERE clause: 'b' = ANY(array_val) OR 'x' = ANY(array_val)
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE 'b' = ANY(array_val) OR 'x' = ANY(array_val)
+ operators_integration_test.go:345: ✓ Operator validation passed: Array membership with OR (expected 3 rows, got 3 rows)
+=== RUN TestOperatorsIntegration/Timestamp_equality
+ operators_integration_test.go:329: CEL Expression: timestamp_val == timestamp("2024-01-01T10:00:00Z")
+ operators_integration_test.go:330: Generated SQL WHERE clause: timestamp_val = CAST('2024-01-01T10:00:00Z' AS TIMESTAMP WITH TIME ZONE)
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE timestamp_val = CAST('2024-01-01T10:00:00Z' AS TIMESTAMP WITH TIME ZONE)
+ operators_integration_test.go:345: ✓ Operator validation passed: Timestamp equality comparison (expected 1 rows, got 1 rows)
+=== RUN TestOperatorsIntegration/Timestamp_greater_than
+ operators_integration_test.go:329: CEL Expression: timestamp_val > timestamp("2024-01-02T00:00:00Z")
+ operators_integration_test.go:330: Generated SQL WHERE clause: timestamp_val > CAST('2024-01-02T00:00:00Z' AS TIMESTAMP WITH TIME ZONE)
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE timestamp_val > CAST('2024-01-02T00:00:00Z' AS TIMESTAMP WITH TIME ZONE)
+ operators_integration_test.go:345: ✓ Operator validation passed: Timestamp greater than comparison (expected 4 rows, got 4 rows)
+=== RUN TestOperatorsIntegration/Timestamp_less_than
+ operators_integration_test.go:329: CEL Expression: timestamp_val < timestamp("2024-01-03T00:00:00Z")
+ operators_integration_test.go:330: Generated SQL WHERE clause: timestamp_val < CAST('2024-01-03T00:00:00Z' AS TIMESTAMP WITH TIME ZONE)
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE timestamp_val < CAST('2024-01-03T00:00:00Z' AS TIMESTAMP WITH TIME ZONE)
+ operators_integration_test.go:345: ✓ Operator validation passed: Timestamp less than comparison (expected 2 rows, got 2 rows)
+=== RUN TestOperatorsIntegration/Complex_multi-operator_expression
+ operators_integration_test.go:329: CEL Expression: int_val > 10 && bool_val && "b" in array_val
+ operators_integration_test.go:330: Generated SQL WHERE clause: int_val > 10 AND bool_val AND 'b' = ANY(array_val)
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE int_val > 10 AND bool_val AND 'b' = ANY(array_val)
+ operators_integration_test.go:345: ✓ Operator validation passed: Complex expression with multiple operator types (expected 1 rows, got 1 rows)
+=== RUN TestOperatorsIntegration/Nested_parenthesized_operators
+ operators_integration_test.go:329: CEL Expression: ((int_val + 5) * 2 > 30) && (text_val.contains("test") || bool_val)
+ operators_integration_test.go:330: Generated SQL WHERE clause: (int_val + 5) * 2 > 30 AND (POSITION('test' IN text_val) > 0 OR bool_val)
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE (int_val + 5) * 2 > 30 AND (POSITION('test' IN text_val) > 0 OR bool_val)
+ operators_integration_test.go:345: ✓ Operator validation passed: Deeply nested operators with parentheses (expected 2 rows, got 2 rows)
+=== RUN TestOperatorsIntegration/Triple_negation
+ operators_integration_test.go:329: CEL Expression: !!!bool_val
+ operators_integration_test.go:330: Generated SQL WHERE clause: NOT bool_val
+ operators_integration_test.go:335: Full SQL Query: SELECT COUNT(*) FROM test_data WHERE NOT bool_val
+ operators_integration_test.go:345: ✓ Operator validation passed: Multiple NOT operators (expected 2 rows, got 2 rows)
+2025/10/31 08:26:23 🐳 Stopping container: dd7d641b2f97
+2025/10/31 08:26:23 ✅ Container stopped: dd7d641b2f97
+2025/10/31 08:26:23 🐳 Terminating container: dd7d641b2f97
+2025/10/31 08:26:24 🚫 Container terminated: dd7d641b2f97
+--- PASS: TestOperatorsIntegration (1.09s)
+ --- PASS: TestOperatorsIntegration/Equality_string (0.00s)
+ --- PASS: TestOperatorsIntegration/Equality_integer (0.00s)
+ --- PASS: TestOperatorsIntegration/Equality_float (0.00s)
+ --- PASS: TestOperatorsIntegration/Equality_boolean (0.00s)
+ --- PASS: TestOperatorsIntegration/Not_equal (0.00s)
+ --- PASS: TestOperatorsIntegration/Less_than (0.00s)
+ --- PASS: TestOperatorsIntegration/Less_than_or_equal (0.00s)
+ --- PASS: TestOperatorsIntegration/Greater_than (0.00s)
+ --- PASS: TestOperatorsIntegration/Greater_than_or_equal (0.00s)
+ --- PASS: TestOperatorsIntegration/Logical_AND (0.00s)
+ --- PASS: TestOperatorsIntegration/Logical_OR (0.00s)
+ --- PASS: TestOperatorsIntegration/Logical_NOT (0.00s)
+ --- PASS: TestOperatorsIntegration/Complex_logical_expression (0.00s)
+ --- PASS: TestOperatorsIntegration/Addition (0.00s)
+ --- PASS: TestOperatorsIntegration/Subtraction (0.00s)
+ --- PASS: TestOperatorsIntegration/Multiplication (0.00s)
+ --- PASS: TestOperatorsIntegration/Division (0.00s)
+ --- PASS: TestOperatorsIntegration/Modulo (0.00s)
+ --- PASS: TestOperatorsIntegration/Complex_arithmetic (0.00s)
+ --- PASS: TestOperatorsIntegration/String_concatenation (0.00s)
+ --- PASS: TestOperatorsIntegration/String_contains (0.00s)
+ --- PASS: TestOperatorsIntegration/String_startsWith (0.00s)
+ --- PASS: TestOperatorsIntegration/String_endsWith (0.00s)
+ --- PASS: TestOperatorsIntegration/String_matches_regex (0.00s)
+ --- PASS: TestOperatorsIntegration/Array_membership_-_in (0.00s)
+ --- PASS: TestOperatorsIntegration/Array_membership_-_multiple_values (0.00s)
+ --- PASS: TestOperatorsIntegration/Timestamp_equality (0.00s)
+ --- PASS: TestOperatorsIntegration/Timestamp_greater_than (0.00s)
+ --- PASS: TestOperatorsIntegration/Timestamp_less_than (0.00s)
+ --- PASS: TestOperatorsIntegration/Complex_multi-operator_expression (0.00s)
+ --- PASS: TestOperatorsIntegration/Nested_parenthesized_operators (0.00s)
+ --- PASS: TestOperatorsIntegration/Triple_negation (0.00s)
+=== RUN TestOperatorEdgeCases
+2025/10/31 08:26:24 🐳 Creating container for image postgres:17-alpine
+2025/10/31 08:26:24 ✅ Container created: 0b5198e132d0
+2025/10/31 08:26:24 🐳 Starting container: 0b5198e132d0
+2025/10/31 08:26:24 ✅ Container started: 0b5198e132d0
+2025/10/31 08:26:24 ⏳ Waiting for container id 0b5198e132d0 image: postgres:17-alpine. Waiting for: &{timeout: Log:database system is ready to accept connections IsRegexp:false Occurrence:2 PollInterval:100ms check: submatchCallback: re: log:[]}
+2025/10/31 08:26:24 🔔 Container is ready: 0b5198e132d0
+=== RUN TestOperatorEdgeCases/Empty_string_equality
+ operators_integration_test.go:495: CEL Expression: empty_string == ""
+ operators_integration_test.go:496: Generated SQL WHERE clause: empty_string = ''
+ operators_integration_test.go:509: ✓ Edge case validation passed: Empty string should be handled correctly
+=== RUN TestOperatorEdgeCases/Zero_integer_equality
+ operators_integration_test.go:495: CEL Expression: zero_int == 0
+ operators_integration_test.go:496: Generated SQL WHERE clause: zero_int = 0
+ operators_integration_test.go:509: ✓ Edge case validation passed: Zero should be handled correctly
+=== RUN TestOperatorEdgeCases/Negative_integer_comparison
+ operators_integration_test.go:495: CEL Expression: negative_int < 0
+ operators_integration_test.go:496: Generated SQL WHERE clause: negative_int < 0
+ operators_integration_test.go:509: ✓ Edge case validation passed: Negative numbers should work correctly
+=== RUN TestOperatorEdgeCases/Large_integer_comparison
+ operators_integration_test.go:495: CEL Expression: large_int > 1000000
+ operators_integration_test.go:496: Generated SQL WHERE clause: large_int > 1000000
+ operators_integration_test.go:509: ✓ Edge case validation passed: Large integers should be handled correctly
+=== RUN TestOperatorEdgeCases/Zero_float_equality
+ operators_integration_test.go:495: CEL Expression: zero_float == 0.0
+ operators_integration_test.go:496: Generated SQL WHERE clause: zero_float = 0
+ operators_integration_test.go:509: ✓ Edge case validation passed: Zero float should be handled correctly
+=== RUN TestOperatorEdgeCases/Negative_float_comparison
+ operators_integration_test.go:495: CEL Expression: negative_float < 0.0
+ operators_integration_test.go:496: Generated SQL WHERE clause: negative_float < 0
+ operators_integration_test.go:509: ✓ Edge case validation passed: Negative floats should work correctly
+=== RUN TestOperatorEdgeCases/Division_by_non-zero
+ operators_integration_test.go:495: CEL Expression: zero_int + 10 == 10
+ operators_integration_test.go:496: Generated SQL WHERE clause: zero_int + 10 = 10
+ operators_integration_test.go:509: ✓ Edge case validation passed: Arithmetic with zero should work
+2025/10/31 08:26:24 🐳 Stopping container: 0b5198e132d0
+2025/10/31 08:26:25 ✅ Container stopped: 0b5198e132d0
+2025/10/31 08:26:25 🐳 Terminating container: 0b5198e132d0
+2025/10/31 08:26:25 🚫 Container terminated: 0b5198e132d0
+--- PASS: TestOperatorEdgeCases (1.06s)
+ --- PASS: TestOperatorEdgeCases/Empty_string_equality (0.00s)
+ --- PASS: TestOperatorEdgeCases/Zero_integer_equality (0.00s)
+ --- PASS: TestOperatorEdgeCases/Negative_integer_comparison (0.00s)
+ --- PASS: TestOperatorEdgeCases/Large_integer_comparison (0.00s)
+ --- PASS: TestOperatorEdgeCases/Zero_float_equality (0.00s)
+ --- PASS: TestOperatorEdgeCases/Negative_float_comparison (0.00s)
+ --- PASS: TestOperatorEdgeCases/Division_by_non-zero (0.00s)
+=== RUN TestParameterizedQueriesIntegration
+2025/10/31 08:26:25 🐳 Creating container for image postgres:17-alpine
+2025/10/31 08:26:25 ✅ Container created: 6826db5d35ad
+2025/10/31 08:26:25 🐳 Starting container: 6826db5d35ad
+2025/10/31 08:26:25 ✅ Container started: 6826db5d35ad
+2025/10/31 08:26:25 ⏳ Waiting for container id 6826db5d35ad image: postgres:17-alpine. Waiting for: &{timeout: Log:database system is ready to accept connections IsRegexp:false Occurrence:2 PollInterval:100ms check: submatchCallback: re: log:[]}
+2025/10/31 08:26:25 🔔 Container is ready: 6826db5d35ad
+=== RUN TestParameterizedQueriesIntegration/simple_string_equality
+ parameterized_integration_test.go:198: Testing: Find user by exact name match
+ parameterized_integration_test.go:208: CEL: usr.name == "John"
+ parameterized_integration_test.go:209: SQL: usr.name = $1
+ parameterized_integration_test.go:210: Parameters: [John]
+=== RUN TestParameterizedQueriesIntegration/integer_comparison
+ parameterized_integration_test.go:198: Testing: Find users older than 25
+ parameterized_integration_test.go:208: CEL: usr.age > 25
+ parameterized_integration_test.go:209: SQL: usr.age > $1
+ parameterized_integration_test.go:210: Parameters: [25]
+=== RUN TestParameterizedQueriesIntegration/double_comparison
+ parameterized_integration_test.go:198: Testing: Find users with high salary
+ parameterized_integration_test.go:208: CEL: usr.salary >= 75000.0
+ parameterized_integration_test.go:209: SQL: usr.salary >= $1
+ parameterized_integration_test.go:210: Parameters: [75000]
+=== RUN TestParameterizedQueriesIntegration/boolean_constant_(inline)
+ parameterized_integration_test.go:198: Testing: Find active users
+ parameterized_integration_test.go:208: CEL: usr.active == true
+ parameterized_integration_test.go:209: SQL: usr.active IS TRUE
+ parameterized_integration_test.go:210: Parameters: []
+=== RUN TestParameterizedQueriesIntegration/complex_AND_expression
+ parameterized_integration_test.go:198: Testing: Find senior active users with good salary
+ parameterized_integration_test.go:208: CEL: usr.age >= 25 && usr.salary > 50000.0 && usr.active == true
+ parameterized_integration_test.go:209: SQL: usr.age >= $1 AND usr.salary > $2 AND usr.active IS TRUE
+ parameterized_integration_test.go:210: Parameters: [25 50000]
+=== RUN TestParameterizedQueriesIntegration/complex_OR_expression
+ parameterized_integration_test.go:198: Testing: Find specific users by name
+ parameterized_integration_test.go:208: CEL: usr.name == "John" || usr.name == "Alice"
+ parameterized_integration_test.go:209: SQL: usr.name = $1 OR usr.name = $2
+ parameterized_integration_test.go:210: Parameters: [John Alice]
+=== RUN TestParameterizedQueriesIntegration/JSON_field_comparison
+ parameterized_integration_test.go:198: Testing: Find users by JSON field value
+ parameterized_integration_test.go:208: CEL: usr.metadata.role == "developer"
+ parameterized_integration_test.go:209: SQL: usr.metadata->>'role' = $1
+ parameterized_integration_test.go:210: Parameters: [developer]
+=== RUN TestParameterizedQueriesIntegration/nested_JSON_field
+ parameterized_integration_test.go:198: Testing: Find users by nested JSON field
+ parameterized_integration_test.go:208: CEL: usr.metadata.level == "senior"
+ parameterized_integration_test.go:209: SQL: usr.metadata->>'level' = $1
+ parameterized_integration_test.go:210: Parameters: [senior]
+=== RUN TestParameterizedQueriesIntegration/mixed_regular_and_JSON_fields
+ parameterized_integration_test.go:198: Testing: Combine regular and JSON field filters
+ parameterized_integration_test.go:208: CEL: usr.age > 30 && usr.metadata.role == "architect"
+ parameterized_integration_test.go:209: SQL: usr.age > $1 AND usr.metadata->>'role' = $2
+ parameterized_integration_test.go:210: Parameters: [30 architect]
+2025/10/31 08:26:25 🐳 Stopping container: 6826db5d35ad
+2025/10/31 08:26:26 ✅ Container stopped: 6826db5d35ad
+2025/10/31 08:26:26 🐳 Terminating container: 6826db5d35ad
+2025/10/31 08:26:26 🚫 Container terminated: 6826db5d35ad
+--- PASS: TestParameterizedQueriesIntegration (1.05s)
+ --- PASS: TestParameterizedQueriesIntegration/simple_string_equality (0.00s)
+ --- PASS: TestParameterizedQueriesIntegration/integer_comparison (0.00s)
+ --- PASS: TestParameterizedQueriesIntegration/double_comparison (0.00s)
+ --- PASS: TestParameterizedQueriesIntegration/boolean_constant_(inline) (0.00s)
+ --- PASS: TestParameterizedQueriesIntegration/complex_AND_expression (0.00s)
+ --- PASS: TestParameterizedQueriesIntegration/complex_OR_expression (0.00s)
+ --- PASS: TestParameterizedQueriesIntegration/JSON_field_comparison (0.00s)
+ --- PASS: TestParameterizedQueriesIntegration/nested_JSON_field (0.00s)
+ --- PASS: TestParameterizedQueriesIntegration/mixed_regular_and_JSON_fields (0.00s)
+=== RUN TestParameterizedQueryPlanCaching
+2025/10/31 08:26:26 🐳 Creating container for image postgres:17-alpine
+2025/10/31 08:26:26 ✅ Container created: 277d79f0f09b
+2025/10/31 08:26:26 🐳 Starting container: 277d79f0f09b
+2025/10/31 08:26:26 ✅ Container started: 277d79f0f09b
+2025/10/31 08:26:26 ⏳ Waiting for container id 277d79f0f09b image: postgres:17-alpine. Waiting for: &{timeout: Log:database system is ready to accept connections IsRegexp:false Occurrence:2 PollInterval:100ms check: submatchCallback: re: log:[]}
+2025/10/31 08:26:26 🔔 Container is ready: 277d79f0f09b
+ parameterized_integration_test.go:312: Query: SELECT id FROM products product WHERE product.price > $1 ORDER BY id
+ parameterized_integration_test.go:313: Parameters: [20]
+ parameterized_integration_test.go:351: Successfully demonstrated query plan caching with parameterized queries
+2025/10/31 08:26:26 🐳 Stopping container: 277d79f0f09b
+2025/10/31 08:26:27 ✅ Container stopped: 277d79f0f09b
+2025/10/31 08:26:27 🐳 Terminating container: 277d79f0f09b
+2025/10/31 08:26:27 🚫 Container terminated: 277d79f0f09b
+--- PASS: TestParameterizedQueryPlanCaching (1.02s)
+=== RUN TestParameterizedPreparedStatements
+2025/10/31 08:26:27 🐳 Creating container for image postgres:17-alpine
+2025/10/31 08:26:27 ✅ Container created: 4c0584098cd0
+2025/10/31 08:26:27 🐳 Starting container: 4c0584098cd0
+2025/10/31 08:26:27 ✅ Container started: 4c0584098cd0
+2025/10/31 08:26:27 ⏳ Waiting for container id 4c0584098cd0 image: postgres:17-alpine. Waiting for: &{timeout: Log:database system is ready to accept connections IsRegexp:false Occurrence:2 PollInterval:100ms check: submatchCallback: re: log:[]}
+2025/10/31 08:26:27 🔔 Container is ready: 4c0584098cd0
+ parameterized_integration_test.go:421: SQL: emp.department = $1 AND emp.salary > $2
+ parameterized_integration_test.go:422: Parameters: [Engineering 75000]
+ parameterized_integration_test.go:467: Successfully used prepared statements with parameterized queries
+2025/10/31 08:26:27 🐳 Stopping container: 4c0584098cd0
+2025/10/31 08:26:28 ✅ Container stopped: 4c0584098cd0
+2025/10/31 08:26:28 🐳 Terminating container: 4c0584098cd0
+2025/10/31 08:26:28 🚫 Container terminated: 4c0584098cd0
+--- PASS: TestParameterizedPreparedStatements (1.04s)
+=== RUN TestParameterizedSQLInjectionPrevention
+2025/10/31 08:26:28 🐳 Creating container for image postgres:17-alpine
+2025/10/31 08:26:28 ✅ Container created: 7b14e039cee6
+2025/10/31 08:26:28 🐳 Starting container: 7b14e039cee6
+2025/10/31 08:26:28 ✅ Container started: 7b14e039cee6
+2025/10/31 08:26:28 ⏳ Waiting for container id 7b14e039cee6 image: postgres:17-alpine. Waiting for: &{timeout: Log:database system is ready to accept connections IsRegexp:false Occurrence:2 PollInterval:100ms check: submatchCallback: re: log:[]}
+2025/10/31 08:26:29 🔔 Container is ready: 7b14e039cee6
+ parameterized_integration_test.go:541: CEL: account.username == "alice' OR '1'='1"
+ parameterized_integration_test.go:542: SQL: account.username = $1
+ parameterized_integration_test.go:543: Parameters: [alice' OR '1'='1]
+ parameterized_integration_test.go:568: Successfully prevented SQL injection using parameterized queries
+2025/10/31 08:26:29 🐳 Stopping container: 7b14e039cee6
+2025/10/31 08:26:29 ✅ Container stopped: 7b14e039cee6
+2025/10/31 08:26:29 🐳 Terminating container: 7b14e039cee6
+2025/10/31 08:26:29 🚫 Container terminated: 7b14e039cee6
+--- PASS: TestParameterizedSQLInjectionPrevention (1.09s)
+=== RUN TestParameterizedDataTypeCompatibility
+2025/10/31 08:26:29 🐳 Creating container for image postgres:17-alpine
+2025/10/31 08:26:29 ✅ Container created: a66106e6f33f
+2025/10/31 08:26:29 🐳 Starting container: a66106e6f33f
+2025/10/31 08:26:29 ✅ Container started: a66106e6f33f
+2025/10/31 08:26:29 ⏳ Waiting for container id a66106e6f33f image: postgres:17-alpine. Waiting for: &{timeout: Log:database system is ready to accept connections IsRegexp:false Occurrence:2 PollInterval:100ms check: submatchCallback: re: log:[]}
+2025/10/31 08:26:30 🔔 Container is ready: a66106e6f33f
+=== RUN TestParameterizedDataTypeCompatibility/text_parameter
+ parameterized_integration_test.go:674: SQL: row.text_col = $1
+ parameterized_integration_test.go:675: Parameters: [test]
+=== RUN TestParameterizedDataTypeCompatibility/int_parameter
+ parameterized_integration_test.go:674: SQL: row.int_col = $1
+ parameterized_integration_test.go:675: Parameters: [42]
+=== RUN TestParameterizedDataTypeCompatibility/double_parameter
+ parameterized_integration_test.go:674: SQL: row.double_col > $1
+ parameterized_integration_test.go:675: Parameters: [3]
+=== RUN TestParameterizedDataTypeCompatibility/bool_parameter_(inline)
+ parameterized_integration_test.go:674: SQL: row.bool_col IS TRUE
+ parameterized_integration_test.go:675: Parameters: []
+=== RUN TestParameterizedDataTypeCompatibility/bytes_parameter
+ parameterized_integration_test.go:674: SQL: row.bytes_col = $1
+ parameterized_integration_test.go:675: Parameters: [[222 173 190 239]]
+2025/10/31 08:26:30 🐳 Stopping container: a66106e6f33f
+2025/10/31 08:26:30 ✅ Container stopped: a66106e6f33f
+2025/10/31 08:26:30 🐳 Terminating container: a66106e6f33f
+2025/10/31 08:26:30 🚫 Container terminated: a66106e6f33f
+--- PASS: TestParameterizedDataTypeCompatibility (1.01s)
+ --- PASS: TestParameterizedDataTypeCompatibility/text_parameter (0.00s)
+ --- PASS: TestParameterizedDataTypeCompatibility/int_parameter (0.00s)
+ --- PASS: TestParameterizedDataTypeCompatibility/double_parameter (0.00s)
+ --- PASS: TestParameterizedDataTypeCompatibility/bool_parameter_(inline) (0.00s)
+ --- PASS: TestParameterizedDataTypeCompatibility/bytes_parameter (0.00s)
+=== RUN TestParameterizedComplexExpressions
+2025/10/31 08:26:30 🐳 Creating container for image postgres:17-alpine
+2025/10/31 08:26:30 ✅ Container created: 83120c749b76
+2025/10/31 08:26:30 🐳 Starting container: 83120c749b76
+2025/10/31 08:26:30 ✅ Container started: 83120c749b76
+2025/10/31 08:26:30 ⏳ Waiting for container id 83120c749b76 image: postgres:17-alpine. Waiting for: &{timeout: Log:database system is ready to accept connections IsRegexp:false Occurrence:2 PollInterval:100ms check: submatchCallback: re: log:[]}
+2025/10/31 08:26:31 🔔 Container is ready: 83120c749b76
+=== RUN TestParameterizedComplexExpressions/ternary_with_parameters
+ parameterized_integration_test.go:916: Testing: Conditional logic with parameterized comparisons
+ parameterized_integration_test.go:926: CEL: row.age > 25 ? row.score > 90.0 : row.score > 80.0
+ parameterized_integration_test.go:927: SQL: CASE WHEN row.age > $1 THEN row.score > $2 ELSE row.score > $3 END
+ parameterized_integration_test.go:928: Parameters: [25 90 80]
+=== RUN TestParameterizedComplexExpressions/IN_with_parameterized_list
+ parameterized_integration_test.go:916: Testing: IN operator with parameterized array
+ parameterized_integration_test.go:926: CEL: row.name in ["Alice", "Bob"]
+ parameterized_integration_test.go:927: SQL: row.name = ANY(ARRAY[$1, $2])
+ parameterized_integration_test.go:928: Parameters: [Alice Bob]
+=== RUN TestParameterizedComplexExpressions/string_contains_with_parameter
+ parameterized_integration_test.go:916: Testing: String contains with parameterized substring
+ parameterized_integration_test.go:926: CEL: row.name.contains("ob")
+ parameterized_integration_test.go:927: SQL: POSITION($1 IN row.name) > 0
+ parameterized_integration_test.go:928: Parameters: [ob]
+2025/10/31 08:26:31 🐳 Stopping container: 83120c749b76
+2025/10/31 08:26:31 ✅ Container stopped: 83120c749b76
+2025/10/31 08:26:31 🐳 Terminating container: 83120c749b76
+2025/10/31 08:26:31 🚫 Container terminated: 83120c749b76
+--- PASS: TestParameterizedComplexExpressions (1.04s)
+ --- PASS: TestParameterizedComplexExpressions/ternary_with_parameters (0.00s)
+ --- PASS: TestParameterizedComplexExpressions/IN_with_parameterized_list (0.00s)
+ --- PASS: TestParameterizedComplexExpressions/string_contains_with_parameter (0.00s)
+=== RUN TestParameterizedQueryPerformance
+2025/10/31 08:26:31 🐳 Creating container for image postgres:17-alpine
+2025/10/31 08:26:31 ✅ Container created: 45dd125333d8
+2025/10/31 08:26:31 🐳 Starting container: 45dd125333d8
+2025/10/31 08:26:31 ✅ Container started: 45dd125333d8
+2025/10/31 08:26:31 ⏳ Waiting for container id 45dd125333d8 image: postgres:17-alpine. Waiting for: &{timeout: Log:database system is ready to accept connections IsRegexp:false Occurrence:2 PollInterval:100ms check: submatchCallback: re: log:[]}
+2025/10/31 08:26:32 🔔 Container is ready: 45dd125333d8
+ parameterized_integration_test.go:1036: Average query time: 483.018µs over 100 iterations
+ parameterized_integration_test.go:1037: Total rows: 10000, matching rows: 100
+2025/10/31 08:26:36 🐳 Stopping container: 45dd125333d8
+2025/10/31 08:26:36 ✅ Container stopped: 45dd125333d8
+2025/10/31 08:26:36 🐳 Terminating container: 45dd125333d8
+2025/10/31 08:26:36 🚫 Container terminated: 45dd125333d8
+--- PASS: TestParameterizedQueryPerformance (4.92s)
+=== RUN TestConvertParameterized
+=== RUN TestConvertParameterized/simple_string_equality
+=== RUN TestConvertParameterized/multiple_string_parameters
+=== RUN TestConvertParameterized/string_with_escaped_quotes
+=== RUN TestConvertParameterized/simple_integer_equality
+=== RUN TestConvertParameterized/integer_comparison
+=== RUN TestConvertParameterized/negative_integer
+=== RUN TestConvertParameterized/simple_double_equality
+=== RUN TestConvertParameterized/double_comparison
+=== RUN TestConvertParameterized/boolean_TRUE_constant
+=== RUN TestConvertParameterized/boolean_FALSE_constant
+=== RUN TestConvertParameterized/mixed_bool_constants_and_params
+=== RUN TestConvertParameterized/bytes_equality
+=== RUN TestConvertParameterized/complex_AND_expression
+=== RUN TestConvertParameterized/complex_OR_expression
+=== RUN TestConvertParameterized/nested_parentheses_with_params
+=== RUN TestConvertParameterized/parameter_ordering_matches_placeholders
+=== RUN TestConvertParameterized/no_parameters_-_only_boolean_constants
+=== RUN TestConvertParameterized/startsWith_with_parameter
+=== RUN TestConvertParameterized/endsWith_with_parameter
+=== RUN TestConvertParameterized/contains_with_parameter
+=== RUN TestConvertParameterized/IN_with_array_literal
+=== RUN TestConvertParameterized/string_IN_with_array_literal
+=== RUN TestConvertParameterized/ternary_with_parameters
+=== RUN TestConvertParameterized/cast_int_to_string
+--- PASS: TestConvertParameterized (0.01s)
+ --- PASS: TestConvertParameterized/simple_string_equality (0.00s)
+ --- PASS: TestConvertParameterized/multiple_string_parameters (0.00s)
+ --- PASS: TestConvertParameterized/string_with_escaped_quotes (0.00s)
+ --- PASS: TestConvertParameterized/simple_integer_equality (0.00s)
+ --- PASS: TestConvertParameterized/integer_comparison (0.00s)
+ --- PASS: TestConvertParameterized/negative_integer (0.00s)
+ --- PASS: TestConvertParameterized/simple_double_equality (0.00s)
+ --- PASS: TestConvertParameterized/double_comparison (0.00s)
+ --- PASS: TestConvertParameterized/boolean_TRUE_constant (0.00s)
+ --- PASS: TestConvertParameterized/boolean_FALSE_constant (0.00s)
+ --- PASS: TestConvertParameterized/mixed_bool_constants_and_params (0.00s)
+ --- PASS: TestConvertParameterized/bytes_equality (0.00s)
+ --- PASS: TestConvertParameterized/complex_AND_expression (0.00s)
+ --- PASS: TestConvertParameterized/complex_OR_expression (0.00s)
+ --- PASS: TestConvertParameterized/nested_parentheses_with_params (0.00s)
+ --- PASS: TestConvertParameterized/parameter_ordering_matches_placeholders (0.00s)
+ --- PASS: TestConvertParameterized/no_parameters_-_only_boolean_constants (0.00s)
+ --- PASS: TestConvertParameterized/startsWith_with_parameter (0.00s)
+ --- PASS: TestConvertParameterized/endsWith_with_parameter (0.00s)
+ --- PASS: TestConvertParameterized/contains_with_parameter (0.00s)
+ --- PASS: TestConvertParameterized/IN_with_array_literal (0.00s)
+ --- PASS: TestConvertParameterized/string_IN_with_array_literal (0.00s)
+ --- PASS: TestConvertParameterized/ternary_with_parameters (0.00s)
+ --- PASS: TestConvertParameterized/cast_int_to_string (0.00s)
+=== RUN TestConvertParameterized_JSONFields
+=== RUN TestConvertParameterized_JSONFields/JSON_field_comparison_with_parameter
+=== RUN TestConvertParameterized_JSONFields/nested_JSON_field_comparison
+=== RUN TestConvertParameterized_JSONFields/JSON_and_regular_field_with_parameters
+--- PASS: TestConvertParameterized_JSONFields (0.00s)
+ --- PASS: TestConvertParameterized_JSONFields/JSON_field_comparison_with_parameter (0.00s)
+ --- PASS: TestConvertParameterized_JSONFields/nested_JSON_field_comparison (0.00s)
+ --- PASS: TestConvertParameterized_JSONFields/JSON_and_regular_field_with_parameters (0.00s)
+=== RUN TestConvertParameterized_Comprehensions
+=== RUN TestConvertParameterized_Comprehensions/all()_with_parameterized_predicate
+=== RUN TestConvertParameterized_Comprehensions/exists()_with_parameterized_predicate
+=== RUN TestConvertParameterized_Comprehensions/exists_one()_with_parameterized_predicate
+=== RUN TestConvertParameterized_Comprehensions/map()_with_parameterized_transform
+--- PASS: TestConvertParameterized_Comprehensions (0.00s)
+ --- PASS: TestConvertParameterized_Comprehensions/all()_with_parameterized_predicate (0.00s)
+ --- PASS: TestConvertParameterized_Comprehensions/exists()_with_parameterized_predicate (0.00s)
+ --- PASS: TestConvertParameterized_Comprehensions/exists_one()_with_parameterized_predicate (0.00s)
+ --- PASS: TestConvertParameterized_Comprehensions/map()_with_parameterized_transform (0.00s)
+=== RUN TestConvertParameterized_RegexPatterns
+=== RUN TestConvertParameterized_RegexPatterns/matches_with_simple_pattern
+=== RUN TestConvertParameterized_RegexPatterns/matches_with_case-insensitive_pattern
+--- PASS: TestConvertParameterized_RegexPatterns (0.00s)
+ --- PASS: TestConvertParameterized_RegexPatterns/matches_with_simple_pattern (0.00s)
+ --- PASS: TestConvertParameterized_RegexPatterns/matches_with_case-insensitive_pattern (0.00s)
+=== RUN TestConvertParameterized_EmptyParameters
+=== RUN TestConvertParameterized_EmptyParameters/field_comparison_only
+=== RUN TestConvertParameterized_EmptyParameters/field_arithmetic
+=== RUN TestConvertParameterized_EmptyParameters/field_with_boolean_constants
+--- PASS: TestConvertParameterized_EmptyParameters (0.00s)
+ --- PASS: TestConvertParameterized_EmptyParameters/field_comparison_only (0.00s)
+ --- PASS: TestConvertParameterized_EmptyParameters/field_arithmetic (0.00s)
+ --- PASS: TestConvertParameterized_EmptyParameters/field_with_boolean_constants (0.00s)
+=== RUN TestConvertParameterized_NegativeCases
+=== RUN TestConvertParameterized_NegativeCases/valid_expression
+=== RUN TestConvertParameterized_NegativeCases/string_with_null_byte
+--- PASS: TestConvertParameterized_NegativeCases (0.00s)
+ --- PASS: TestConvertParameterized_NegativeCases/valid_expression (0.00s)
+ --- PASS: TestConvertParameterized_NegativeCases/string_with_null_byte (0.00s)
+=== RUN TestConvertParameterized_ParameterTypeConsistency
+=== RUN TestConvertParameterized_ParameterTypeConsistency/string_parameter_type
+ parameterized_test.go:600: Parameter type: string (value: John)
+=== RUN TestConvertParameterized_ParameterTypeConsistency/int64_parameter_type
+ parameterized_test.go:600: Parameter type: int64 (value: 25)
+=== RUN TestConvertParameterized_ParameterTypeConsistency/float64_parameter_type
+ parameterized_test.go:600: Parameter type: float64 (value: 50000.5)
+=== RUN TestConvertParameterized_ParameterTypeConsistency/bytes_parameter_type
+ parameterized_test.go:600: Parameter type: []uint8 (value: [104 101 108 108 111])
+--- PASS: TestConvertParameterized_ParameterTypeConsistency (0.00s)
+ --- PASS: TestConvertParameterized_ParameterTypeConsistency/string_parameter_type (0.00s)
+ --- PASS: TestConvertParameterized_ParameterTypeConsistency/int64_parameter_type (0.00s)
+ --- PASS: TestConvertParameterized_ParameterTypeConsistency/float64_parameter_type (0.00s)
+ --- PASS: TestConvertParameterized_ParameterTypeConsistency/bytes_parameter_type (0.00s)
+=== RUN TestReDoSProtection_NestedQuantifiers
+=== RUN TestReDoSProtection_NestedQuantifiers/nested_star_quantifier
+=== RUN TestReDoSProtection_NestedQuantifiers/nested_plus_quantifier
+=== RUN TestReDoSProtection_NestedQuantifiers/complex_nested_pattern
+=== RUN TestReDoSProtection_NestedQuantifiers/nested_with_brace_quantifier
+=== RUN TestReDoSProtection_NestedQuantifiers/double_star
+=== RUN TestReDoSProtection_NestedQuantifiers/double_plus
+=== RUN TestReDoSProtection_NestedQuantifiers/mixed_nested
+--- PASS: TestReDoSProtection_NestedQuantifiers (0.00s)
+ --- PASS: TestReDoSProtection_NestedQuantifiers/nested_star_quantifier (0.00s)
+ --- PASS: TestReDoSProtection_NestedQuantifiers/nested_plus_quantifier (0.00s)
+ --- PASS: TestReDoSProtection_NestedQuantifiers/complex_nested_pattern (0.00s)
+ --- PASS: TestReDoSProtection_NestedQuantifiers/nested_with_brace_quantifier (0.00s)
+ --- PASS: TestReDoSProtection_NestedQuantifiers/double_star (0.00s)
+ --- PASS: TestReDoSProtection_NestedQuantifiers/double_plus (0.00s)
+ --- PASS: TestReDoSProtection_NestedQuantifiers/mixed_nested (0.00s)
+=== RUN TestReDoSProtection_QuantifiedAlternation
+=== RUN TestReDoSProtection_QuantifiedAlternation/quantified_alternation_star
+=== RUN TestReDoSProtection_QuantifiedAlternation/quantified_alternation_plus
+=== RUN TestReDoSProtection_QuantifiedAlternation/complex_alternation
+--- PASS: TestReDoSProtection_QuantifiedAlternation (0.00s)
+ --- PASS: TestReDoSProtection_QuantifiedAlternation/quantified_alternation_star (0.00s)
+ --- PASS: TestReDoSProtection_QuantifiedAlternation/quantified_alternation_plus (0.00s)
+ --- PASS: TestReDoSProtection_QuantifiedAlternation/complex_alternation (0.00s)
+=== RUN TestReDoSProtection_PatternLength
+--- PASS: TestReDoSProtection_PatternLength (0.00s)
+=== RUN TestReDoSProtection_GroupLimit
+--- PASS: TestReDoSProtection_GroupLimit (0.00s)
+=== RUN TestReDoSProtection_NestingDepth
+--- PASS: TestReDoSProtection_NestingDepth (0.00s)
+=== RUN TestReDoSProtection_SafePatterns
+=== RUN TestReDoSProtection_SafePatterns/simple_literal
+=== RUN TestReDoSProtection_SafePatterns/character_class
+=== RUN TestReDoSProtection_SafePatterns/anchored_pattern
+=== RUN TestReDoSProtection_SafePatterns/digit_pattern
+=== RUN TestReDoSProtection_SafePatterns/word_boundary
+=== RUN TestReDoSProtection_SafePatterns/safe_alternation
+=== RUN TestReDoSProtection_SafePatterns/safe_group
+=== RUN TestReDoSProtection_SafePatterns/email_pattern
+--- PASS: TestReDoSProtection_SafePatterns (0.00s)
+ --- PASS: TestReDoSProtection_SafePatterns/simple_literal (0.00s)
+ --- PASS: TestReDoSProtection_SafePatterns/character_class (0.00s)
+ --- PASS: TestReDoSProtection_SafePatterns/anchored_pattern (0.00s)
+ --- PASS: TestReDoSProtection_SafePatterns/digit_pattern (0.00s)
+ --- PASS: TestReDoSProtection_SafePatterns/word_boundary (0.00s)
+ --- PASS: TestReDoSProtection_SafePatterns/safe_alternation (0.00s)
+ --- PASS: TestReDoSProtection_SafePatterns/safe_group (0.00s)
+ --- PASS: TestReDoSProtection_SafePatterns/email_pattern (0.00s)
+=== RUN TestReDoSProtection_RealWorldAttackPatterns
+=== RUN TestReDoSProtection_RealWorldAttackPatterns/email_redos
+=== RUN TestReDoSProtection_RealWorldAttackPatterns/json_redos
+=== RUN TestReDoSProtection_RealWorldAttackPatterns/url_redos
+--- PASS: TestReDoSProtection_RealWorldAttackPatterns (0.00s)
+ --- PASS: TestReDoSProtection_RealWorldAttackPatterns/email_redos (0.00s)
+ --- PASS: TestReDoSProtection_RealWorldAttackPatterns/json_redos (0.00s)
+ --- PASS: TestReDoSProtection_RealWorldAttackPatterns/url_redos (0.00s)
+=== RUN TestReDoSProtection_EdgeCases
+=== RUN TestReDoSProtection_EdgeCases/escaped_parentheses
+=== RUN TestReDoSProtection_EdgeCases/exactly_max_groups
+=== RUN TestReDoSProtection_EdgeCases/exactly_max_depth
+=== RUN TestReDoSProtection_EdgeCases/empty_pattern
+--- PASS: TestReDoSProtection_EdgeCases (0.00s)
+ --- PASS: TestReDoSProtection_EdgeCases/escaped_parentheses (0.00s)
+ --- PASS: TestReDoSProtection_EdgeCases/exactly_max_groups (0.00s)
+ --- PASS: TestReDoSProtection_EdgeCases/exactly_max_depth (0.00s)
+ --- PASS: TestReDoSProtection_EdgeCases/empty_pattern (0.00s)
+=== RUN TestReDoSProtection_FunctionStyleMatches
+--- PASS: TestReDoSProtection_FunctionStyleMatches (0.00s)
+=== RUN TestRegexConversion_CaseInsensitive
+=== RUN TestRegexConversion_CaseInsensitive/case_insensitive_simple
+=== RUN TestRegexConversion_CaseInsensitive/case_insensitive_complex
+=== RUN TestRegexConversion_CaseInsensitive/case_sensitive_default
+--- PASS: TestRegexConversion_CaseInsensitive (0.00s)
+ --- PASS: TestRegexConversion_CaseInsensitive/case_insensitive_simple (0.00s)
+ --- PASS: TestRegexConversion_CaseInsensitive/case_insensitive_complex (0.00s)
+ --- PASS: TestRegexConversion_CaseInsensitive/case_sensitive_default (0.00s)
+=== RUN TestRegexConversion_NonCapturingGroups
+=== RUN TestRegexConversion_NonCapturingGroups/simple_non_capturing_group
+=== RUN TestRegexConversion_NonCapturingGroups/non_capturing_with_alternation
+=== RUN TestRegexConversion_NonCapturingGroups/nested_non_capturing
+--- PASS: TestRegexConversion_NonCapturingGroups (0.00s)
+ --- PASS: TestRegexConversion_NonCapturingGroups/simple_non_capturing_group (0.00s)
+ --- PASS: TestRegexConversion_NonCapturingGroups/non_capturing_with_alternation (0.00s)
+ --- PASS: TestRegexConversion_NonCapturingGroups/nested_non_capturing (0.00s)
+=== RUN TestRegexConversion_UnsupportedFeatures
+=== RUN TestRegexConversion_UnsupportedFeatures/lookahead_positive
+=== RUN TestRegexConversion_UnsupportedFeatures/lookahead_negative
+=== RUN TestRegexConversion_UnsupportedFeatures/lookbehind_positive
+=== RUN TestRegexConversion_UnsupportedFeatures/lookbehind_negative
+=== RUN TestRegexConversion_UnsupportedFeatures/named_group
+=== RUN TestRegexConversion_UnsupportedFeatures/multiline_flag
+=== RUN TestRegexConversion_UnsupportedFeatures/dotall_flag
+--- PASS: TestRegexConversion_UnsupportedFeatures (0.00s)
+ --- PASS: TestRegexConversion_UnsupportedFeatures/lookahead_positive (0.00s)
+ --- PASS: TestRegexConversion_UnsupportedFeatures/lookahead_negative (0.00s)
+ --- PASS: TestRegexConversion_UnsupportedFeatures/lookbehind_positive (0.00s)
+ --- PASS: TestRegexConversion_UnsupportedFeatures/lookbehind_negative (0.00s)
+ --- PASS: TestRegexConversion_UnsupportedFeatures/named_group (0.00s)
+ --- PASS: TestRegexConversion_UnsupportedFeatures/multiline_flag (0.00s)
+ --- PASS: TestRegexConversion_UnsupportedFeatures/dotall_flag (0.00s)
+=== RUN TestRegexConversion_CharacterClasses
+=== RUN TestRegexConversion_CharacterClasses/digit_class
+=== RUN TestRegexConversion_CharacterClasses/word_class
+=== RUN TestRegexConversion_CharacterClasses/whitespace_class
+=== RUN TestRegexConversion_CharacterClasses/non_digit_class
+=== RUN TestRegexConversion_CharacterClasses/non_word_class
+=== RUN TestRegexConversion_CharacterClasses/non_whitespace_class
+--- PASS: TestRegexConversion_CharacterClasses (0.00s)
+ --- PASS: TestRegexConversion_CharacterClasses/digit_class (0.00s)
+ --- PASS: TestRegexConversion_CharacterClasses/word_class (0.00s)
+ --- PASS: TestRegexConversion_CharacterClasses/whitespace_class (0.00s)
+ --- PASS: TestRegexConversion_CharacterClasses/non_digit_class (0.00s)
+ --- PASS: TestRegexConversion_CharacterClasses/non_word_class (0.00s)
+ --- PASS: TestRegexConversion_CharacterClasses/non_whitespace_class (0.00s)
+=== RUN TestRegexConversion_CombinedFeatures
+=== RUN TestRegexConversion_CombinedFeatures/case_insensitive_with_non_capturing
+=== RUN TestRegexConversion_CombinedFeatures/case_insensitive_with_char_classes
+--- PASS: TestRegexConversion_CombinedFeatures (0.00s)
+ --- PASS: TestRegexConversion_CombinedFeatures/case_insensitive_with_non_capturing (0.00s)
+ --- PASS: TestRegexConversion_CombinedFeatures/case_insensitive_with_char_classes (0.00s)
+=== RUN TestRegexConversion_BackwardCompatibility
+=== RUN TestRegexConversion_BackwardCompatibility/simple_literal
+=== RUN TestRegexConversion_BackwardCompatibility/with_anchors
+=== RUN TestRegexConversion_BackwardCompatibility/with_quantifiers
+=== RUN TestRegexConversion_BackwardCompatibility/with_alternation
+--- PASS: TestRegexConversion_BackwardCompatibility (0.00s)
+ --- PASS: TestRegexConversion_BackwardCompatibility/simple_literal (0.00s)
+ --- PASS: TestRegexConversion_BackwardCompatibility/with_anchors (0.00s)
+ --- PASS: TestRegexConversion_BackwardCompatibility/with_quantifiers (0.00s)
+ --- PASS: TestRegexConversion_BackwardCompatibility/with_alternation (0.00s)
+=== RUN TestIssue85_StringFunctionsInComprehensions
+=== RUN TestIssue85_StringFunctionsInComprehensions/size()_in_exists_one_comprehension
+=== RUN TestIssue85_StringFunctionsInComprehensions/upperAscii()_in_map_comprehension
+=== RUN TestIssue85_StringFunctionsInComprehensions/lowerAscii()_in_map_comprehension
+=== RUN TestIssue85_StringFunctionsInComprehensions/size()_in_map_comprehension
+=== RUN TestIssue85_StringFunctionsInComprehensions/size()_in_filter_comprehension
+--- PASS: TestIssue85_StringFunctionsInComprehensions (0.00s)
+ --- PASS: TestIssue85_StringFunctionsInComprehensions/size()_in_exists_one_comprehension (0.00s)
+ --- PASS: TestIssue85_StringFunctionsInComprehensions/upperAscii()_in_map_comprehension (0.00s)
+ --- PASS: TestIssue85_StringFunctionsInComprehensions/lowerAscii()_in_map_comprehension (0.00s)
+ --- PASS: TestIssue85_StringFunctionsInComprehensions/size()_in_map_comprehension (0.00s)
+ --- PASS: TestIssue85_StringFunctionsInComprehensions/size()_in_filter_comprehension (0.00s)
+=== RUN TestIssue85_SizeOutsideComprehension
+--- PASS: TestIssue85_SizeOutsideComprehension (0.00s)
+=== RUN TestStringFunctions_LowerAscii
+=== RUN TestStringFunctions_LowerAscii/method_call
+=== RUN TestStringFunctions_LowerAscii/with_comparison
+--- PASS: TestStringFunctions_LowerAscii (0.00s)
+ --- PASS: TestStringFunctions_LowerAscii/method_call (0.00s)
+ --- PASS: TestStringFunctions_LowerAscii/with_comparison (0.00s)
+=== RUN TestStringFunctions_UpperAscii
+=== RUN TestStringFunctions_UpperAscii/method_call
+=== RUN TestStringFunctions_UpperAscii/with_startsWith
+--- PASS: TestStringFunctions_UpperAscii (0.00s)
+ --- PASS: TestStringFunctions_UpperAscii/method_call (0.00s)
+ --- PASS: TestStringFunctions_UpperAscii/with_startsWith (0.00s)
+=== RUN TestStringFunctions_Trim
+=== RUN TestStringFunctions_Trim/method_call
+=== RUN TestStringFunctions_Trim/in_comparison
+--- PASS: TestStringFunctions_Trim (0.00s)
+ --- PASS: TestStringFunctions_Trim/method_call (0.00s)
+ --- PASS: TestStringFunctions_Trim/in_comparison (0.00s)
+=== RUN TestStringFunctions_CharAt
+=== RUN TestStringFunctions_CharAt/constant_index
+=== RUN TestStringFunctions_CharAt/dynamic_index
+--- PASS: TestStringFunctions_CharAt (0.00s)
+ --- PASS: TestStringFunctions_CharAt/constant_index (0.00s)
+ --- PASS: TestStringFunctions_CharAt/dynamic_index (0.00s)
+=== RUN TestStringFunctions_IndexOf
+=== RUN TestStringFunctions_IndexOf/simple_indexOf
+=== RUN TestStringFunctions_IndexOf/indexOf_with_offset
+--- PASS: TestStringFunctions_IndexOf (0.00s)
+ --- PASS: TestStringFunctions_IndexOf/simple_indexOf (0.00s)
+ --- PASS: TestStringFunctions_IndexOf/indexOf_with_offset (0.00s)
+=== RUN TestStringFunctions_LastIndexOf
+=== RUN TestStringFunctions_LastIndexOf/simple_lastIndexOf
+--- PASS: TestStringFunctions_LastIndexOf (0.00s)
+ --- PASS: TestStringFunctions_LastIndexOf/simple_lastIndexOf (0.00s)
+=== RUN TestStringFunctions_Substring
+=== RUN TestStringFunctions_Substring/substring_with_start_only_(constant)
+=== RUN TestStringFunctions_Substring/substring_with_start_and_end_(constant)
+=== RUN TestStringFunctions_Substring/substring_with_dynamic_start
+--- PASS: TestStringFunctions_Substring (0.00s)
+ --- PASS: TestStringFunctions_Substring/substring_with_start_only_(constant) (0.00s)
+ --- PASS: TestStringFunctions_Substring/substring_with_start_and_end_(constant) (0.00s)
+ --- PASS: TestStringFunctions_Substring/substring_with_dynamic_start (0.00s)
+=== RUN TestStringFunctions_Replace
+=== RUN TestStringFunctions_Replace/replace_without_limit
+=== RUN TestStringFunctions_Replace/replace_with_limit=-1_(replace_all)
+--- PASS: TestStringFunctions_Replace (0.00s)
+ --- PASS: TestStringFunctions_Replace/replace_without_limit (0.00s)
+ --- PASS: TestStringFunctions_Replace/replace_with_limit=-1_(replace_all) (0.00s)
+=== RUN TestStringFunctions_ReplaceWithLimitError
+--- PASS: TestStringFunctions_ReplaceWithLimitError (0.00s)
+=== RUN TestStringFunctions_Reverse
+=== RUN TestStringFunctions_Reverse/simple_reverse
+--- PASS: TestStringFunctions_Reverse (0.00s)
+ --- PASS: TestStringFunctions_Reverse/simple_reverse (0.00s)
+=== RUN TestStringFunctions_Split
+=== RUN TestStringFunctions_Split/method_call_-_basic_split
+=== RUN TestStringFunctions_Split/field_split
+=== RUN TestStringFunctions_Split/split_with_limit_-1_(unlimited)
+=== RUN TestStringFunctions_Split/split_with_limit_0_(empty_array)
+=== RUN TestStringFunctions_Split/split_with_limit_1_(no_split)
+=== RUN TestStringFunctions_Split/split_with_limit_2
+=== RUN TestStringFunctions_Split/split_with_limit_3
+=== RUN TestStringFunctions_Split/split_with_space_delimiter
+--- PASS: TestStringFunctions_Split (0.01s)
+ --- PASS: TestStringFunctions_Split/method_call_-_basic_split (0.00s)
+ --- PASS: TestStringFunctions_Split/field_split (0.00s)
+ --- PASS: TestStringFunctions_Split/split_with_limit_-1_(unlimited) (0.00s)
+ --- PASS: TestStringFunctions_Split/split_with_limit_0_(empty_array) (0.00s)
+ --- PASS: TestStringFunctions_Split/split_with_limit_1_(no_split) (0.00s)
+ --- PASS: TestStringFunctions_Split/split_with_limit_2 (0.00s)
+ --- PASS: TestStringFunctions_Split/split_with_limit_3 (0.00s)
+ --- PASS: TestStringFunctions_Split/split_with_space_delimiter (0.00s)
+=== RUN TestStringFunctions_Split_InComprehensions
+=== RUN TestStringFunctions_Split_InComprehensions/split_in_exists_comprehension
+=== RUN TestStringFunctions_Split_InComprehensions/split_in_all_comprehension
+=== RUN TestStringFunctions_Split_InComprehensions/split_in_filter_comprehension
+=== RUN TestStringFunctions_Split_InComprehensions/split_in_map_comprehension
+--- PASS: TestStringFunctions_Split_InComprehensions (0.00s)
+ --- PASS: TestStringFunctions_Split_InComprehensions/split_in_exists_comprehension (0.00s)
+ --- PASS: TestStringFunctions_Split_InComprehensions/split_in_all_comprehension (0.00s)
+ --- PASS: TestStringFunctions_Split_InComprehensions/split_in_filter_comprehension (0.00s)
+ --- PASS: TestStringFunctions_Split_InComprehensions/split_in_map_comprehension (0.00s)
+=== RUN TestStringFunctions_Split_Errors
+=== RUN TestStringFunctions_Split_Errors/negative_limit_other_than_-1
+--- PASS: TestStringFunctions_Split_Errors (0.00s)
+ --- PASS: TestStringFunctions_Split_Errors/negative_limit_other_than_-1 (0.00s)
+=== RUN TestStringFunctions_Join
+=== RUN TestStringFunctions_Join/method_call_-_basic_join_with_delimiter
+=== RUN TestStringFunctions_Join/join_without_delimiter_(empty_string)
+=== RUN TestStringFunctions_Join/join_array_field
+=== RUN TestStringFunctions_Join/join_with_space_delimiter
+=== RUN TestStringFunctions_Join/join_with_pipe_delimiter
+--- PASS: TestStringFunctions_Join (0.00s)
+ --- PASS: TestStringFunctions_Join/method_call_-_basic_join_with_delimiter (0.00s)
+ --- PASS: TestStringFunctions_Join/join_without_delimiter_(empty_string) (0.00s)
+ --- PASS: TestStringFunctions_Join/join_array_field (0.00s)
+ --- PASS: TestStringFunctions_Join/join_with_space_delimiter (0.00s)
+ --- PASS: TestStringFunctions_Join/join_with_pipe_delimiter (0.00s)
+=== RUN TestStringFunctions_Join_WithComprehensions
+=== RUN TestStringFunctions_Join_WithComprehensions/join_filtered_array
+=== RUN TestStringFunctions_Join_WithComprehensions/join_mapped_array
+--- PASS: TestStringFunctions_Join_WithComprehensions (0.00s)
+ --- PASS: TestStringFunctions_Join_WithComprehensions/join_filtered_array (0.00s)
+ --- PASS: TestStringFunctions_Join_WithComprehensions/join_mapped_array (0.00s)
+=== RUN TestStringFunctions_Format
+=== RUN TestStringFunctions_Format/method_call_-_format_with_%s
+=== RUN TestStringFunctions_Format/format_with_%d_(converted_to_%s)
+=== RUN TestStringFunctions_Format/format_with_%f_(converted_to_%s)
+=== RUN TestStringFunctions_Format/format_with_multiple_args
+=== RUN TestStringFunctions_Format/format_with_field_values
+=== RUN TestStringFunctions_Format/format_with_escaped_%%
+--- PASS: TestStringFunctions_Format (0.00s)
+ --- PASS: TestStringFunctions_Format/method_call_-_format_with_%s (0.00s)
+ --- PASS: TestStringFunctions_Format/format_with_%d_(converted_to_%s) (0.00s)
+ --- PASS: TestStringFunctions_Format/format_with_%f_(converted_to_%s) (0.00s)
+ --- PASS: TestStringFunctions_Format/format_with_multiple_args (0.00s)
+ --- PASS: TestStringFunctions_Format/format_with_field_values (0.00s)
+ --- PASS: TestStringFunctions_Format/format_with_escaped_%% (0.00s)
+=== RUN TestStringFunctions_Format_Errors
+=== RUN TestStringFunctions_Format_Errors/unsupported_%b_specifier
+=== RUN TestStringFunctions_Format_Errors/unsupported_%x_specifier
+--- PASS: TestStringFunctions_Format_Errors (0.00s)
+ --- PASS: TestStringFunctions_Format_Errors/unsupported_%b_specifier (0.00s)
+ --- PASS: TestStringFunctions_Format_Errors/unsupported_%x_specifier (0.00s)
+=== RUN TestStringFunctions_NoPanicOnEmptyArgs
+=== RUN TestStringFunctions_NoPanicOnEmptyArgs/defensive_checks_exist
+--- PASS: TestStringFunctions_NoPanicOnEmptyArgs (0.00s)
+ --- PASS: TestStringFunctions_NoPanicOnEmptyArgs/defensive_checks_exist (0.00s)
+=== RUN TestJSONColumnTableReference
+=== RUN TestJSONColumnTableReference/json_column_metadata
+ transform_struct_coverage_test.go:82: Generated SQL for Access metadata JSON column - should use ->> operator: assets.metadata->>'status' = 'active'
+=== RUN TestJSONColumnTableReference/json_column_properties
+ transform_struct_coverage_test.go:82: Generated SQL for Access properties JSON column: assets.properties->>'version' = '1.0'
+=== RUN TestJSONColumnTableReference/json_column_content
+ transform_struct_coverage_test.go:82: Generated SQL for Access content JSON column: assets.content->>'title' = 'test'
+=== RUN TestJSONColumnTableReference/nested_json_access
+ transform_struct_coverage_test.go:82: Generated SQL for Nested JSON field access: assets.metadata->'user'->>'name' = 'admin'
+=== RUN TestJSONColumnTableReference/json_with_has
+ transform_struct_coverage_test.go:82: Generated SQL for has() on JSON column: assets.metadata ? 'status'
+--- PASS: TestJSONColumnTableReference (0.00s)
+ --- PASS: TestJSONColumnTableReference/json_column_metadata (0.00s)
+ --- PASS: TestJSONColumnTableReference/json_column_properties (0.00s)
+ --- PASS: TestJSONColumnTableReference/json_column_content (0.00s)
+ --- PASS: TestJSONColumnTableReference/nested_json_access (0.00s)
+ --- PASS: TestJSONColumnTableReference/json_with_has (0.00s)
+=== RUN TestTableReferenceDetection
+=== RUN TestTableReferenceDetection/simple_column_access
+ transform_struct_coverage_test.go:140: Generated SQL: users.name = 'test'
+=== RUN TestTableReferenceDetection/integer_column
+ transform_struct_coverage_test.go:140: Generated SQL: users.age > 18
+=== RUN TestTableReferenceDetection/combined_columns_and_json
+ transform_struct_coverage_test.go:140: Generated SQL: users.name = 'admin' AND users.metadata->>'role' = 'superuser'
+--- PASS: TestTableReferenceDetection (0.00s)
+ --- PASS: TestTableReferenceDetection/simple_column_access (0.00s)
+ --- PASS: TestTableReferenceDetection/integer_column (0.00s)
+ --- PASS: TestTableReferenceDetection/combined_columns_and_json (0.00s)
+=== RUN TestMapComprehensionAsTransform
+=== RUN TestMapComprehensionAsTransform/map_simple_transform
+ transform_struct_coverage_test.go:198: Generated SQL: ARRAY(SELECT s * 2 FROM UNNEST(data.scores) AS s)
+=== RUN TestMapComprehensionAsTransform/map_with_addition
+ transform_struct_coverage_test.go:198: Generated SQL: ARRAY(SELECT s + 10 FROM UNNEST(data.scores) AS s)
+=== RUN TestMapComprehensionAsTransform/map_double_array
+ transform_struct_coverage_test.go:198: Generated SQL: ARRAY(SELECT p * 1.1 FROM UNNEST(data.prices) AS p)
+--- PASS: TestMapComprehensionAsTransform (0.00s)
+ --- PASS: TestMapComprehensionAsTransform/map_simple_transform (0.00s)
+ --- PASS: TestMapComprehensionAsTransform/map_with_addition (0.00s)
+ --- PASS: TestMapComprehensionAsTransform/map_double_array (0.00s)
+=== RUN TestStructExpressions
+=== RUN TestStructExpressions/simple_map_struct
+ transform_struct_coverage_test.go:253: Generated SQL for Simple map structure: ROW('value', 42)
+=== RUN TestStructExpressions/nested_map_struct
+ transform_struct_coverage_test.go:253: Generated SQL for Nested map structure: ROW(ROW('test', 30))
+=== RUN TestStructExpressions/map_with_mixed_types
+ transform_struct_coverage_test.go:253: Generated SQL for Map with mixed value types: ROW('test', 42, TRUE)
+--- PASS: TestStructExpressions (0.00s)
+ --- PASS: TestStructExpressions/simple_map_struct (0.00s)
+ --- PASS: TestStructExpressions/nested_map_struct (0.00s)
+ --- PASS: TestStructExpressions/map_with_mixed_types (0.00s)
+=== RUN TestEdgeCasesForCoverage
+=== RUN TestEdgeCasesForCoverage/deeply_nested_json
+ transform_struct_coverage_test.go:310: Generated SQL for Deeply nested JSON path: records.metadata->'a'->'b'->'c'->>'d' = 'deep'
+=== RUN TestEdgeCasesForCoverage/json_with_comparison
+ transform_struct_coverage_test.go:310: Generated SQL for JSON field with numeric comparison: (records.metadata->>'count')::numeric > 10
+=== RUN TestEdgeCasesForCoverage/array_with_complex_filter
+ transform_struct_coverage_test.go:310: Generated SQL for Filter with multiple string operations: ARRAY(SELECT t FROM UNNEST(records.tags) AS t WHERE t LIKE 'prod%' ESCAPE E'\\' AND t LIKE '%ion' ESCAPE E'\\')
+--- PASS: TestEdgeCasesForCoverage (0.00s)
+ --- PASS: TestEdgeCasesForCoverage/deeply_nested_json (0.00s)
+ --- PASS: TestEdgeCasesForCoverage/json_with_comparison (0.00s)
+ --- PASS: TestEdgeCasesForCoverage/array_with_complex_filter (0.00s)
+=== RUN FuzzConvert
+=== RUN FuzzConvert/seed#0
+=== RUN FuzzConvert/seed#1
+=== RUN FuzzConvert/seed#2
+=== RUN FuzzConvert/seed#3
+=== RUN FuzzConvert/seed#4
+=== RUN FuzzConvert/seed#5
+=== RUN FuzzConvert/seed#6
+=== RUN FuzzConvert/seed#7
+=== RUN FuzzConvert/seed#8
+=== RUN FuzzConvert/seed#9
+=== RUN FuzzConvert/seed#10
+=== RUN FuzzConvert/seed#11
+=== RUN FuzzConvert/seed#12
+=== RUN FuzzConvert/seed#13
+=== RUN FuzzConvert/seed#14
+=== RUN FuzzConvert/seed#15
+=== RUN FuzzConvert/seed#16
+=== RUN FuzzConvert/seed#17
+=== RUN FuzzConvert/seed#18
+=== RUN FuzzConvert/seed#19
+=== RUN FuzzConvert/seed#20
+=== RUN FuzzConvert/seed#21
+=== RUN FuzzConvert/seed#22
+=== RUN FuzzConvert/seed#23
+=== RUN FuzzConvert/seed#24
+=== RUN FuzzConvert/seed#25
+=== RUN FuzzConvert/seed#26
+=== RUN FuzzConvert/seed#27
+=== RUN FuzzConvert/seed#28
+=== RUN FuzzConvert/299bc76ba66bca6b
+--- PASS: FuzzConvert (0.01s)
+ --- PASS: FuzzConvert/seed#0 (0.00s)
+ --- PASS: FuzzConvert/seed#1 (0.00s)
+ --- PASS: FuzzConvert/seed#2 (0.00s)
+ --- PASS: FuzzConvert/seed#3 (0.00s)
+ --- PASS: FuzzConvert/seed#4 (0.00s)
+ --- PASS: FuzzConvert/seed#5 (0.00s)
+ --- PASS: FuzzConvert/seed#6 (0.00s)
+ --- PASS: FuzzConvert/seed#7 (0.00s)
+ --- PASS: FuzzConvert/seed#8 (0.00s)
+ --- PASS: FuzzConvert/seed#9 (0.00s)
+ --- PASS: FuzzConvert/seed#10 (0.00s)
+ --- PASS: FuzzConvert/seed#11 (0.00s)
+ --- PASS: FuzzConvert/seed#12 (0.00s)
+ --- PASS: FuzzConvert/seed#13 (0.00s)
+ --- PASS: FuzzConvert/seed#14 (0.00s)
+ --- PASS: FuzzConvert/seed#15 (0.00s)
+ --- PASS: FuzzConvert/seed#16 (0.00s)
+ --- PASS: FuzzConvert/seed#17 (0.00s)
+ --- PASS: FuzzConvert/seed#18 (0.00s)
+ --- PASS: FuzzConvert/seed#19 (0.00s)
+ --- PASS: FuzzConvert/seed#20 (0.00s)
+ --- PASS: FuzzConvert/seed#21 (0.00s)
+ --- PASS: FuzzConvert/seed#22 (0.00s)
+ --- PASS: FuzzConvert/seed#23 (0.00s)
+ --- PASS: FuzzConvert/seed#24 (0.00s)
+ --- PASS: FuzzConvert/seed#25 (0.00s)
+ --- PASS: FuzzConvert/seed#26 (0.00s)
+ --- PASS: FuzzConvert/seed#27 (0.00s)
+ --- PASS: FuzzConvert/seed#28 (0.00s)
+ --- PASS: FuzzConvert/299bc76ba66bca6b (0.00s)
+=== RUN FuzzEscapeLikePattern
+=== RUN FuzzEscapeLikePattern/seed#0
+=== RUN FuzzEscapeLikePattern/seed#1
+=== RUN FuzzEscapeLikePattern/seed#2
+=== RUN FuzzEscapeLikePattern/seed#3
+=== RUN FuzzEscapeLikePattern/seed#4
+=== RUN FuzzEscapeLikePattern/seed#5
+=== RUN FuzzEscapeLikePattern/seed#6
+=== RUN FuzzEscapeLikePattern/seed#7
+=== RUN FuzzEscapeLikePattern/seed#8
+=== RUN FuzzEscapeLikePattern/seed#9
+=== RUN FuzzEscapeLikePattern/seed#10
+=== RUN FuzzEscapeLikePattern/seed#11
+=== RUN FuzzEscapeLikePattern/seed#12
+=== RUN FuzzEscapeLikePattern/seed#13
+=== RUN FuzzEscapeLikePattern/seed#14
+=== RUN FuzzEscapeLikePattern/seed#15
+=== RUN FuzzEscapeLikePattern/seed#16
+=== RUN FuzzEscapeLikePattern/seed#17
+=== RUN FuzzEscapeLikePattern/seed#18
+=== RUN FuzzEscapeLikePattern/seed#19
+=== RUN FuzzEscapeLikePattern/seed#20
+--- PASS: FuzzEscapeLikePattern (0.01s)
+ --- PASS: FuzzEscapeLikePattern/seed#0 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#1 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#2 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#3 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#4 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#5 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#6 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#7 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#8 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#9 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#10 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#11 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#12 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#13 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#14 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#15 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#16 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#17 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#18 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#19 (0.00s)
+ --- PASS: FuzzEscapeLikePattern/seed#20 (0.00s)
+=== RUN FuzzConvertRE2ToPOSIX
+=== RUN FuzzConvertRE2ToPOSIX/seed#0
+=== RUN FuzzConvertRE2ToPOSIX/seed#1
+=== RUN FuzzConvertRE2ToPOSIX/seed#2
+=== RUN FuzzConvertRE2ToPOSIX/seed#3
+=== RUN FuzzConvertRE2ToPOSIX/seed#4
+=== RUN FuzzConvertRE2ToPOSIX/seed#5
+=== RUN FuzzConvertRE2ToPOSIX/seed#6
+=== RUN FuzzConvertRE2ToPOSIX/seed#7
+=== RUN FuzzConvertRE2ToPOSIX/seed#8
+=== RUN FuzzConvertRE2ToPOSIX/seed#9
+=== RUN FuzzConvertRE2ToPOSIX/seed#10
+=== RUN FuzzConvertRE2ToPOSIX/seed#11
+=== RUN FuzzConvertRE2ToPOSIX/seed#12
+=== RUN FuzzConvertRE2ToPOSIX/seed#13
+=== RUN FuzzConvertRE2ToPOSIX/seed#14
+=== RUN FuzzConvertRE2ToPOSIX/seed#15
+=== RUN FuzzConvertRE2ToPOSIX/seed#16
+=== RUN FuzzConvertRE2ToPOSIX/seed#17
+=== RUN FuzzConvertRE2ToPOSIX/seed#18
+=== RUN FuzzConvertRE2ToPOSIX/seed#19
+--- PASS: FuzzConvertRE2ToPOSIX (0.01s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#0 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#1 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#2 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#3 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#4 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#5 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#6 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#7 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#8 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#9 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#10 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#11 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#12 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#13 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#14 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#15 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#16 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#17 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#18 (0.00s)
+ --- PASS: FuzzConvertRE2ToPOSIX/seed#19 (0.00s)
+FAIL
+coverage: 74.1% of statements
+FAIL github.com/spandigital/cel2sql/v3 21.665s
+ github.com/spandigital/cel2sql/v3/examples/basic coverage: 0.0% of statements
+ github.com/spandigital/cel2sql/v3/examples/comprehensions coverage: 0.0% of statements
+ github.com/spandigital/cel2sql/v3/examples/context coverage: 0.0% of statements
+ github.com/spandigital/cel2sql/v3/examples/index_analysis coverage: 0.0% of statements
+ github.com/spandigital/cel2sql/v3/examples/load_table_schema coverage: 0.0% of statements
+ github.com/spandigital/cel2sql/v3/examples/logging coverage: 0.0% of statements
+ github.com/spandigital/cel2sql/v3/examples/parameterized coverage: 0.0% of statements
+ github.com/spandigital/cel2sql/v3/examples/string_extensions coverage: 0.0% of statements
+=== RUN TestPostgreSQL17Compatibility
+2025/10/31 08:26:15 github.com/testcontainers/testcontainers-go - Connected to docker:
+ Server Version: 28.4.0
+ API Version: 1.51
+ Operating System: Docker Desktop
+ Total Memory: 7837 MB
+ Labels:
+ com.docker.desktop.address=unix:///Users/richardwooding/Library/Containers/com.docker.docker/Data/docker-cli.sock
+ Testcontainers for Go Version: v0.38.0
+ Resolved Docker Host: unix:///var/run/docker.sock
+ Resolved Docker Socket Path: /var/run/docker.sock
+ Test SessionID: 7dd9e19bf9b85ae429b118db0b8b19122cea258e87959ab4cc7b9aa2d249cca3
+ Test ProcessID: cc75f7f8-af19-45c7-8269-814b7fa80218
+2025/10/31 08:26:15 🐳 Creating container for image postgres:17
+2025/10/31 08:26:15 🐳 Creating container for image testcontainers/ryuk:0.12.0
+2025/10/31 08:26:15 ✅ Container created: 26d01e78cb8f
+2025/10/31 08:26:15 🐳 Starting container: 26d01e78cb8f
+2025/10/31 08:26:15 ✅ Container started: 26d01e78cb8f
+2025/10/31 08:26:15 ⏳ Waiting for container id 26d01e78cb8f image: testcontainers/ryuk:0.12.0. Waiting for: &{Port:8080/tcp timeout: PollInterval:100ms skipInternalCheck:false skipExternalCheck:false}
+2025/10/31 08:26:16 🔔 Container is ready: 26d01e78cb8f
+2025/10/31 08:26:16 ✅ Container created: 3c7bf5aacb55
+2025/10/31 08:26:16 🐳 Starting container: 3c7bf5aacb55
+2025/10/31 08:26:16 ✅ Container started: 3c7bf5aacb55
+2025/10/31 08:26:16 ⏳ Waiting for container id 3c7bf5aacb55 image: postgres:17. Waiting for: &{timeout: deadline:0xc00051f548 Strategies:[0xc0002e63c0]}
+2025/10/31 08:26:16 🔔 Container is ready: 3c7bf5aacb55
+=== RUN TestPostgreSQL17Compatibility/case_when_ternary_true
+ postgres17_compat_test.go:227: CEL Expression: (test_compat.age > 30 ? "senior" : "junior") == "senior"
+ postgres17_compat_test.go:228: Generated SQL: (CASE WHEN test_compat.age > 30 THEN 'senior' ELSE 'junior' END) = 'senior'
+ postgres17_compat_test.go:229: Expected SQL pattern: (CASE WHEN test_compat.age > 30 THEN 'senior' ELSE 'junior' END) = 'senior'
+ postgres17_compat_test.go:230: Description: Test CASE WHEN for ternary operator (true case)
+ postgres17_compat_test.go:237: Executing query: SELECT COUNT(*) FROM test_compat WHERE (CASE WHEN test_compat.age > 30 THEN 'senior' ELSE 'junior' END) = 'senior'
+ postgres17_compat_test.go:252: Sample matching records:
+ postgres17_compat_test.go:259: - ID: 3, Name: Charlie, Age: 35, Active: true
+=== RUN TestPostgreSQL17Compatibility/case_when_ternary_false
+ postgres17_compat_test.go:227: CEL Expression: (test_compat.age > 30 ? "senior" : "junior") == "junior"
+ postgres17_compat_test.go:228: Generated SQL: (CASE WHEN test_compat.age > 30 THEN 'senior' ELSE 'junior' END) = 'junior'
+ postgres17_compat_test.go:229: Expected SQL pattern: (CASE WHEN test_compat.age > 30 THEN 'senior' ELSE 'junior' END) = 'junior'
+ postgres17_compat_test.go:230: Description: Test CASE WHEN for ternary operator (false case)
+ postgres17_compat_test.go:237: Executing query: SELECT COUNT(*) FROM test_compat WHERE (CASE WHEN test_compat.age > 30 THEN 'senior' ELSE 'junior' END) = 'junior'
+ postgres17_compat_test.go:252: Sample matching records:
+ postgres17_compat_test.go:259: - ID: 1, Name: Alice, Age: 25, Active: true
+ postgres17_compat_test.go:259: - ID: 2, Name: Bob, Age: 30, Active: false
+ postgres17_compat_test.go:259: - ID: 4, Name: David, Age: 28, Active: false
+=== RUN TestPostgreSQL17Compatibility/case_when_nested
+ postgres17_compat_test.go:227: CEL Expression: (test_compat.active ? (test_compat.age > 30 ? "senior_active" : "junior_active") : "inactive") == "junior_active"
+ postgres17_compat_test.go:228: Generated SQL: (CASE WHEN test_compat.active THEN CASE WHEN test_compat.age > 30 THEN 'senior_active' ELSE 'junior_active' END ELSE 'inactive' END) = 'junior_active'
+ postgres17_compat_test.go:229: Expected SQL pattern: (CASE WHEN test_compat.active THEN CASE WHEN test_compat.age > 30 THEN 'senior_active' ELSE 'junior_active' END ELSE 'inactive' END) = 'junior_active'
+ postgres17_compat_test.go:230: Description: Test nested CASE WHEN
+ postgres17_compat_test.go:237: Executing query: SELECT COUNT(*) FROM test_compat WHERE (CASE WHEN test_compat.active THEN CASE WHEN test_compat.age > 30 THEN 'senior_active' ELSE 'junior_active' END ELSE 'inactive' END) = 'junior_active'
+ postgres17_compat_test.go:252: Sample matching records:
+ postgres17_compat_test.go:259: - ID: 1, Name: Alice, Age: 25, Active: true
+=== RUN TestPostgreSQL17Compatibility/cast_to_boolean
+ postgres17_compat_test.go:227: CEL Expression: bool(test_compat.age > 30) == true
+ postgres17_compat_test.go:228: Generated SQL: CAST(test_compat.age > 30 AS BOOLEAN) IS TRUE
+ postgres17_compat_test.go:229: Expected SQL pattern: CAST(test_compat.age > 30 AS BOOLEAN) IS TRUE
+ postgres17_compat_test.go:230: Description: Test CAST to BOOLEAN
+ postgres17_compat_test.go:237: Executing query: SELECT COUNT(*) FROM test_compat WHERE CAST(test_compat.age > 30 AS BOOLEAN) IS TRUE
+ postgres17_compat_test.go:252: Sample matching records:
+ postgres17_compat_test.go:259: - ID: 3, Name: Charlie, Age: 35, Active: true
+=== RUN TestPostgreSQL17Compatibility/cast_to_bigint
+ postgres17_compat_test.go:227: CEL Expression: int(test_compat.score) >= 95
+ postgres17_compat_test.go:228: Generated SQL: CAST(test_compat.score AS BIGINT) >= 95
+ postgres17_compat_test.go:229: Expected SQL pattern: CAST(test_compat.score AS BIGINT) >= 95
+ postgres17_compat_test.go:230: Description: Test CAST to BIGINT
+ postgres17_compat_test.go:237: Executing query: SELECT COUNT(*) FROM test_compat WHERE CAST(test_compat.score AS BIGINT) >= 95
+ postgres17_compat_test.go:252: Sample matching records:
+ postgres17_compat_test.go:259: - ID: 1, Name: Alice, Age: 25, Active: true
+=== RUN TestPostgreSQL17Compatibility/cast_to_text
+ postgres17_compat_test.go:227: CEL Expression: string(test_compat.age) == "30"
+ postgres17_compat_test.go:228: Generated SQL: CAST(test_compat.age AS TEXT) = '30'
+ postgres17_compat_test.go:229: Expected SQL pattern: CAST(test_compat.age AS TEXT) = '30'
+ postgres17_compat_test.go:230: Description: Test CAST to TEXT
+ postgres17_compat_test.go:237: Executing query: SELECT COUNT(*) FROM test_compat WHERE CAST(test_compat.age AS TEXT) = '30'
+ postgres17_compat_test.go:252: Sample matching records:
+ postgres17_compat_test.go:259: - ID: 2, Name: Bob, Age: 30, Active: false
+=== RUN TestPostgreSQL17Compatibility/extract_epoch
+ postgres17_compat_test.go:227: CEL Expression: int(test_compat.created_at) > 1704000000
+ postgres17_compat_test.go:228: Generated SQL: EXTRACT(EPOCH FROM test_compat.created_at)::bigint > 1704000000
+ postgres17_compat_test.go:229: Expected SQL pattern: EXTRACT(EPOCH FROM test_compat.created_at)::bigint > 1704000000
+ postgres17_compat_test.go:230: Description: Test EXTRACT(EPOCH FROM timestamp) for Unix timestamp conversion
+ postgres17_compat_test.go:237: Executing query: SELECT COUNT(*) FROM test_compat WHERE EXTRACT(EPOCH FROM test_compat.created_at)::bigint > 1704000000
+ postgres17_compat_test.go:252: Sample matching records:
+ postgres17_compat_test.go:259: - ID: 1, Name: Alice, Age: 25, Active: true
+ postgres17_compat_test.go:259: - ID: 2, Name: Bob, Age: 30, Active: false
+ postgres17_compat_test.go:259: - ID: 3, Name: Charlie, Age: 35, Active: true
+=== RUN TestPostgreSQL17Compatibility/extract_doy
+ postgres17_compat_test.go:227: CEL Expression: test_compat.created_at.getDayOfYear() > 100
+ postgres17_compat_test.go:228: Generated SQL: EXTRACT(DOY FROM test_compat.created_at) - 1 > 100
+ postgres17_compat_test.go:229: Expected SQL pattern: EXTRACT(DOY FROM test_compat.created_at) - 1 > 100
+ postgres17_compat_test.go:230: Description: Test EXTRACT(DOY ...) for day of year
+ postgres17_compat_test.go:237: Executing query: SELECT COUNT(*) FROM test_compat WHERE EXTRACT(DOY FROM test_compat.created_at) - 1 > 100
+ postgres17_compat_test.go:252: Sample matching records:
+ postgres17_compat_test.go:259: - ID: 2, Name: Bob, Age: 30, Active: false
+ postgres17_compat_test.go:259: - ID: 4, Name: David, Age: 28, Active: false
+=== RUN TestPostgreSQL17Compatibility/extract_dow_monday
+ postgres17_compat_test.go:227: CEL Expression: test_compat.created_at.getDayOfWeek() == 0
+ postgres17_compat_test.go:228: Generated SQL: (EXTRACT(DOW FROM test_compat.created_at) + 6) % 7 = 0
+ postgres17_compat_test.go:229: Expected SQL pattern: (EXTRACT(DOW FROM test_compat.created_at) + 6) % 7 = 0
+ postgres17_compat_test.go:230: Description: Test getDayOfWeek for Monday (CEL value 0)
+ postgres17_compat_test.go:237: Executing query: SELECT COUNT(*) FROM test_compat WHERE (EXTRACT(DOW FROM test_compat.created_at) + 6) % 7 = 0
+ postgres17_compat_test.go:252: Sample matching records:
+ postgres17_compat_test.go:259: - ID: 1, Name: Alice, Age: 25, Active: true
+=== RUN TestPostgreSQL17Compatibility/extract_dow_sunday
+ postgres17_compat_test.go:227: CEL Expression: test_compat.created_at.getDayOfWeek() == 6
+ postgres17_compat_test.go:228: Generated SQL: (EXTRACT(DOW FROM test_compat.created_at) + 6) % 7 = 6
+ postgres17_compat_test.go:229: Expected SQL pattern: (EXTRACT(DOW FROM test_compat.created_at) + 6) % 7 = 6
+ postgres17_compat_test.go:230: Description: Test getDayOfWeek for Sunday (CEL value 6) - fixes issue #42
+ postgres17_compat_test.go:237: Executing query: SELECT COUNT(*) FROM test_compat WHERE (EXTRACT(DOW FROM test_compat.created_at) + 6) % 7 = 6
+ postgres17_compat_test.go:252: Sample matching records:
+ postgres17_compat_test.go:259: - ID: 3, Name: Charlie, Age: 35, Active: true
+=== RUN TestPostgreSQL17Compatibility/extract_dow_thursday
+ postgres17_compat_test.go:227: CEL Expression: test_compat.created_at.getDayOfWeek() == 3
+ postgres17_compat_test.go:228: Generated SQL: (EXTRACT(DOW FROM test_compat.created_at) + 6) % 7 = 3
+ postgres17_compat_test.go:229: Expected SQL pattern: (EXTRACT(DOW FROM test_compat.created_at) + 6) % 7 = 3
+ postgres17_compat_test.go:230: Description: Test getDayOfWeek for Thursday (CEL value 3)
+ postgres17_compat_test.go:237: Executing query: SELECT COUNT(*) FROM test_compat WHERE (EXTRACT(DOW FROM test_compat.created_at) + 6) % 7 = 3
+ postgres17_compat_test.go:252: Sample matching records:
+ postgres17_compat_test.go:259: - ID: 2, Name: Bob, Age: 30, Active: false
+ postgres17_compat_test.go:259: - ID: 4, Name: David, Age: 28, Active: false
+=== RUN TestPostgreSQL17Compatibility/at_time_zone
+ postgres17_compat_test.go:227: CEL Expression: test_compat.created_at > timestamp("2024-01-01T00:00:00Z")
+ postgres17_compat_test.go:228: Generated SQL: test_compat.created_at > CAST('2024-01-01T00:00:00Z' AS TIMESTAMP WITH TIME ZONE)
+ postgres17_compat_test.go:229: Expected SQL pattern: test_compat.created_at > CAST('2024-01-01T00:00:00Z' AS TIMESTAMP WITH TIME ZONE)
+ postgres17_compat_test.go:230: Description: Test timestamp() function converts to CAST AS TIMESTAMP WITH TIME ZONE
+ postgres17_compat_test.go:237: Executing query: SELECT COUNT(*) FROM test_compat WHERE test_compat.created_at > CAST('2024-01-01T00:00:00Z' AS TIMESTAMP WITH TIME ZONE)
+ postgres17_compat_test.go:252: Sample matching records:
+ postgres17_compat_test.go:259: - ID: 1, Name: Alice, Age: 25, Active: true
+ postgres17_compat_test.go:259: - ID: 2, Name: Bob, Age: 30, Active: false
+ postgres17_compat_test.go:259: - ID: 3, Name: Charlie, Age: 35, Active: true
+=== RUN TestPostgreSQL17Compatibility/complex_case_when_with_cast
+ postgres17_compat_test.go:227: CEL Expression: (test_compat.active ? string(test_compat.age) : "0") == "25"
+ postgres17_compat_test.go:228: Generated SQL: (CASE WHEN test_compat.active THEN CAST(test_compat.age AS TEXT) ELSE '0' END) = '25'
+ postgres17_compat_test.go:229: Expected SQL pattern: (CASE WHEN test_compat.active THEN CAST(test_compat.age AS TEXT) ELSE '0' END) = '25'
+ postgres17_compat_test.go:230: Description: Test complex expression combining CASE WHEN and type casting
+ postgres17_compat_test.go:237: Executing query: SELECT COUNT(*) FROM test_compat WHERE (CASE WHEN test_compat.active THEN CAST(test_compat.age AS TEXT) ELSE '0' END) = '25'
+ postgres17_compat_test.go:252: Sample matching records:
+ postgres17_compat_test.go:259: - ID: 1, Name: Alice, Age: 25, Active: true
+=== RUN TestPostgreSQL17Compatibility/epoch_with_conditional
+ postgres17_compat_test.go:227: CEL Expression: (int(test_compat.created_at) > 1720000000 ? "recent" : "old") == "recent"
+ postgres17_compat_test.go:228: Generated SQL: (CASE WHEN EXTRACT(EPOCH FROM test_compat.created_at)::bigint > 1720000000 THEN 'recent' ELSE 'old' END) = 'recent'
+ postgres17_compat_test.go:229: Expected SQL pattern: (CASE WHEN EXTRACT(EPOCH FROM test_compat.created_at)::bigint > 1720000000 THEN 'recent' ELSE 'old' END) = 'recent'
+ postgres17_compat_test.go:230: Description: Test EXTRACT EPOCH combined with CASE WHEN
+ postgres17_compat_test.go:237: Executing query: SELECT COUNT(*) FROM test_compat WHERE (CASE WHEN EXTRACT(EPOCH FROM test_compat.created_at)::bigint > 1720000000 THEN 'recent' ELSE 'old' END) = 'recent'
+ postgres17_compat_test.go:252: Sample matching records:
+ postgres17_compat_test.go:259: - ID: 4, Name: David, Age: 28, Active: false
+2025/10/31 08:26:16 🐳 Stopping container: 3c7bf5aacb55
+2025/10/31 08:26:17 ✅ Container stopped: 3c7bf5aacb55
+2025/10/31 08:26:17 🐳 Terminating container: 3c7bf5aacb55
+2025/10/31 08:26:17 🚫 Container terminated: 3c7bf5aacb55
+--- PASS: TestPostgreSQL17Compatibility (1.58s)
+ --- PASS: TestPostgreSQL17Compatibility/case_when_ternary_true (0.01s)
+ --- PASS: TestPostgreSQL17Compatibility/case_when_ternary_false (0.00s)
+ --- PASS: TestPostgreSQL17Compatibility/case_when_nested (0.00s)
+ --- PASS: TestPostgreSQL17Compatibility/cast_to_boolean (0.00s)
+ --- PASS: TestPostgreSQL17Compatibility/cast_to_bigint (0.00s)
+ --- PASS: TestPostgreSQL17Compatibility/cast_to_text (0.00s)
+ --- PASS: TestPostgreSQL17Compatibility/extract_epoch (0.00s)
+ --- PASS: TestPostgreSQL17Compatibility/extract_doy (0.00s)
+ --- PASS: TestPostgreSQL17Compatibility/extract_dow_monday (0.00s)
+ --- PASS: TestPostgreSQL17Compatibility/extract_dow_sunday (0.00s)
+ --- PASS: TestPostgreSQL17Compatibility/extract_dow_thursday (0.00s)
+ --- PASS: TestPostgreSQL17Compatibility/at_time_zone (0.00s)
+ --- PASS: TestPostgreSQL17Compatibility/complex_case_when_with_cast (0.00s)
+ --- PASS: TestPostgreSQL17Compatibility/epoch_with_conditional (0.00s)
+=== RUN TestConnectionStringLengthValidation
+=== RUN TestConnectionStringLengthValidation/valid_short_connection_string
+=== RUN TestConnectionStringLengthValidation/valid_connection_string_at_limit
+=== RUN TestConnectionStringLengthValidation/connection_string_exceeds_limit
+=== RUN TestConnectionStringLengthValidation/very_long_connection_string
+--- PASS: TestConnectionStringLengthValidation (0.08s)
+ --- PASS: TestConnectionStringLengthValidation/valid_short_connection_string (0.04s)
+ --- PASS: TestConnectionStringLengthValidation/valid_connection_string_at_limit (0.03s)
+ --- PASS: TestConnectionStringLengthValidation/connection_string_exceeds_limit (0.00s)
+ --- PASS: TestConnectionStringLengthValidation/very_long_connection_string (0.00s)
+=== RUN TestMalformedConnectionStringsNoCredentialExposure
+=== RUN TestMalformedConnectionStringsNoCredentialExposure/invalid_syntax_with_credentials
+ provider_connection_security_test.go:112: Error message (should be generic): invalid schema: failed to create connection pool
+=== RUN TestMalformedConnectionStringsNoCredentialExposure/malformed_uri_with_password
+ provider_connection_security_test.go:112: Error message (should be generic): invalid schema: failed to create connection pool
+=== RUN TestMalformedConnectionStringsNoCredentialExposure/broken_url_encoding
+ provider_connection_security_test.go:112: Error message (should be generic): invalid schema: failed to create connection pool
+--- PASS: TestMalformedConnectionStringsNoCredentialExposure (0.00s)
+ --- PASS: TestMalformedConnectionStringsNoCredentialExposure/invalid_syntax_with_credentials (0.00s)
+ --- PASS: TestMalformedConnectionStringsNoCredentialExposure/malformed_uri_with_password (0.00s)
+ --- PASS: TestMalformedConnectionStringsNoCredentialExposure/broken_url_encoding (0.00s)
+=== RUN TestValidConnectionWithPostgreSQL17
+2025/10/31 08:26:17 🐳 Creating container for image postgres:17
+2025/10/31 08:26:17 ✅ Container created: 474722ee44a6
+2025/10/31 08:26:17 🐳 Starting container: 474722ee44a6
+2025/10/31 08:26:17 ✅ Container started: 474722ee44a6
+2025/10/31 08:26:17 ⏳ Waiting for container id 474722ee44a6 image: postgres:17. Waiting for: &{timeout: deadline:0xc0002d7a28 Strategies:[0xc0004b0180]}
+2025/10/31 08:26:18 🔔 Container is ready: 474722ee44a6
+ provider_connection_security_test.go:161: Connection string length: 67 characters
+2025/10/31 08:26:18 🐳 Stopping container: 474722ee44a6
+2025/10/31 08:26:18 ✅ Container stopped: 474722ee44a6
+2025/10/31 08:26:18 🐳 Terminating container: 474722ee44a6
+2025/10/31 08:26:18 🚫 Container terminated: 474722ee44a6
+--- PASS: TestValidConnectionWithPostgreSQL17 (1.06s)
+=== RUN TestInvalidConnectionFormats
+=== RUN TestInvalidConnectionFormats/invalid_scheme
+=== RUN TestInvalidConnectionFormats/invalid_port
+=== RUN TestInvalidConnectionFormats/garbage_string
+--- PASS: TestInvalidConnectionFormats (0.00s)
+ --- PASS: TestInvalidConnectionFormats/invalid_scheme (0.00s)
+ --- PASS: TestInvalidConnectionFormats/invalid_port (0.00s)
+ --- PASS: TestInvalidConnectionFormats/garbage_string (0.00s)
+=== RUN TestConnectionStringSecurityProperties
+=== RUN TestConnectionStringSecurityProperties/error_does_not_leak_connection_string
+ provider_connection_security_test.go:236: Error message: invalid schema: failed to create connection pool
+=== RUN TestConnectionStringSecurityProperties/length_validation_happens_before_parsing
+=== RUN TestConnectionStringSecurityProperties/no_connection_details_in_error_type
+ provider_connection_security_test.go:275: Error message: invalid schema: failed to create connection pool
+--- PASS: TestConnectionStringSecurityProperties (0.00s)
+ --- PASS: TestConnectionStringSecurityProperties/error_does_not_leak_connection_string (0.00s)
+ --- PASS: TestConnectionStringSecurityProperties/length_validation_happens_before_parsing (0.00s)
+ --- PASS: TestConnectionStringSecurityProperties/no_connection_details_in_error_type (0.00s)
+=== RUN TestConnectionStringLengthConstant
+--- PASS: TestConnectionStringLengthConstant (0.00s)
+=== RUN Test_typeProvider_FindStructType
+=== RUN Test_typeProvider_FindStructType/trigrams
+=== RUN Test_typeProvider_FindStructType/trigrams.cell
+=== RUN Test_typeProvider_FindStructType/trigrams.cell.value
+=== RUN Test_typeProvider_FindStructType/not_exists
+=== RUN Test_typeProvider_FindStructType/trigrams.cell.not_exists
+--- PASS: Test_typeProvider_FindStructType (0.00s)
+ --- PASS: Test_typeProvider_FindStructType/trigrams (0.00s)
+ --- PASS: Test_typeProvider_FindStructType/trigrams.cell (0.00s)
+ --- PASS: Test_typeProvider_FindStructType/trigrams.cell.value (0.00s)
+ --- PASS: Test_typeProvider_FindStructType/not_exists (0.00s)
+ --- PASS: Test_typeProvider_FindStructType/trigrams.cell.not_exists (0.00s)
+=== RUN Test_typeProvider_FindStructFieldNames
+=== RUN Test_typeProvider_FindStructFieldNames/wikipedia
+=== RUN Test_typeProvider_FindStructFieldNames/trigrams
+=== RUN Test_typeProvider_FindStructFieldNames/trigrams.cell
+=== RUN Test_typeProvider_FindStructFieldNames/trigrams.cell.sample
+=== RUN Test_typeProvider_FindStructFieldNames/not_exists
+--- PASS: Test_typeProvider_FindStructFieldNames (0.00s)
+ --- PASS: Test_typeProvider_FindStructFieldNames/wikipedia (0.00s)
+ --- PASS: Test_typeProvider_FindStructFieldNames/trigrams (0.00s)
+ --- PASS: Test_typeProvider_FindStructFieldNames/trigrams.cell (0.00s)
+ --- PASS: Test_typeProvider_FindStructFieldNames/trigrams.cell.sample (0.00s)
+ --- PASS: Test_typeProvider_FindStructFieldNames/not_exists (0.00s)
+=== RUN Test_typeProvider_FindStructFieldType
+=== RUN Test_typeProvider_FindStructFieldType/wikipedia.title
+=== RUN Test_typeProvider_FindStructFieldType/wikipedia.id
+=== RUN Test_typeProvider_FindStructFieldType/wikipedia.is_redirect
+=== RUN Test_typeProvider_FindStructFieldType/trigrams.cell
+=== RUN Test_typeProvider_FindStructFieldType/trigrams.cell.value
+=== RUN Test_typeProvider_FindStructFieldType/trigrams.cell.sample
+=== RUN Test_typeProvider_FindStructFieldType/trigrams.cell.sample.id
+=== RUN Test_typeProvider_FindStructFieldType/not_exists_struct
+=== RUN Test_typeProvider_FindStructFieldType/not_exists_field
+--- PASS: Test_typeProvider_FindStructFieldType (0.00s)
+ --- PASS: Test_typeProvider_FindStructFieldType/wikipedia.title (0.00s)
+ --- PASS: Test_typeProvider_FindStructFieldType/wikipedia.id (0.00s)
+ --- PASS: Test_typeProvider_FindStructFieldType/wikipedia.is_redirect (0.00s)
+ --- PASS: Test_typeProvider_FindStructFieldType/trigrams.cell (0.00s)
+ --- PASS: Test_typeProvider_FindStructFieldType/trigrams.cell.value (0.00s)
+ --- PASS: Test_typeProvider_FindStructFieldType/trigrams.cell.sample (0.00s)
+ --- PASS: Test_typeProvider_FindStructFieldType/trigrams.cell.sample.id (0.00s)
+ --- PASS: Test_typeProvider_FindStructFieldType/not_exists_struct (0.00s)
+ --- PASS: Test_typeProvider_FindStructFieldType/not_exists_field (0.00s)
+=== RUN Test_typeProvider_PostgreSQLTypes
+=== RUN Test_typeProvider_PostgreSQLTypes/uuid
+=== RUN Test_typeProvider_PostgreSQLTypes/uuid_array
+=== RUN Test_typeProvider_PostgreSQLTypes/inet
+=== RUN Test_typeProvider_PostgreSQLTypes/cidr
+=== RUN Test_typeProvider_PostgreSQLTypes/macaddr
+=== RUN Test_typeProvider_PostgreSQLTypes/macaddr8
+=== RUN Test_typeProvider_PostgreSQLTypes/xml
+=== RUN Test_typeProvider_PostgreSQLTypes/money
+=== RUN Test_typeProvider_PostgreSQLTypes/tsvector
+=== RUN Test_typeProvider_PostgreSQLTypes/tsquery
+=== RUN Test_typeProvider_PostgreSQLTypes/unknown_type_returns_false
+=== RUN Test_typeProvider_PostgreSQLTypes/point_returns_false
+=== RUN Test_typeProvider_PostgreSQLTypes/polygon_returns_false
+--- PASS: Test_typeProvider_PostgreSQLTypes (0.00s)
+ --- PASS: Test_typeProvider_PostgreSQLTypes/uuid (0.00s)
+ --- PASS: Test_typeProvider_PostgreSQLTypes/uuid_array (0.00s)
+ --- PASS: Test_typeProvider_PostgreSQLTypes/inet (0.00s)
+ --- PASS: Test_typeProvider_PostgreSQLTypes/cidr (0.00s)
+ --- PASS: Test_typeProvider_PostgreSQLTypes/macaddr (0.00s)
+ --- PASS: Test_typeProvider_PostgreSQLTypes/macaddr8 (0.00s)
+ --- PASS: Test_typeProvider_PostgreSQLTypes/xml (0.00s)
+ --- PASS: Test_typeProvider_PostgreSQLTypes/money (0.00s)
+ --- PASS: Test_typeProvider_PostgreSQLTypes/tsvector (0.00s)
+ --- PASS: Test_typeProvider_PostgreSQLTypes/tsquery (0.00s)
+ --- PASS: Test_typeProvider_PostgreSQLTypes/unknown_type_returns_false (0.00s)
+ --- PASS: Test_typeProvider_PostgreSQLTypes/point_returns_false (0.00s)
+ --- PASS: Test_typeProvider_PostgreSQLTypes/polygon_returns_false (0.00s)
+=== RUN TestLoadTableSchema_WithPostgresContainer
+2025/10/31 08:26:18 🐳 Creating container for image postgres:17
+2025/10/31 08:26:18 ✅ Container created: 01d07fa089df
+2025/10/31 08:26:18 🐳 Starting container: 01d07fa089df
+2025/10/31 08:26:18 ✅ Container started: 01d07fa089df
+2025/10/31 08:26:18 ⏳ Waiting for container id 01d07fa089df image: postgres:17. Waiting for: &{timeout: deadline:0xc0004f8268 Strategies:[0xc00057d260]}
+2025/10/31 08:26:19 🔔 Container is ready: 01d07fa089df
+=== RUN TestLoadTableSchema_WithPostgresContainer/field_id
+=== RUN TestLoadTableSchema_WithPostgresContainer/field_name
+=== RUN TestLoadTableSchema_WithPostgresContainer/field_email
+=== RUN TestLoadTableSchema_WithPostgresContainer/field_age
+=== RUN TestLoadTableSchema_WithPostgresContainer/field_created_at
+=== RUN TestLoadTableSchema_WithPostgresContainer/field_is_active
+2025/10/31 08:26:19 🐳 Stopping container: 01d07fa089df
+2025/10/31 08:26:19 ✅ Container stopped: 01d07fa089df
+2025/10/31 08:26:19 🐳 Terminating container: 01d07fa089df
+2025/10/31 08:26:19 🚫 Container terminated: 01d07fa089df
+--- PASS: TestLoadTableSchema_WithPostgresContainer (1.08s)
+ --- PASS: TestLoadTableSchema_WithPostgresContainer/field_id (0.00s)
+ --- PASS: TestLoadTableSchema_WithPostgresContainer/field_name (0.00s)
+ --- PASS: TestLoadTableSchema_WithPostgresContainer/field_email (0.00s)
+ --- PASS: TestLoadTableSchema_WithPostgresContainer/field_age (0.00s)
+ --- PASS: TestLoadTableSchema_WithPostgresContainer/field_created_at (0.00s)
+ --- PASS: TestLoadTableSchema_WithPostgresContainer/field_is_active (0.00s)
+=== RUN TestJSONHasFieldExpressions
+2025/10/31 08:26:19 🐳 Creating container for image postgres:15
+2025/10/31 08:26:19 ✅ Container created: 02e0bd81f9fa
+2025/10/31 08:26:19 🐳 Starting container: 02e0bd81f9fa
+2025/10/31 08:26:19 ✅ Container started: 02e0bd81f9fa
+2025/10/31 08:26:19 ⏳ Waiting for container id 02e0bd81f9fa image: postgres:15. Waiting for: &{timeout: deadline:0xc0004f8d18 Strategies:[0xc000517e00]}
+2025/10/31 08:26:20 🔔 Container is ready: 02e0bd81f9fa
+=== RUN TestJSONHasFieldExpressions/has_jsonb_simple_field
+ provider_testcontainer_test.go:265: CEL Expression: has(information_assets.metadata.corpus)
+ provider_testcontainer_test.go:266: Generated SQL: information_assets.metadata ? 'corpus'
+ provider_testcontainer_test.go:267: Expected SQL pattern: information_assets.metadata ? 'corpus'
+ provider_testcontainer_test.go:285: Executing query: SELECT COUNT(*) FROM information_assets WHERE information_assets.metadata ? 'corpus'
+ provider_testcontainer_test.go:291: Expected count: 6, Actual count: 6
+=== RUN TestJSONHasFieldExpressions/has_jsonb_nested_field
+ provider_testcontainer_test.go:265: CEL Expression: has(information_assets.metadata.corpus.section)
+ provider_testcontainer_test.go:266: Generated SQL: jsonb_extract_path_text(information_assets.metadata, 'corpus', 'section') IS NOT NULL
+ provider_testcontainer_test.go:267: Expected SQL pattern: jsonb_extract_path_text(information_assets.metadata, 'corpus', 'section') IS NOT NULL
+ provider_testcontainer_test.go:285: Executing query: SELECT COUNT(*) FROM information_assets WHERE jsonb_extract_path_text(information_assets.metadata, 'corpus', 'section') IS NOT NULL
+ provider_testcontainer_test.go:291: Expected count: 6, Actual count: 6
+=== RUN TestJSONHasFieldExpressions/has_json_simple_field
+ provider_testcontainer_test.go:265: CEL Expression: has(information_assets.properties.visibility)
+ provider_testcontainer_test.go:266: Generated SQL: information_assets.properties->'visibility' IS NOT NULL
+ provider_testcontainer_test.go:267: Expected SQL pattern: information_assets.properties->'visibility' IS NOT NULL
+ provider_testcontainer_test.go:285: Executing query: SELECT COUNT(*) FROM information_assets WHERE information_assets.properties->'visibility' IS NOT NULL
+ provider_testcontainer_test.go:291: Expected count: 6, Actual count: 6
+=== RUN TestJSONHasFieldExpressions/has_jsonb_nonexistent_field
+ provider_testcontainer_test.go:265: CEL Expression: has(information_assets.metadata.nonexistent)
+ provider_testcontainer_test.go:266: Generated SQL: information_assets.metadata ? 'nonexistent'
+ provider_testcontainer_test.go:267: Expected SQL pattern: information_assets.metadata ? 'nonexistent'
+ provider_testcontainer_test.go:285: Executing query: SELECT COUNT(*) FROM information_assets WHERE information_assets.metadata ? 'nonexistent'
+ provider_testcontainer_test.go:291: Expected count: 0, Actual count: 0
+=== RUN TestJSONHasFieldExpressions/has_jsonb_deeply_nested_field
+ provider_testcontainer_test.go:265: CEL Expression: has(information_assets.metadata.corpus.tags)
+ provider_testcontainer_test.go:266: Generated SQL: jsonb_extract_path_text(information_assets.metadata, 'corpus', 'tags') IS NOT NULL
+ provider_testcontainer_test.go:267: Expected SQL pattern: jsonb_extract_path_text(information_assets.metadata, 'corpus', 'tags') IS NOT NULL
+ provider_testcontainer_test.go:285: Executing query: SELECT COUNT(*) FROM information_assets WHERE jsonb_extract_path_text(information_assets.metadata, 'corpus', 'tags') IS NOT NULL
+ provider_testcontainer_test.go:291: Expected count: 6, Actual count: 6
+=== RUN TestJSONHasFieldExpressions/has_jsonb_version_field
+ provider_testcontainer_test.go:265: CEL Expression: has(information_assets.metadata.version.major)
+ provider_testcontainer_test.go:266: Generated SQL: jsonb_extract_path_text(information_assets.metadata, 'version', 'major') IS NOT NULL
+ provider_testcontainer_test.go:267: Expected SQL pattern: jsonb_extract_path_text(information_assets.metadata, 'version', 'major') IS NOT NULL
+ provider_testcontainer_test.go:285: Executing query: SELECT COUNT(*) FROM information_assets WHERE jsonb_extract_path_text(information_assets.metadata, 'version', 'major') IS NOT NULL
+ provider_testcontainer_test.go:291: Expected count: 6, Actual count: 6
+=== RUN TestJSONHasFieldExpressions/has_jsonb_author_department
+ provider_testcontainer_test.go:265: CEL Expression: has(information_assets.metadata.author.department)
+ provider_testcontainer_test.go:266: Generated SQL: jsonb_extract_path_text(information_assets.metadata, 'author', 'department') IS NOT NULL
+ provider_testcontainer_test.go:267: Expected SQL pattern: jsonb_extract_path_text(information_assets.metadata, 'author', 'department') IS NOT NULL
+ provider_testcontainer_test.go:285: Executing query: SELECT COUNT(*) FROM information_assets WHERE jsonb_extract_path_text(information_assets.metadata, 'author', 'department') IS NOT NULL
+ provider_testcontainer_test.go:291: Expected count: 6, Actual count: 6
+=== RUN TestJSONHasFieldExpressions/has_documents_content_metadata
+ provider_testcontainer_test.go:265: CEL Expression: has(documents.content.metadata)
+ provider_testcontainer_test.go:266: Generated SQL: documents.content ? 'metadata'
+ provider_testcontainer_test.go:267: Expected SQL pattern: documents.content ? 'metadata'
+ provider_testcontainer_test.go:285: Executing query: SELECT COUNT(*) FROM documents WHERE documents.content ? 'metadata'
+ provider_testcontainer_test.go:291: Expected count: 3, Actual count: 3
+ provider_testcontainer_test.go:307: Sample matching records:
+ provider_testcontainer_test.go:313: - ID: 1, Name: Introduction to APIs
+ provider_testcontainer_test.go:313: - ID: 2, Name: Authentication Best Practices
+ provider_testcontainer_test.go:313: - ID: 3, Name: Troubleshooting Common Issues
+=== RUN TestJSONHasFieldExpressions/has_documents_deep_nested
+ provider_testcontainer_test.go:265: CEL Expression: has(documents.content.metadata.corpus.section)
+ provider_testcontainer_test.go:266: Generated SQL: jsonb_extract_path_text(documents.content, 'metadata', 'corpus', 'section') IS NOT NULL
+ provider_testcontainer_test.go:267: Expected SQL pattern: jsonb_extract_path_text(documents.content, 'metadata', 'corpus', 'section') IS NOT NULL
+ provider_testcontainer_test.go:285: Executing query: SELECT COUNT(*) FROM documents WHERE jsonb_extract_path_text(documents.content, 'metadata', 'corpus', 'section') IS NOT NULL
+ provider_testcontainer_test.go:291: Expected count: 3, Actual count: 3
+ provider_testcontainer_test.go:307: Sample matching records:
+ provider_testcontainer_test.go:313: - ID: 1, Name: Introduction to APIs
+ provider_testcontainer_test.go:313: - ID: 2, Name: Authentication Best Practices
+ provider_testcontainer_test.go:313: - ID: 3, Name: Troubleshooting Common Issues
+=== RUN TestJSONHasFieldExpressions/has_classification_security
+ provider_testcontainer_test.go:265: CEL Expression: has(information_assets.classification.security.level)
+ provider_testcontainer_test.go:266: Generated SQL: jsonb_extract_path_text(information_assets.classification, 'security', 'level') IS NOT NULL
+ provider_testcontainer_test.go:267: Expected SQL pattern: jsonb_extract_path_text(information_assets.classification, 'security', 'level') IS NOT NULL
+ provider_testcontainer_test.go:285: Executing query: SELECT COUNT(*) FROM information_assets WHERE jsonb_extract_path_text(information_assets.classification, 'security', 'level') IS NOT NULL
+ provider_testcontainer_test.go:291: Expected count: 6, Actual count: 6
+=== RUN TestJSONHasFieldExpressions/has_conditional_and
+ provider_testcontainer_test.go:265: CEL Expression: has(information_assets.metadata.corpus.section) && information_assets.metadata.corpus.section == "Getting Started"
+ provider_testcontainer_test.go:266: Generated SQL: jsonb_extract_path_text(information_assets.metadata, 'corpus', 'section') IS NOT NULL AND information_assets.metadata->'corpus'->>'section' = 'Getting Started'
+ provider_testcontainer_test.go:267: Expected SQL pattern: jsonb_extract_path_text(information_assets.metadata, 'corpus', 'section') IS NOT NULL AND information_assets.metadata->'corpus'->>'section' = 'Getting Started'
+ provider_testcontainer_test.go:285: Executing query: SELECT COUNT(*) FROM information_assets WHERE jsonb_extract_path_text(information_assets.metadata, 'corpus', 'section') IS NOT NULL AND information_assets.metadata->'corpus'->>'section' = 'Getting Started'
+ provider_testcontainer_test.go:291: Expected count: 2, Actual count: 2
+ provider_testcontainer_test.go:307: Sample matching records:
+ provider_testcontainer_test.go:313: - ID: 1, Name: User Guide Documentation
+ provider_testcontainer_test.go:313: - ID: 4, Name: Migration Guide
+=== RUN TestJSONHasFieldExpressions/has_conditional_or
+ provider_testcontainer_test.go:265: CEL Expression: has(information_assets.metadata.nonexistent) || has(information_assets.metadata.corpus.section)
+ provider_testcontainer_test.go:266: Generated SQL: information_assets.metadata ? 'nonexistent' OR jsonb_extract_path_text(information_assets.metadata, 'corpus', 'section') IS NOT NULL
+ provider_testcontainer_test.go:267: Expected SQL pattern: information_assets.metadata ? 'nonexistent' OR jsonb_extract_path_text(information_assets.metadata, 'corpus', 'section') IS NOT NULL
+ provider_testcontainer_test.go:285: Executing query: SELECT COUNT(*) FROM information_assets WHERE information_assets.metadata ? 'nonexistent' OR jsonb_extract_path_text(information_assets.metadata, 'corpus', 'section') IS NOT NULL
+ provider_testcontainer_test.go:291: Expected count: 6, Actual count: 6
+=== RUN TestJSONHasFieldExpressions/has_null_handling
+=== RUN TestJSONHasFieldExpressions/has_type_mixing
+ provider_testcontainer_test.go:365: Mixed JSON/JSONB has() query returned 6 results
+=== RUN TestJSONHasFieldExpressions/has_regular_fields
+2025/10/31 08:26:20 🐳 Stopping container: 02e0bd81f9fa
+2025/10/31 08:26:20 ✅ Container stopped: 02e0bd81f9fa
+2025/10/31 08:26:20 🐳 Terminating container: 02e0bd81f9fa
+2025/10/31 08:26:20 🚫 Container terminated: 02e0bd81f9fa
+--- PASS: TestJSONHasFieldExpressions (1.09s)
+ --- PASS: TestJSONHasFieldExpressions/has_jsonb_simple_field (0.01s)
+ --- PASS: TestJSONHasFieldExpressions/has_jsonb_nested_field (0.00s)
+ --- PASS: TestJSONHasFieldExpressions/has_json_simple_field (0.00s)
+ --- PASS: TestJSONHasFieldExpressions/has_jsonb_nonexistent_field (0.00s)
+ --- PASS: TestJSONHasFieldExpressions/has_jsonb_deeply_nested_field (0.00s)
+ --- PASS: TestJSONHasFieldExpressions/has_jsonb_version_field (0.00s)
+ --- PASS: TestJSONHasFieldExpressions/has_jsonb_author_department (0.00s)
+ --- PASS: TestJSONHasFieldExpressions/has_documents_content_metadata (0.00s)
+ --- PASS: TestJSONHasFieldExpressions/has_documents_deep_nested (0.00s)
+ --- PASS: TestJSONHasFieldExpressions/has_classification_security (0.00s)
+ --- PASS: TestJSONHasFieldExpressions/has_conditional_and (0.00s)
+ --- PASS: TestJSONHasFieldExpressions/has_conditional_or (0.00s)
+ --- PASS: TestJSONHasFieldExpressions/has_null_handling (0.00s)
+ --- PASS: TestJSONHasFieldExpressions/has_type_mixing (0.00s)
+ --- PASS: TestJSONHasFieldExpressions/has_regular_fields (0.00s)
+=== RUN TestLoadTableSchema_WithArrayTypes
+2025/10/31 08:26:20 🐳 Creating container for image postgres:15
+2025/10/31 08:26:20 ✅ Container created: eba6989d1a08
+2025/10/31 08:26:20 🐳 Starting container: eba6989d1a08
+2025/10/31 08:26:20 ✅ Container started: eba6989d1a08
+2025/10/31 08:26:20 ⏳ Waiting for container id eba6989d1a08 image: postgres:15. Waiting for: &{timeout: deadline:0xc0006cc768 Strategies:[0xc0000db140]}
+2025/10/31 08:26:21 🔔 Container is ready: eba6989d1a08
+2025/10/31 08:26:21 🐳 Stopping container: eba6989d1a08
+2025/10/31 08:26:21 ✅ Container stopped: eba6989d1a08
+2025/10/31 08:26:21 🐳 Terminating container: eba6989d1a08
+2025/10/31 08:26:21 🚫 Container terminated: eba6989d1a08
+--- PASS: TestLoadTableSchema_WithArrayTypes (1.04s)
+=== RUN TestLoadTableSchema_NonExistentTable
+2025/10/31 08:26:21 🐳 Creating container for image postgres:17
+2025/10/31 08:26:21 ✅ Container created: 9b79ca91110a
+2025/10/31 08:26:21 🐳 Starting container: 9b79ca91110a
+2025/10/31 08:26:21 ✅ Container started: 9b79ca91110a
+2025/10/31 08:26:21 ⏳ Waiting for container id 9b79ca91110a image: postgres:17. Waiting for: &{timeout: deadline:0xc0006ccc78 Strategies:[0xc00057aa80]}
+2025/10/31 08:26:22 🔔 Container is ready: 9b79ca91110a
+2025/10/31 08:26:22 🐳 Stopping container: 9b79ca91110a
+2025/10/31 08:26:22 ✅ Container stopped: 9b79ca91110a
+2025/10/31 08:26:22 🐳 Terminating container: 9b79ca91110a
+2025/10/31 08:26:22 🚫 Container terminated: 9b79ca91110a
+--- PASS: TestLoadTableSchema_NonExistentTable (1.02s)
+=== RUN TestLoadTableSchema_WithoutConnection
+--- PASS: TestLoadTableSchema_WithoutConnection (0.00s)
+=== RUN TestCELToSQL_ComprehensiveIntegration
+2025/10/31 08:26:22 🐳 Creating container for image postgres:15
+2025/10/31 08:26:22 ✅ Container created: 7334c1b3722a
+2025/10/31 08:26:22 🐳 Starting container: 7334c1b3722a
+2025/10/31 08:26:22 ✅ Container started: 7334c1b3722a
+2025/10/31 08:26:22 ⏳ Waiting for container id 7334c1b3722a image: postgres:15. Waiting for: &{timeout: deadline:0xc0006cc4b8 Strategies:[0xc00057a480]}
+2025/10/31 08:26:23 🔔 Container is ready: 7334c1b3722a
+=== RUN TestCELToSQL_ComprehensiveIntegration/basic_equality
+ provider_testcontainer_test.go:688: CEL: users.name == "John Doe"
+ provider_testcontainer_test.go:689: SQL: users.name = 'John Doe'
+=== RUN TestCELToSQL_ComprehensiveIntegration/numeric_comparison
+ provider_testcontainer_test.go:688: CEL: users.age > 28
+ provider_testcontainer_test.go:689: SQL: users.age > 28
+=== RUN TestCELToSQL_ComprehensiveIntegration/boolean_filter
+ provider_testcontainer_test.go:688: CEL: users.is_active == true
+ provider_testcontainer_test.go:689: SQL: users.is_active IS TRUE
+=== RUN TestCELToSQL_ComprehensiveIntegration/date_arithmetic_recent
+ provider_testcontainer_test.go:688: CEL: users.created_at > timestamp("2024-01-01T00:00:00Z")
+ provider_testcontainer_test.go:689: SQL: users.created_at > CAST('2024-01-01T00:00:00Z' AS TIMESTAMP WITH TIME ZONE)
+=== RUN TestCELToSQL_ComprehensiveIntegration/array_contains
+ provider_testcontainer_test.go:688: CEL: "electronics" in products.tags
+ provider_testcontainer_test.go:689: SQL: 'electronics' = ANY(products.tags)
+=== RUN TestCELToSQL_ComprehensiveIntegration/array_size
+ provider_testcontainer_test.go:688: CEL: size(products.tags) > 2
+ provider_testcontainer_test.go:689: SQL: COALESCE(ARRAY_LENGTH(products.tags, 1), 0) > 2
+=== RUN TestCELToSQL_ComprehensiveIntegration/complex_condition
+ provider_testcontainer_test.go:688: CEL: users.age >= 25 && users.is_active == true
+ provider_testcontainer_test.go:689: SQL: users.age >= 25 AND users.is_active IS TRUE
+=== RUN TestCELToSQL_ComprehensiveIntegration/numeric_array_filter
+ provider_testcontainer_test.go:688: CEL: 95 in products.scores
+ provider_testcontainer_test.go:689: SQL: 95 = ANY(products.scores)
+=== RUN TestCELToSQL_ComprehensiveIntegration/string_operations
+ provider_testcontainer_test.go:688: CEL: users.email.contains("@example.com")
+ provider_testcontainer_test.go:689: SQL: POSITION('@example.com' IN users.email) > 0
+=== RUN TestCELToSQL_ComprehensiveIntegration/or_condition
+ provider_testcontainer_test.go:688: CEL: users.age < 25 || users.age > 40
+ provider_testcontainer_test.go:689: SQL: users.age < 25 OR users.age > 40
+=== RUN TestCELToSQL_ComprehensiveIntegration/json_field_access
+ provider_testcontainer_test.go:688: CEL: users.preferences.theme == "dark"
+ provider_testcontainer_test.go:689: SQL: users.preferences->>'theme' = 'dark'
+=== RUN TestCELToSQL_ComprehensiveIntegration/json_boolean_field
+ provider_testcontainer_test.go:688: CEL: users.preferences.notifications == "true"
+ provider_testcontainer_test.go:689: SQL: users.preferences->>'notifications' = 'true'
+=== RUN TestCELToSQL_ComprehensiveIntegration/json_string_field
+ provider_testcontainer_test.go:688: CEL: users.profile.location == "New York"
+ provider_testcontainer_test.go:689: SQL: users.profile->>'location' = 'New York'
+=== RUN TestCELToSQL_ComprehensiveIntegration/product_json_price_string
+ provider_testcontainer_test.go:688: CEL: products.metadata.price == "999.99"
+ provider_testcontainer_test.go:689: SQL: products.metadata->>'price' = '999.99'
+=== RUN TestCELToSQL_ComprehensiveIntegration/product_json_category
+ provider_testcontainer_test.go:688: CEL: products.metadata.category == "electronics"
+ provider_testcontainer_test.go:689: SQL: products.metadata->>'category' = 'electronics'
+=== RUN TestCELToSQL_ComprehensiveIntegration/json_complex_condition
+ provider_testcontainer_test.go:688: CEL: users.preferences.theme == "dark" && users.age > 25
+ provider_testcontainer_test.go:689: SQL: users.preferences->>'theme' = 'dark' AND users.age > 25
+=== RUN TestCELToSQL_ComprehensiveIntegration/date_arithmetic_complex
+ provider_testcontainer_test.go:717: Complex date CEL: users.created_at > timestamp("2024-06-01T00:00:00Z") && users.created_at < timestamp("2024-12-31T23:59:59Z")
+ provider_testcontainer_test.go:718: Complex date SQL: users.created_at > CAST('2024-06-01T00:00:00Z' AS TIMESTAMP WITH TIME ZONE) AND users.created_at < CAST('2024-12-31T23:59:59Z' AS TIMESTAMP WITH TIME ZONE)
+=== RUN TestCELToSQL_ComprehensiveIntegration/array_manipulation_complex
+ provider_testcontainer_test.go:741: Complex array CEL: size(products.tags) >= 2 && "electronics" in products.tags
+ provider_testcontainer_test.go:742: Complex array SQL: COALESCE(ARRAY_LENGTH(products.tags, 1), 0) >= 2 AND 'electronics' = ANY(products.tags)
+2025/10/31 08:26:23 🐳 Stopping container: 7334c1b3722a
+2025/10/31 08:26:23 ✅ Container stopped: 7334c1b3722a
+2025/10/31 08:26:23 🐳 Terminating container: 7334c1b3722a
+2025/10/31 08:26:23 🚫 Container terminated: 7334c1b3722a
+--- PASS: TestCELToSQL_ComprehensiveIntegration (1.09s)
+ --- PASS: TestCELToSQL_ComprehensiveIntegration/basic_equality (0.02s)
+ --- PASS: TestCELToSQL_ComprehensiveIntegration/numeric_comparison (0.00s)
+ --- PASS: TestCELToSQL_ComprehensiveIntegration/boolean_filter (0.00s)
+ --- PASS: TestCELToSQL_ComprehensiveIntegration/date_arithmetic_recent (0.00s)
+ --- PASS: TestCELToSQL_ComprehensiveIntegration/array_contains (0.00s)
+ --- PASS: TestCELToSQL_ComprehensiveIntegration/array_size (0.00s)
+ --- PASS: TestCELToSQL_ComprehensiveIntegration/complex_condition (0.00s)
+ --- PASS: TestCELToSQL_ComprehensiveIntegration/numeric_array_filter (0.00s)
+ --- PASS: TestCELToSQL_ComprehensiveIntegration/string_operations (0.00s)
+ --- PASS: TestCELToSQL_ComprehensiveIntegration/or_condition (0.00s)
+ --- PASS: TestCELToSQL_ComprehensiveIntegration/json_field_access (0.00s)
+ --- PASS: TestCELToSQL_ComprehensiveIntegration/json_boolean_field (0.00s)
+ --- PASS: TestCELToSQL_ComprehensiveIntegration/json_string_field (0.00s)
+ --- PASS: TestCELToSQL_ComprehensiveIntegration/product_json_price_string (0.00s)
+ --- PASS: TestCELToSQL_ComprehensiveIntegration/product_json_category (0.00s)
+ --- PASS: TestCELToSQL_ComprehensiveIntegration/json_complex_condition (0.00s)
+ --- PASS: TestCELToSQL_ComprehensiveIntegration/date_arithmetic_complex (0.00s)
+ --- PASS: TestCELToSQL_ComprehensiveIntegration/array_manipulation_complex (0.00s)
+=== RUN TestLoadTableSchema_JsonComprehensions
+2025/10/31 08:26:23 🐳 Creating container for image postgres:15
+2025/10/31 08:26:23 ✅ Container created: e5d9d3ad0a76
+2025/10/31 08:26:23 🐳 Starting container: e5d9d3ad0a76
+2025/10/31 08:26:23 ✅ Container started: e5d9d3ad0a76
+2025/10/31 08:26:23 ⏳ Waiting for container id e5d9d3ad0a76 image: postgres:15. Waiting for: &{timeout: deadline:0xc0007ceb68 Strategies:[0xc000244cc0]}
+2025/10/31 08:26:24 🔔 Container is ready: e5d9d3ad0a76
+=== RUN TestLoadTableSchema_JsonComprehensions/json_field_types_verification
+=== RUN TestLoadTableSchema_JsonComprehensions/debug_data_structure
+ provider_testcontainer_test.go:929: User 1: Alice Johnson, tags: [developer team-lead mentor] (type: []interface {}), scores: [85 92 88 95] (type: []interface {})
+ provider_testcontainer_test.go:929: User 2: Bob Smith, tags: [marketer analyst] (type: []interface {}), scores: [75 80 78 82] (type: []interface {})
+ provider_testcontainer_test.go:939: First tag from user 1: developer
+ provider_testcontainer_test.go:952: Column: id, Type: integer
+ provider_testcontainer_test.go:952: Column: name, Type: text
+ provider_testcontainer_test.go:952: Column: email, Type: text
+ provider_testcontainer_test.go:952: Column: settings, Type: jsonb
+ provider_testcontainer_test.go:952: Column: metadata, Type: json
+ provider_testcontainer_test.go:952: Column: tags, Type: jsonb
+ provider_testcontainer_test.go:952: Column: scores, Type: jsonb
+ provider_testcontainer_test.go:952: Column: attributes, Type: json
+ provider_testcontainer_test.go:952: Column: created_at, Type: timestamp with time zone
+ provider_testcontainer_test.go:960: Raw tags JSON: ["developer", "team-lead", "mentor"]
+ provider_testcontainer_test.go:961: Raw scores JSON: [85, 92, 88, 95]
+ provider_testcontainer_test.go:970: Count of users with developer tag using ? operator: 2
+ provider_testcontainer_test.go:977: Error with jsonb_array_elements_text: ERROR: cannot extract elements from a scalar (SQLSTATE 22023)
+ provider_testcontainer_test.go:986: Error with jsonb_array_elements for scores: ERROR: cannot extract elements from a scalar (SQLSTATE 22023)
+ provider_testcontainer_test.go:998: JSONB type of tags: array, scores: array
+ provider_testcontainer_test.go:1005: Error with jsonb_array_length: ERROR: cannot get array length of a scalar (SQLSTATE 22023)
+=== RUN TestLoadTableSchema_JsonComprehensions/debug_all_user_data
+ provider_testcontainer_test.go:1035: User 1 (Alice Johnson): tags_null=false, scores_null=false, tags='["developer", "team-lead", "mentor"]', scores='[85, 92, 88, 95]'
+ provider_testcontainer_test.go:1035: User 2 (Bob Smith): tags_null=false, scores_null=false, tags='["marketer", "analyst"]', scores='[75, 80, 78, 82]'
+ provider_testcontainer_test.go:1035: User 3 (Carol Davis): tags_null=false, scores_null=false, tags='["sales", "manager", "closer"]', scores='[90, 94, 91, 89, 93]'
+ provider_testcontainer_test.go:1035: User 4 (David Wilson): tags_null=false, scores_null=false, tags='["developer", "architect", "security"]', scores='[88, 91, 87, 90]'
+ provider_testcontainer_test.go:1035: User 5 (Eva Brown): tags_null=false, scores_null=false, tags='["designer", "ux"]', scores='[83, 86, 84]'
+ provider_testcontainer_test.go:1035: User 6 (Test Empty): tags_null=false, scores_null=false, tags='[]', scores='[]'
+ provider_testcontainer_test.go:1035: User 7 (Test Null): tags_null=false, scores_null=false, tags='null', scores='null'
+ provider_testcontainer_test.go:1046: Count using jsonb_array_elements_text on row 1: 1
+2025/10/31 08:26:24 🐳 Stopping container: e5d9d3ad0a76
+2025/10/31 08:26:24 ✅ Container stopped: e5d9d3ad0a76
+2025/10/31 08:26:24 🐳 Terminating container: e5d9d3ad0a76
+2025/10/31 08:26:24 🚫 Container terminated: e5d9d3ad0a76
+--- PASS: TestLoadTableSchema_JsonComprehensions (1.07s)
+ --- PASS: TestLoadTableSchema_JsonComprehensions/json_field_types_verification (0.00s)
+ --- PASS: TestLoadTableSchema_JsonComprehensions/debug_data_structure (0.02s)
+ --- PASS: TestLoadTableSchema_JsonComprehensions/debug_all_user_data (0.00s)
+=== RUN TestJSONNestedPathExpressions
+2025/10/31 08:26:24 🐳 Creating container for image postgres:15
+2025/10/31 08:26:24 ✅ Container created: cad02cd38e47
+2025/10/31 08:26:24 🐳 Starting container: cad02cd38e47
+2025/10/31 08:26:24 ✅ Container started: cad02cd38e47
+2025/10/31 08:26:24 ⏳ Waiting for container id cad02cd38e47 image: postgres:15. Waiting for: &{timeout: deadline:0xc0002d7868 Strategies:[0xc000244c60]}
+2025/10/31 08:26:25 🔔 Container is ready: cad02cd38e47
+=== RUN TestJSONNestedPathExpressions/nested_jsonb_corpus_section_getting_started
+ provider_testcontainer_test.go:1224: CEL Expression: information_assets.metadata.corpus.section == "Getting Started"
+ provider_testcontainer_test.go:1225: Generated SQL: information_assets.metadata->'corpus'->>'section' = 'Getting Started'
+ provider_testcontainer_test.go:1226: Expected SQL pattern: information_assets.metadata->'corpus'->>'section' = 'Getting Started'
+ provider_testcontainer_test.go:1248: Executing query: SELECT COUNT(*) FROM information_assets WHERE information_assets.metadata->'corpus'->>'section' = 'Getting Started'
+ provider_testcontainer_test.go:1254: Expected count: 2, Actual count: 2
+ provider_testcontainer_test.go:1270: Sample matching records:
+ provider_testcontainer_test.go:1276: - ID: 1, Name: User Guide Documentation
+ provider_testcontainer_test.go:1276: - ID: 4, Name: Migration Guide
+=== RUN TestJSONNestedPathExpressions/nested_jsonb_corpus_section_reference
+ provider_testcontainer_test.go:1224: CEL Expression: information_assets.metadata.corpus.section == "Reference"
+ provider_testcontainer_test.go:1225: Generated SQL: information_assets.metadata->'corpus'->>'section' = 'Reference'
+ provider_testcontainer_test.go:1226: Expected SQL pattern: information_assets.metadata->'corpus'->>'section' = 'Reference'
+ provider_testcontainer_test.go:1248: Executing query: SELECT COUNT(*) FROM information_assets WHERE information_assets.metadata->'corpus'->>'section' = 'Reference'
+ provider_testcontainer_test.go:1254: Expected count: 2, Actual count: 2
+ provider_testcontainer_test.go:1270: Sample matching records:
+ provider_testcontainer_test.go:1276: - ID: 2, Name: API Reference Manual
+ provider_testcontainer_test.go:1276: - ID: 6, Name: Developer Resources
+=== RUN TestJSONNestedPathExpressions/nested_jsonb_version_major_greater_than_1
+ provider_testcontainer_test.go:1224: CEL Expression: information_assets.metadata.version.major > 1
+ provider_testcontainer_test.go:1225: Generated SQL: (information_assets.metadata->'version'->>'major')::numeric > 1
+ provider_testcontainer_test.go:1226: Expected SQL pattern: (information_assets.metadata->'version'->>'major')::numeric > 1
+ provider_testcontainer_test.go:1248: Executing query: SELECT COUNT(*) FROM information_assets WHERE (information_assets.metadata->'version'->>'major')::numeric > 1
+ provider_testcontainer_test.go:1254: Expected count: 3, Actual count: 3
+ provider_testcontainer_test.go:1270: Sample matching records:
+ provider_testcontainer_test.go:1276: - ID: 1, Name: User Guide Documentation
+ provider_testcontainer_test.go:1276: - ID: 2, Name: API Reference Manual
+ provider_testcontainer_test.go:1276: - ID: 4, Name: Migration Guide
+=== RUN TestJSONNestedPathExpressions/nested_json_properties_visibility_public
+ provider_testcontainer_test.go:1224: CEL Expression: information_assets.properties.visibility == "public"
+ provider_testcontainer_test.go:1225: Generated SQL: information_assets.properties->>'visibility' = 'public'
+ provider_testcontainer_test.go:1226: Expected SQL pattern: information_assets.properties->>'visibility' = 'public'
+ provider_testcontainer_test.go:1248: Executing query: SELECT COUNT(*) FROM information_assets WHERE information_assets.properties->>'visibility' = 'public'
+ provider_testcontainer_test.go:1254: Expected count: 5, Actual count: 5
+=== RUN TestJSONNestedPathExpressions/nested_jsonb_author_department
+ provider_testcontainer_test.go:1224: CEL Expression: information_assets.metadata.author.department == "Engineering"
+ provider_testcontainer_test.go:1225: Generated SQL: information_assets.metadata->'author'->>'department' = 'Engineering'
+ provider_testcontainer_test.go:1226: Expected SQL pattern: information_assets.metadata->'author'->>'department' = 'Engineering'
+ provider_testcontainer_test.go:1248: Executing query: SELECT COUNT(*) FROM information_assets WHERE information_assets.metadata->'author'->>'department' = 'Engineering'
+ provider_testcontainer_test.go:1254: Expected count: 2, Actual count: 2
+ provider_testcontainer_test.go:1270: Sample matching records:
+ provider_testcontainer_test.go:1276: - ID: 2, Name: API Reference Manual
+ provider_testcontainer_test.go:1276: - ID: 4, Name: Migration Guide
+=== RUN TestJSONNestedPathExpressions/nested_jsonb_corpus_chapter_greater_than_2
+ provider_testcontainer_test.go:1224: CEL Expression: information_assets.metadata.corpus.chapter > 2
+ provider_testcontainer_test.go:1225: Generated SQL: (information_assets.metadata->'corpus'->>'chapter')::numeric > 2
+ provider_testcontainer_test.go:1226: Expected SQL pattern: (information_assets.metadata->'corpus'->>'chapter')::numeric > 2
+ provider_testcontainer_test.go:1248: Executing query: SELECT COUNT(*) FROM information_assets WHERE (information_assets.metadata->'corpus'->>'chapter')::numeric > 2
+ provider_testcontainer_test.go:1254: Expected count: 3, Actual count: 3
+ provider_testcontainer_test.go:1270: Sample matching records:
+ provider_testcontainer_test.go:1276: - ID: 2, Name: API Reference Manual
+ provider_testcontainer_test.go:1276: - ID: 4, Name: Migration Guide
+ provider_testcontainer_test.go:1276: - ID: 6, Name: Developer Resources
+=== RUN TestJSONNestedPathExpressions/document_nested_corpus_section
+ provider_testcontainer_test.go:1224: CEL Expression: documents.content.metadata.corpus.section == "Getting Started"
+ provider_testcontainer_test.go:1225: Generated SQL: documents.content->'metadata'->'corpus'->>'section' = 'Getting Started'
+ provider_testcontainer_test.go:1226: Expected SQL pattern: documents.content->'metadata'->'corpus'->>'section' = 'Getting Started'
+ provider_testcontainer_test.go:1248: Executing query: SELECT COUNT(*) FROM documents WHERE documents.content->'metadata'->'corpus'->>'section' = 'Getting Started'
+ provider_testcontainer_test.go:1254: Expected count: 1, Actual count: 1
+ provider_testcontainer_test.go:1270: Sample matching records:
+ provider_testcontainer_test.go:1276: - ID: 1, Name: Introduction to APIs
+=== RUN TestJSONNestedPathExpressions/document_nested_stats_total_words
+ provider_testcontainer_test.go:1224: CEL Expression: documents.content.metadata.stats.totalWords > 500
+ provider_testcontainer_test.go:1225: Generated SQL: (documents.content->'metadata'->'stats'->>'totalWords')::numeric > 500
+ provider_testcontainer_test.go:1226: Expected SQL pattern: (documents.content->'metadata'->'stats'->>'totalWords')::numeric > 500
+ provider_testcontainer_test.go:1248: Executing query: SELECT COUNT(*) FROM documents WHERE (documents.content->'metadata'->'stats'->>'totalWords')::numeric > 500
+ provider_testcontainer_test.go:1254: Expected count: 2, Actual count: 2
+ provider_testcontainer_test.go:1270: Sample matching records:
+ provider_testcontainer_test.go:1276: - ID: 2, Name: Authentication Best Practices
+ provider_testcontainer_test.go:1276: - ID: 3, Name: Troubleshooting Common Issues
+=== RUN TestJSONNestedPathExpressions/nested_jsonb_classification_security_level
+ provider_testcontainer_test.go:1224: CEL Expression: information_assets.classification.security.level == "public"
+ provider_testcontainer_test.go:1225: Generated SQL: information_assets.classification->'security'->>'level' = 'public'
+ provider_testcontainer_test.go:1226: Expected SQL pattern: information_assets.classification->'security'->>'level' = 'public'
+ provider_testcontainer_test.go:1248: Executing query: SELECT COUNT(*) FROM information_assets WHERE information_assets.classification->'security'->>'level' = 'public'
+ provider_testcontainer_test.go:1254: Expected count: 5, Actual count: 5
+=== RUN TestJSONNestedPathExpressions/complex_and_condition
+ provider_testcontainer_test.go:1224: CEL Expression: information_assets.metadata.corpus.section == "Getting Started" && information_assets.metadata.version.major == 2
+ provider_testcontainer_test.go:1225: Generated SQL: information_assets.metadata->'corpus'->>'section' = 'Getting Started' AND (information_assets.metadata->'version'->>'major')::numeric = 2
+ provider_testcontainer_test.go:1226: Expected SQL pattern: information_assets.metadata->'corpus'->>'section' = 'Getting Started' AND (information_assets.metadata->'version'->>'major')::numeric = 2
+ provider_testcontainer_test.go:1248: Executing query: SELECT COUNT(*) FROM information_assets WHERE information_assets.metadata->'corpus'->>'section' = 'Getting Started' AND (information_assets.metadata->'version'->>'major')::numeric = 2
+ provider_testcontainer_test.go:1254: Expected count: 2, Actual count: 2
+ provider_testcontainer_test.go:1270: Sample matching records:
+ provider_testcontainer_test.go:1276: - ID: 1, Name: User Guide Documentation
+ provider_testcontainer_test.go:1276: - ID: 4, Name: Migration Guide
+=== RUN TestJSONNestedPathExpressions/complex_or_condition
+ provider_testcontainer_test.go:1224: CEL Expression: information_assets.metadata.corpus.section == "Reference" || information_assets.metadata.corpus.section == "Tutorials"
+ provider_testcontainer_test.go:1225: Generated SQL: information_assets.metadata->'corpus'->>'section' = 'Reference' OR information_assets.metadata->'corpus'->>'section' = 'Tutorials'
+ provider_testcontainer_test.go:1226: Expected SQL pattern: information_assets.metadata->'corpus'->>'section' = 'Reference' OR information_assets.metadata->'corpus'->>'section' = 'Tutorials'
+ provider_testcontainer_test.go:1248: Executing query: SELECT COUNT(*) FROM information_assets WHERE information_assets.metadata->'corpus'->>'section' = 'Reference' OR information_assets.metadata->'corpus'->>'section' = 'Tutorials'
+ provider_testcontainer_test.go:1254: Expected count: 3, Actual count: 3
+ provider_testcontainer_test.go:1270: Sample matching records:
+ provider_testcontainer_test.go:1276: - ID: 2, Name: API Reference Manual
+ provider_testcontainer_test.go:1276: - ID: 3, Name: Advanced Tutorial Series
+ provider_testcontainer_test.go:1276: - ID: 6, Name: Developer Resources
+=== RUN TestJSONNestedPathExpressions/nested_null_handling
+=== RUN TestJSONNestedPathExpressions/nested_type_mixing
+ provider_testcontainer_test.go:1328: Mixed JSON/JSONB query returned 2 results
+=== RUN TestJSONNestedPathExpressions/deeply_nested_json_paths
+2025/10/31 08:26:25 🐳 Stopping container: cad02cd38e47
+2025/10/31 08:26:25 ✅ Container stopped: cad02cd38e47
+2025/10/31 08:26:25 🐳 Terminating container: cad02cd38e47
+2025/10/31 08:26:25 🚫 Container terminated: cad02cd38e47
+--- PASS: TestJSONNestedPathExpressions (1.10s)
+ --- PASS: TestJSONNestedPathExpressions/nested_jsonb_corpus_section_getting_started (0.01s)
+ --- PASS: TestJSONNestedPathExpressions/nested_jsonb_corpus_section_reference (0.00s)
+ --- PASS: TestJSONNestedPathExpressions/nested_jsonb_version_major_greater_than_1 (0.00s)
+ --- PASS: TestJSONNestedPathExpressions/nested_json_properties_visibility_public (0.00s)
+ --- PASS: TestJSONNestedPathExpressions/nested_jsonb_author_department (0.00s)
+ --- PASS: TestJSONNestedPathExpressions/nested_jsonb_corpus_chapter_greater_than_2 (0.00s)
+ --- PASS: TestJSONNestedPathExpressions/document_nested_corpus_section (0.00s)
+ --- PASS: TestJSONNestedPathExpressions/document_nested_stats_total_words (0.00s)
+ --- PASS: TestJSONNestedPathExpressions/nested_jsonb_classification_security_level (0.00s)
+ --- PASS: TestJSONNestedPathExpressions/complex_and_condition (0.00s)
+ --- PASS: TestJSONNestedPathExpressions/complex_or_condition (0.00s)
+ --- PASS: TestJSONNestedPathExpressions/nested_null_handling (0.00s)
+ --- PASS: TestJSONNestedPathExpressions/nested_type_mixing (0.00s)
+ --- PASS: TestJSONNestedPathExpressions/deeply_nested_json_paths (0.00s)
+=== RUN TestRegexPatternMatching
+2025/10/31 08:26:25 🐳 Creating container for image postgres:17
+2025/10/31 08:26:25 ✅ Container created: 46308e70b34e
+2025/10/31 08:26:25 🐳 Starting container: 46308e70b34e
+2025/10/31 08:26:25 ✅ Container started: 46308e70b34e
+2025/10/31 08:26:25 ⏳ Waiting for container id 46308e70b34e image: postgres:17. Waiting for: &{timeout: deadline:0xc0004f8128 Strategies:[0xc00001e240]}
+2025/10/31 08:26:26 🔔 Container is ready: 46308e70b34e
+=== RUN TestRegexPatternMatching/email_domain_pattern
+ provider_testcontainer_test.go:1509: CEL Expression: test_regex.email.matches(".*@example\\.com")
+ provider_testcontainer_test.go:1510: Generated SQL: test_regex.email ~ '.*@example\.com'
+ provider_testcontainer_test.go:1511: Expected SQL pattern: test_regex.email ~ '.*@example\.com'
+ provider_testcontainer_test.go:1512: Description: Match emails with example.com domain
+ provider_testcontainer_test.go:1519: Executing query: SELECT COUNT(*) FROM test_regex WHERE test_regex.email ~ '.*@example\.com'
+ provider_testcontainer_test.go:1534: Sample matching records:
+ provider_testcontainer_test.go:1540: - ID: 1, Name: John Doe, Email: john.doe@example.com, Code: ABC123, Phone: 555-1234
+=== RUN TestRegexPatternMatching/code_pattern_alpha_numeric
+ provider_testcontainer_test.go:1509: CEL Expression: test_regex.code.matches("^[A-Z]{3}\\d{3}$")
+ provider_testcontainer_test.go:1510: Generated SQL: test_regex.code ~ '^[A-Z]{3}[[:digit:]]{3}$'
+ provider_testcontainer_test.go:1511: Expected SQL pattern: test_regex.code ~ '^[A-Z]{3}[[:digit:]]{3}$'
+ provider_testcontainer_test.go:1512: Description: Match 3 uppercase letters followed by 3 digits
+ provider_testcontainer_test.go:1519: Executing query: SELECT COUNT(*) FROM test_regex WHERE test_regex.code ~ '^[A-Z]{3}[[:digit:]]{3}$'
+ provider_testcontainer_test.go:1534: Sample matching records:
+ provider_testcontainer_test.go:1540: - ID: 1, Name: John Doe, Email: john.doe@example.com, Code: ABC123, Phone: 555-1234
+ provider_testcontainer_test.go:1540: - ID: 2, Name: Jane Smith, Email: jane.smith@company.org, Code: XYZ789, Phone: 555-5678
+ provider_testcontainer_test.go:1540: - ID: 3, Name: Bob Johnson, Email: bob@invalid-email, Code: DEF456, Phone: 123.456.7890
+=== RUN TestRegexPatternMatching/phone_basic_format
+ provider_testcontainer_test.go:1509: CEL Expression: test_regex.phone.matches("^\\d{3}-\\d{4}$")
+ provider_testcontainer_test.go:1510: Generated SQL: test_regex.phone ~ '^[[:digit:]]{3}-[[:digit:]]{4}$'
+ provider_testcontainer_test.go:1511: Expected SQL pattern: test_regex.phone ~ '^[[:digit:]]{3}-[[:digit:]]{4}$'
+ provider_testcontainer_test.go:1512: Description: Match basic phone format XXX-XXXX
+ provider_testcontainer_test.go:1519: Executing query: SELECT COUNT(*) FROM test_regex WHERE test_regex.phone ~ '^[[:digit:]]{3}-[[:digit:]]{4}$'
+ provider_testcontainer_test.go:1534: Sample matching records:
+ provider_testcontainer_test.go:1540: - ID: 1, Name: John Doe, Email: john.doe@example.com, Code: ABC123, Phone: 555-1234
+ provider_testcontainer_test.go:1540: - ID: 2, Name: Jane Smith, Email: jane.smith@company.org, Code: XYZ789, Phone: 555-5678
+=== RUN TestRegexPatternMatching/description_word_boundary
+ provider_testcontainer_test.go:1509: CEL Expression: test_regex.description.matches("\\btest\\b")
+ provider_testcontainer_test.go:1510: Generated SQL: test_regex.description ~ '\ytest\y'
+ provider_testcontainer_test.go:1511: Expected SQL pattern: test_regex.description ~ '\ytest\y'
+ provider_testcontainer_test.go:1512: Description: Match whole word 'test' using word boundaries
+ provider_testcontainer_test.go:1519: Executing query: SELECT COUNT(*) FROM test_regex WHERE test_regex.description ~ '\ytest\y'
+ provider_testcontainer_test.go:1534: Sample matching records:
+ provider_testcontainer_test.go:1540: - ID: 1, Name: John Doe, Email: john.doe@example.com, Code: ABC123, Phone: 555-1234
+ provider_testcontainer_test.go:1540: - ID: 4, Name: Alice Brown, Email: alice.brown@test.net, Code: GHI999, Phone: (555) 123-4567
+=== RUN TestRegexPatternMatching/email_function_style
+ provider_testcontainer_test.go:1509: CEL Expression: matches(test_regex.email, ".*\\.org$")
+ provider_testcontainer_test.go:1510: Generated SQL: test_regex.email ~ '.*\.org$'
+ provider_testcontainer_test.go:1511: Expected SQL pattern: test_regex.email ~ '.*\.org$'
+ provider_testcontainer_test.go:1512: Description: Function-style matches for .org domains
+ provider_testcontainer_test.go:1519: Executing query: SELECT COUNT(*) FROM test_regex WHERE test_regex.email ~ '.*\.org$'
+ provider_testcontainer_test.go:1534: Sample matching records:
+ provider_testcontainer_test.go:1540: - ID: 2, Name: Jane Smith, Email: jane.smith@company.org, Code: XYZ789, Phone: 555-5678
+=== RUN TestRegexPatternMatching/complex_pattern_whitespace
+ provider_testcontainer_test.go:1509: CEL Expression: test_regex.description.matches("\\w+\\s+\\w+")
+ provider_testcontainer_test.go:1510: Generated SQL: test_regex.description ~ '[[:alnum:]_]+[[:space:]]+[[:alnum:]_]+'
+ provider_testcontainer_test.go:1511: Expected SQL pattern: test_regex.description ~ '[[:alnum:]_]+[[:space:]]+[[:alnum:]_]+'
+ provider_testcontainer_test.go:1512: Description: Match two words separated by whitespace
+ provider_testcontainer_test.go:1519: Executing query: SELECT COUNT(*) FROM test_regex WHERE test_regex.description ~ '[[:alnum:]_]+[[:space:]]+[[:alnum:]_]+'
+ provider_testcontainer_test.go:1534: Sample matching records:
+ provider_testcontainer_test.go:1540: - ID: 1, Name: John Doe, Email: john.doe@example.com, Code: ABC123, Phone: 555-1234
+ provider_testcontainer_test.go:1540: - ID: 2, Name: Jane Smith, Email: jane.smith@company.org, Code: XYZ789, Phone: 555-5678
+ provider_testcontainer_test.go:1540: - ID: 3, Name: Bob Johnson, Email: bob@invalid-email, Code: DEF456, Phone: 123.456.7890
+=== RUN TestRegexPatternMatching/negated_pattern_no_digits
+ provider_testcontainer_test.go:1509: CEL Expression: !test_regex.name.matches("\\d")
+ provider_testcontainer_test.go:1510: Generated SQL: NOT test_regex.name ~ '[[:digit:]]'
+ provider_testcontainer_test.go:1511: Expected SQL pattern: NOT test_regex.name ~ '[[:digit:]]'
+ provider_testcontainer_test.go:1512: Description: Names that don't contain any digits
+ provider_testcontainer_test.go:1519: Executing query: SELECT COUNT(*) FROM test_regex WHERE NOT test_regex.name ~ '[[:digit:]]'
+ provider_testcontainer_test.go:1534: Sample matching records:
+ provider_testcontainer_test.go:1540: - ID: 1, Name: John Doe, Email: john.doe@example.com, Code: ABC123, Phone: 555-1234
+ provider_testcontainer_test.go:1540: - ID: 2, Name: Jane Smith, Email: jane.smith@company.org, Code: XYZ789, Phone: 555-5678
+ provider_testcontainer_test.go:1540: - ID: 3, Name: Bob Johnson, Email: bob@invalid-email, Code: DEF456, Phone: 123.456.7890
+2025/10/31 08:26:26 🐳 Stopping container: 46308e70b34e
+2025/10/31 08:26:26 ✅ Container stopped: 46308e70b34e
+2025/10/31 08:26:26 🐳 Terminating container: 46308e70b34e
+2025/10/31 08:26:26 🚫 Container terminated: 46308e70b34e
+--- PASS: TestRegexPatternMatching (1.00s)
+ --- PASS: TestRegexPatternMatching/email_domain_pattern (0.00s)
+ --- PASS: TestRegexPatternMatching/code_pattern_alpha_numeric (0.00s)
+ --- PASS: TestRegexPatternMatching/phone_basic_format (0.00s)
+ --- PASS: TestRegexPatternMatching/description_word_boundary (0.00s)
+ --- PASS: TestRegexPatternMatching/email_function_style (0.00s)
+ --- PASS: TestRegexPatternMatching/complex_pattern_whitespace (0.00s)
+ --- PASS: TestRegexPatternMatching/negated_pattern_no_digits (0.00s)
+PASS
+coverage: 92.1% of statements
+ok github.com/spandigital/cel2sql/v3/pg 13.042s coverage: 92.1% of statements
+? github.com/spandigital/cel2sql/v3/sqltypes [no test files]
+ github.com/spandigital/cel2sql/v3/test coverage: 0.0% of statements
+FAIL
+make: *** [test] Error 1