Skip to content

Add CUBRID database dialect support#575

Open
search5 wants to merge 10 commits into
go-jet:masterfrom
search5:cubrid-support
Open

Add CUBRID database dialect support#575
search5 wants to merge 10 commits into
go-jet:masterfrom
search5:cubrid-support

Conversation

@search5
Copy link
Copy Markdown

@search5 search5 commented Apr 2, 2026

Motivation

CUBRID is an open-source relational database widely adopted in Korean public-sector and enterprise environments. Despite its maturity (the current stable release is 11.4), there is no type-safe SQL builder for Go that supports CUBRID natively. Developers working with CUBRID in Go are currently limited to raw SQL strings, which sacrifices the compile-time safety and composability that go-jet provides for PostgreSQL, MySQL, and SQLite.

This PR adds first-class CUBRID support to go-jet, following the same architecture and conventions used by the existing dialects.

What This PR Contains

1. cubrid/ — SQL Builder Dialect Package

A complete SQL builder dialect for CUBRID, including:

  • Standard DML statements: SELECT, INSERT, UPDATE, DELETE
  • CUBRID-specific statements: REPLACE INTO, MERGE INTO
  • Hierarchical query support: START WITH, CONNECT BY / CONNECT BY NOCYCLE, ORDER SIBLINGS BY
  • Hierarchical pseudo-columns and functions: PRIOR(), LEVEL, ROWNUM, CONNECT_BY_ROOT(), CONNECT_BY_ISLEAF, SYS_CONNECT_BY_PATH()
  • CUBRID-specific functions: NVL, NVL2, DECODE, TO_CHAR, TO_DATE, TO_DATETIME, TRUNC, INCR, DECR, etc.
  • CAST with CUBRID-native type targets
  • INTERVAL literal expressions
  • LOCK / UNLOCK table statements
  • SET (UNION, INTERSECT, EXCEPT) operations
  • WITH (CTE) support
  • Window functions
  • All expressions support method chaining, consistent with existing dialects

2. generator/cubrid/ — Code Generator

  • Reads CUBRID schema metadata (tables, views, columns, primary keys, nullable flags)
  • Maps CUBRID data types to Go types and SQL builder column types
  • Generates model structs and type-safe table/view builder files
  • Supports three connection methods: DBConnection struct, DSN string, and Pool/HA configurations via cubrid-go driver
  • Integration tests verified against CUBRID 11.4

3. internal/jet/ — Minimal Core Additions

  • cast.go: Shared Cast implementation reusable across dialects
  • clause_cubrid.go: CUBRID-specific SQL clauses (ClauseStartWith, ClauseConnectBy, ClauseOrderSiblingsBy, ClauseMergeInto, ClauseMergeUsing, ClauseMergeOn, ClauseWhenMatched, ClauseWhenNotMatched, ClauseReplaceInto)

4. generator/template/ — Type Mapping Extensions

  • Added CUBRID-specific type mappings to model_template.go and sql_builder_template.go:
    short, monetary, string, nchar, nchar varying, clob, set, multiset, sequence, list, object, oid, timestampltz, datetimeltz, datetimetz
  • Added "CUBRID" case to insertedRowAlias in process.go

5. cmd/jet/main.go — CLI Entry Point

  • Added case "cubrid" to the jet CLI generator, supporting both DSN and host/port connection parameters

6. go.mod

  • Added github.com/search5/cubrid-go driver dependency

Design Decisions

  • Zero changes to existing dialects. The mysql/, postgres/, sqlite/, qrm/, and existing internal/jet/ files are completely untouched. All CUBRID support is purely additive.
  • Follows existing patterns. The package structure, interface design, and chaining API mirror what MySQL, PostgreSQL, and SQLite already do, so existing go-jet users should find the CUBRID dialect immediately familiar.
  • CUBRID-specific features are first-class. Hierarchical queries (CONNECT BY) and MERGE INTO are not afterthoughts — they have dedicated clause types, proper serialization, and full test coverage.

