Repository Owner: SPANDigital
Repository URL: https://github.com/SPANDigital/cel2sql
Maintainer: Richard Wooding (@richardwooding)
This project converts CEL (Common Expression Language) expressions to PostgreSQL SQL conditions. It was recently migrated from BigQuery to PostgreSQL using the latest pgx v5 driver.
cel2sql.go- Main conversion engine that transforms CEL AST to SQL stringspg/provider.go- PostgreSQL type provider for CEL type system integrationsqltypes/types.go- Custom SQL type definitions for CEL (Date, Time, DateTime)test/testdata.go- PostgreSQL schema definitions for testing
- Uses CEL's protobuf-based type system (
exprpb.Type,exprpb.Expr) - Maps PostgreSQL types to CEL types through the
pg.TypeProvider - Supports composite types, arrays, and nested schemas
- Use Go 1.24+ features
- Follow standard Go naming conventions
- Prefer explicit error handling over panics
- Use context.Context for database operations
- Always use
pgxpool.Poolfor connection pooling - Map PostgreSQL types properly:
text→decls.Stringbigint→decls.Intboolean→decls.Booldouble precision→decls.Doubletimestamp with time zone→decls.Timestampjson→decls.String(with JSON path support)jsonb→decls.String(with JSON path support)
- Support arrays with
Repeated: true - Handle composite types with nested
Schemafields - JSON/JSONB fields support PostgreSQL path operations (
->>)
- CEL expressions like
user.preferences.themeautomatically convert touser.preferences->>'theme' - The converter detects JSON/JSONB columns and applies proper PostgreSQL syntax
- Nested JSON access is supported:
user.profile.settings.key→user.profile->>'settings'->>'key' - JSON field detection happens in
shouldUseJSONPath()andvisitSelect()functions
- Full comprehension support:
all(),exists(),exists_one(),filter(),map() - PostgreSQL UNNEST integration: All comprehensions use
UNNEST()for array processing - Pattern recognition:
comprehensions.gohandles AST pattern matching for comprehension types - Nested comprehensions: Support for complex nested operations
- Schema integration: Works with
pg.Schemaincluding array fields and composite types
- Test files should use PostgreSQL schemas, not BigQuery
- Use
pg.NewTypeProvider()withpg.Schemadefinitions - Include tests for nested types and arrays
- Verify SQL output matches PostgreSQL syntax
- Use testcontainers for integration testing
- CEL:
github.com/google/cel-go- Core CEL functionality - PostgreSQL:
github.com/jackc/pgx/v5- Database driver - Protobuf: Required for CEL (don't remove these dependencies)
- Testing:
github.com/stretchr/testify - Containers:
github.com/testcontainers/testcontainers-go
schema := pg.Schema{
{Name: "field_name", Type: "text", Repeated: false},
{Name: "array_field", Type: "text", Repeated: true},
{Name: "json_field", Type: "jsonb", Repeated: false},
{Name: "composite_field", Type: "composite", Schema: []pg.FieldSchema{...}},
}
provider := pg.NewTypeProvider(map[string]pg.Schema{"TableName": schema})// Load schema from PostgreSQL database
provider, err := pg.NewTypeProviderWithConnection(ctx, connectionString)
if err != nil {
return err
}
defer provider.Close()
// Load specific table schema
err = provider.LoadTableSchema(ctx, "tableName")
if err != nil {
return err
}env, err := cel.NewEnv(
cel.CustomTypeProvider(provider),
cel.Variable("table", cel.ObjectType("TableName")),
)- Add function mapping in
cel2sql.goconversion logic - Add corresponding tests in
cel2sql_test.go - Update README documentation
This project was recently migrated from BigQuery to PostgreSQL and modernized:
- Removed: All
cloud.google.com/go/bigquerydependencies - Removed:
bq/package entirely - Added:
pg/package with PostgreSQL-specific logic - Updated: All tests to use PostgreSQL schemas and testcontainers
- Updated: Documentation to reflect PostgreSQL usage
- Added: Comprehensive JSON/JSONB support with path operations
- Enhanced: Type system with dynamic schema loading
- Improved: SQL generation with PostgreSQL-specific syntax
- JSON/JSONB Support: Full PostgreSQL JSON path operations
- Dynamic Schema Loading: Load table schemas from live PostgreSQL databases
- Enhanced Testing: Comprehensive testcontainer integration tests
- PostgreSQL Optimized: Single quotes, POSITION(), ARRAY_LENGTH(,1), etc.
- Type Safety: Improved type mappings and error handling
- Don't add BigQuery dependencies back
- Don't remove protobuf dependencies (required by CEL)
- Don't use direct SQL string concatenation (use proper escaping)
- Don't ignore context cancellation in database operations
- Consider PostgreSQL-specific SQL syntax differences
- Add comprehensive tests with realistic PostgreSQL schemas
- Update type mappings in
pg/provider.goif needed - Document new CEL operators/functions in README
- Ensure backward compatibility with existing CEL expressions
- Use
cel.AstToCheckedExpr()to inspect CEL AST structure - Check
typeMapin converter for type resolution issues - PostgreSQL arrays use
[]suffix in type names - Composite types require proper nested schema navigation
- Always use parameterized queries when integrating with actual databases
- Validate CEL expressions before conversion
- Sanitize field names and table names in SQL output
- Be cautious with user-provided schema definitions
- Run full test suite including integration tests
- Update version in
go.modif needed - Create release notes documenting changes
- Tag release following semantic versioning
- Update documentation as needed
For questions or issues, contact Richard Wooding or create an issue on the SPANDigital/cel2sql repository.
- Root files: Core library files (
cel2sql.go,comprehensions.go) pg/: PostgreSQL-specific type provider and schema handlingsqltypes/: Custom SQL type definitions for CEL integrationtest/: Test data and schema definitionsexamples/: Example implementations in separate directories:examples/basic/: Basic usage examplesexamples/load_table_schema/: Dynamic schema loading examplesexamples/comprehensions/: CEL comprehensions examples- Each example should be in its own directory with a
main.goandREADME.md
- Each example must be in its own subdirectory under
examples/ - Main file should be named
main.go(not named after the feature) - Include a comprehensive
README.mdexplaining the example - Examples should be runnable with
go run main.gofrom their directory - Document expected output and key concepts demonstrated
- golangci-lint: All code must pass
golangci-lint runwithout issues - Required before commits: Run
golangci-lint runand fix all issues - Common linting rules:
- Use
errors.New()instead offmt.Errorf()for static error messages - Rename unused parameters to
_(e.g.,func foo(used string, _ string)) - Add comments for exported constants and types
- Include package comments for main packages in examples
- Use
- Formatting: Always run
go fmt ./...before committing - Static analysis: Ensure
go vet ./...passes without warnings