Query Framework Migration Guide
This guide is for applications already using the Chenile query framework with MyBatis mapper XML files and query definition JSON files.
Migration Summary
For existing MyBatis/JDBC applications, migration is intentionally backward compatible.
Most applications do not need to change their existing query XML, query JSON, controller usage, request payloads, datasource configuration, or count queries.
The default behavior remains:
- Query execution uses MyBatis.
- Paginated queries execute
<queryId>-count. - Responses include exact
maxRowsandmaxPages. - Existing
query.datasources,query.mapperFiles,query.definitionFiles, andquery.defaultTenantIdproperties continue to work.
Existing MyBatis Applications
Keep the existing configuration shape:
query:
defaultTenantId: tenant1
mapperFiles: classpath*:query/mapper/*.xml
definitionFiles: classpath*:query/mapper/*.json
datasources:
tenant1:
type: com.zaxxer.hikari.HikariDataSource
jdbcUrl: jdbc:h2:mem:demo_tenant1
username: demo
password: password
Do not set query.provider for normal MyBatis/JDBC usage. The framework defaults it to:
query:
provider: mybatis
You also do not need to set query.mybatis.enabled. It defaults to true.
Count Query Behavior
Old behavior remains the default. If a query is marked as paginated, the framework runs:
<queryId>-count
and then runs the main query with pagination.
Example:
{
"id": "Student.getAll",
"name": "students",
"paginated": true
}
The framework expects this mapper id to exist:
Student.getAll-count
No migration is required if this behavior is acceptable.
Optional No-Count Mode
For high-volume list APIs where the count query is expensive, disable count query execution globally:
query:
pagination:
countQueryEnabled: false
When disabled, the framework fetches pageSize + 1 rows, trims the extra row, and uses that extra row to determine whether a next page exists.
Response behavior changes in no-count mode:
{
"maxRows": 0,
"maxPages": 0,
"pagination": {
"countQueryExecuted": false,
"totalCountAvailable": false,
"nextPageAvailable": true
}
}
Use pagination.nextPageAvailable instead of maxPages when count query is disabled.
Response Contract Change
SearchResponse now has an additional nullable field:
private SearchPaginationInfo pagination;
Existing clients can ignore this field. It is mainly useful when query.pagination.countQueryEnabled=false.
When count query is enabled, pagination can remain null and existing maxRows / maxPages behavior is preserved.
Count Result Type
The count query result can now be any Number, not only Integer.
This makes existing count mappers more tolerant of JDBC drivers that return Long for count(*).
No mapper change is required unless your count query returns a non-numeric value.
Provider Extension Migration
The old query framework was tightly coupled to MyBatis execution. The new framework keeps MyBatis as the default but allows applications to provide their own execution provider.
For existing MyBatis/JDBC services, do nothing:
query:
provider: mybatis
or omit query.provider completely.
For a custom backend, register a Spring bean that implements:
org.chenile.query.service.impl.QueryExecutionProvider
Then select it:
query:
provider: document
For a provider that does not use MyBatis at all, disable MyBatis infrastructure:
query:
provider: document
mybatis:
enabled: false
definitionFiles: classpath*:query/definitions/*.json
The query definition JSON is still used for:
- query lookup by external query name
- filter enrichment
- pagination flag
- column metadata
- ACL metadata
- response metadata
The custom provider owns only backend execution, sorting, pagination, and count behavior.
See Query Provider Extension for complete provider examples.
Suggested Migration Steps
- Upgrade the query framework dependency.
- Keep existing MyBatis mapper XML and query definition JSON unchanged.
- Keep existing datasource YAML unchanged.
- Run existing query Cucumber/API tests.
- Add one test for default pagination to confirm
maxRowsandmaxPagesstill match old behavior. - If count queries are expensive, add a separate profile with
query.pagination.countQueryEnabled=false. - In no-count mode, update API clients to use
pagination.nextPageAvailable. - Only create a custom
QueryExecutionProviderif the backend cannot be handled by MyBatis/JDBC configuration.
Quick Compatibility Checklist
- Existing
/q/{queryName}REST endpoint: compatible. - Existing
SearchRequest: compatible. - Existing
SearchResponse: compatible; one nullable field was added. - Existing MyBatis mapper XML: compatible.
- Existing query definition JSON: compatible.
- Existing count query mapper ids: compatible.
- Existing datasource YAML: compatible.
- Existing multi-tenant routing: compatible.
- New provider extension: optional.
- New no-count pagination mode: optional.