Test Plan

  • go build ./... passes
  • go vet ./... passes (excluding pre-existing WriteByte signature warning)
  • go test ./cubrid/ — all SQL builder unit tests pass
  • go test ./generator/cubrid/ — all unit tests pass
  • go test -tags integration ./generator/cubrid/ — all integration tests pass against CUBRID 11.4
    • Schema metadata extraction (tables, views, columns, PKs, nullable)
    • Code generation (model + SQL builder files)
    • CUBRID-specific type mappings (19 types verified)
    • DSN, Pool, and HA connection modes
  • go test ./internal/jet/ — existing core tests still pass
  • go test ./generator/template/ — template tests pass including new CUBRID type cases

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 2, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.18%. Comparing base (a0558ce) to head (7411362).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #575      +/-   ##
==========================================
+ Coverage   92.22%   93.18%   +0.96%     
==========================================
  Files         138      165      +27     
  Lines        8382     9360     +978     
==========================================
+ Hits         7730     8722     +992     
+ Misses        477      467      -10     
+ Partials      175      171       -4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

search5 added a commit to search5/jet that referenced this pull request Apr 2, 2026
The codecov check on PR go-jet#575 reported 53.41% patch coverage (164 lines
missing), failing the 90% target. This commit addresses the gap with
comprehensive unit tests and CI integration test support.

Unit test additions (cubrid/ package, 78.6% -> 94.5%):

  - select_statement: WINDOW clause, AsTable subquery, ORDER BY with
    NULLS FIRST/LAST, PRECEDING/FOLLOWING window frame offsets
  - set_statement: INTERSECT_ALL, EXCEPT_ALL (both function and method
    forms), ORDER_BY/LIMIT/OFFSET chaining, AsTable on set results
  - insert_statement: MODELS batch insert
  - replace_statement: MODELS batch replace
  - update_statement: SET with column assignment expressions
  - with_statement: WITH, WITH_RECURSIVE, CTE ALIAS (new file)
  - lateral: LATERAL derived table with AS alias (new file)
  - values: VALUES table constructor with AS alias (new file)
  - statement: RawStatement (new file)
  - functions: LPAD, RPAD, CURRENT_TIME, CURRENT_TIMESTAMP, NOW
  - cubrid_functions: TIMEDIFF, CURRENT_USER_, DRANDOM with seed,
    TO_DATETIME with format, TO_TIMESTAMP with format
  - dialect: argumentToString for []byte, float division (/ operator)
  - interval_literal: INTERVALd(0), unitType.String(), intervalDebugString

Unit test additions (internal/jet/, CUBRID files -> 100%):

  - clause_cubrid: full serialization tests for all CUBRID-specific
    clauses with actual data (StartWith, ConnectBy, ConnectBy NOCYCLE,
    OrderSiblingsBy, MergeInto, MergeUsing, MergeOn, WhenMatched
    UPDATE/DELETE, WhenNotMatched INSERT, ReplaceInto with/without
    columns, GetColumns). Also covers all lowercase serialize() wrappers.
  - cast: CAST expression with dialect operator override path

CircleCI configuration (.circleci/config.yml):

  - Add cubrid/cubrid:11.4 Docker service (port 33000, DB: cubdb)
  - Add wait-for-CUBRID step (up to 60s with 2s interval)
  - Add cubrid/... to -coverpkg list in main test run
  - Add CUBRID integration test step running generator/cubrid/... tests
    with -tags integration and CUBRID_DSN env var
  - Merge CUBRID coverage profile into main cover.out before codecov
    upload
@search5 search5 force-pushed the cubrid-support branch 2 times, most recently from 8ce27df to 81a07be Compare April 21, 2026 08:44
search5 added 5 commits April 22, 2026 16:56
- Add cubrid/ package: SQL builder dialect for CUBRID 11.x
  - SELECT, INSERT, UPDATE, DELETE, REPLACE INTO, MERGE INTO
  - Hierarchical queries (START WITH, CONNECT BY, PRIOR, LEVEL)
  - CUBRID-specific functions, CAST, INTERVAL, LOCK/UNLOCK
- Add generator/cubrid/ package: code generator for CUBRID schema
  - Table/view metadata extraction, column type mapping
  - DSN parsing, Pool/HA connection support
  - Integration tests against CUBRID 11.4
