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