- Add internal/jet/cast.go: shared CAST expression implementation
- Add internal/jet/clause_cubrid.go: CUBRID-specific SQL clauses
  (START WITH, CONNECT BY, ORDER SIBLINGS BY, MERGE, REPLACE INTO)
- Update generator/template/: add CUBRID type mappings
  (short, monetary, string, nchar, clob, set, multiset, etc.)
- Update cmd/jet/main.go: add CUBRID as a supported source
- Update go.mod: add cubrid-go driver dependency
- Remove local replace directive for cubrid-go (use published module)
- Update cubrid-go to latest version with Pool/HA support
- Restore go directive to 1.24.0 to match CI toolchain
v0.1.0 declared a non-existent go 1.26.1 directive which broke
builds on Go 1.24.x. v0.1.1 fixes this by lowering to go 1.22.
The codecov check on PR go-jet#575 reported 53.41% patch coverage (164 lines
missing), failing the 90% target. This commit addresses the gap with
comprehensive unit tests and CI integration test support.

Unit test additions (cubrid/ package, 78.6% -> 94.5%):

  - select_statement: WINDOW clause, AsTable subquery, ORDER BY with
    NULLS FIRST/LAST, PRECEDING/FOLLOWING window frame offsets
  - set_statement: INTERSECT_ALL, EXCEPT_ALL (both function and method
    forms), ORDER_BY/LIMIT/OFFSET chaining, AsTable on set results
  - insert_statement: MODELS batch insert
  - replace_statement: MODELS batch replace
  - update_statement: SET with column assignment expressions
  - with_statement: WITH, WITH_RECURSIVE, CTE ALIAS (new file)
  - lateral: LATERAL derived table with AS alias (new file)
  - values: VALUES table constructor with AS alias (new file)
  - statement: RawStatement (new file)
  - functions: LPAD, RPAD, CURRENT_TIME, CURRENT_TIMESTAMP, NOW
  - cubrid_functions: TIMEDIFF, CURRENT_USER_, DRANDOM with seed,
    TO_DATETIME with format, TO_TIMESTAMP with format
  - dialect: argumentToString for []byte, float division (/ operator)
  - interval_literal: INTERVALd(0), unitType.String(), intervalDebugString

Unit test additions (internal/jet/, CUBRID files -> 100%):

  - clause_cubrid: full serialization tests for all CUBRID-specific
    clauses with actual data (StartWith, ConnectBy, ConnectBy NOCYCLE,
    OrderSiblingsBy, MergeInto, MergeUsing, MergeOn, WhenMatched
    UPDATE/DELETE, WhenNotMatched INSERT, ReplaceInto with/without
    columns, GetColumns). Also covers all lowercase serialize() wrappers.
  - cast: CAST expression with dialect operator override path

CircleCI configuration (.circleci/config.yml):

  - Add cubrid/cubrid:11.4 Docker service (port 33000, DB: cubdb)
  - Add wait-for-CUBRID step (up to 60s with 2s interval)
  - Add cubrid/... to -coverpkg list in main test run
  - Add CUBRID integration test step running generator/cubrid/... tests
    with -tags integration and CUBRID_DSN env var
  - Merge CUBRID coverage profile into main cover.out before codecov
    upload
- Remove cubridREGEXPLIKEoperator/cubridNOTREGEXPLIKEoperator from dialect.go:
  these operator overrides were never invoked because REGEXP_LIKE uses the
  dialect's RegexpLike() method path, not the binary operator override path.
  The default fallback in dialectImpl.RegexpLike() already outputs correct CUBRID SQL.
- Add UPDATE and SHARE RowLock constants to select_statement.go
- Add TestSelectFOR covering SELECT ... FOR UPDATE/SHARE
- Add TestSelectPRECEDING_FOLLOWING_UNBOUNDED covering toJetFrameOffset UNBOUNDED branch

cubrid package unit test coverage: 94.3% → 97.7%
search5 added 5 commits April 22, 2026 17:23
Add tests covering previously uncovered code paths:
- dialect.go: ValuesDefaultColumnName, JsonValueEncode lambdas
- dialect.go: TRUNC function
- insert_statement.go: ON DUPLICATE KEY UPDATE with multiple assignments
- select_statement.go: WINDOW().AS() with no arguments, VALUES with default column names
- interval_literal.go: INTERVALd hours+microseconds branch
- generator/template/process.go: insertedRowAlias CUBRID branch

cubrid package unit test coverage: 97.7% → 99.3%
- column_types_test.go: add DEC, CHARACTER, UTIME, VARBIT, LIST, DATETIMELTZ,
  TIMESTAMPLTZ, CHARACTER VARYING, and default-branch cases
- error_path_test.go: unit tests for GenerateDSN (missing DB name),
  GeneratePool (empty DSN), GenerateHA (invalid DSN), Generate (connection
  refused) — covers all generator function error paths without requiring a DB
- query_set_test.go: mock SQL driver tests for GetTablesMetaData (list error,
  view error, column error via partial mock), GetEnumsMetaData (nil return),
  getColumnMetaData (list columns error)

Unit-test-only coverage: generator/cubrid 31.9% → 66.4%
Remaining success-path lines are covered by the existing integration tests
error_path_test.go:
- TestGenerateDSN_ConnectionRefused: covers openConnection error in GenerateDSN
- TestGenerateDB_SchemaError: covers metadata.GetSchema error path in GenerateDB
- TestGenerateDB_ProcessSchemaError: covers template.ProcessSchema error path using
  schemaDriver (returns one mock table) + /dev/null as destDir to force fs error
- Added schemaDriver and emptyDriver mock SQL drivers

query_set_test.go:
- TestGetColumnMetaData_Success: covers pkSet + columns construction loops using
  colsPksDriver (returns one column + one PK)
- TestGetColumnMetaData_PKsError: covers ListPrimaryKeys error path using pksErrDriver

Coverage summary (unit tests only):
- generator/cubrid/query_set.go: 0% → 100%
- generator/cubrid/cubrid_generator.go: 31.9% → 89.4%
  (remaining ~10% are success paths covered by integration tests)
Refactor cubrid_generator.go to inject dependencies via package-level variables:
- sqlOpen: replaces sql.Open("cubrid", ...) in openConnection
- newPool: replaces cubriddriver.NewPool
- newHACluster: replaces cubriddriver.NewHACluster
- poolProvider/haProvider interfaces allow mock implementations in tests

New tests in error_path_test.go:
- TestOpenConnection_Success: success path via sqlOpen mock
- TestOpenConnection_SqlOpenError: sqlOpen failure path
- TestGenerate_Success / TestGenerateDSN_Success: full happy paths
- TestGeneratePool_Success / TestGenerateHA_Success: via mockPool/mockHA
- TestGenerateDB_CustomTemplate: covers len(templates)>0 branch

generator/cubrid unit coverage: 89.4% → 100%
Tests call the SerializerFunc returned by each operator with 0 arguments,
triggering the len(expressions) < 2 panic guard.

cubrid/dialect.go unit coverage: 93.18% → 100%
@search5
Copy link
Copy Markdown
Author

search5 commented Apr 27, 2026

Hi @go-jet! 👋 Friendly ping — this PR adds first-class CUBRID dialect support. CUBRID is widely used in Korean public-sector and enterprise environments, and this would make go-jet the first type-safe SQL builder for Go to support it natively.

All tests pass (including integration tests against CUBRID 11.4), coverage improved from 92.22% to 93.18%, and existing dialects are completely untouched.

Would love to get your feedback whenever you have a moment. Thank you!

@go-jet
Copy link
Copy Markdown
Owner

go-jet commented May 3, 2026

Thanks, @search5, for the contribution. CUBRID looks like an interesting database, and I
appreciate the effort that went into adding support for it.

That said, I do not currently plan to add support for new dialects in Jet. Due
to time constraints, I would prefer to focus on maintaining and improving the
existing dialects rather than expanding the supported database dialects.

CUBRID also still seems to be a fairly niche database, so adding and maintaining
first-class support for it would likely increase the long-term maintenance
burden more than I can commit to right now. Also given the recent increase in supply-chain attacks,
I need to be especially careful about adding new third-party libraries, since search5/cubrid-go appears
to be relatively new.

For these reasons, I do not think this is something I can review/merge at the moment,
but I can leave this PR open, so if someone else needs CUBRID support can use it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants