Query Provider Extension
Chenile query ships with one production provider: mybatis. This provider is the default and works for JDBC databases when the mapper SQL is compatible with that database.
For JDBC databases where the existing MyBatis mapper SQL is valid, applications should normally only change datasource and mapper configuration:
query:
mapperFiles: classpath*:query/mapper/*.xml
definitionFiles: classpath*:query/mapper/*.json
datasources:
tenant1:
type: com.zaxxer.hikari.HikariDataSource
driverClassName: com.example.Driver
jdbcUrl: jdbc:example://localhost:9000/default
username: app
password: secret
Do not set query.provider for this case. It defaults to mybatis.
When To Add A Provider
Create a custom QueryExecutionProvider only when datasource changes are not enough:
- The database needs different pagination or sorting syntax.
- Query execution is not MyBatis/JDBC.
- The backend is not SQL, for example a document store or search engine.
- The result mapping or count execution is backend-specific.
Custom JDBC Provider
For a JDBC database that still uses MyBatis mappers, extend MybatisQueryExecutionProvider and override only the behavior that differs:
package com.example.query;
import java.util.Map;
import org.chenile.query.service.impl.MybatisQueryExecutionProvider;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WarehouseQueryProviderConfiguration {
@Bean
public MybatisQueryExecutionProvider warehouseQueryExecutionProvider(SqlSessionTemplate sqlSessionTemplate) {
return new WarehouseQueryExecutionProvider(sqlSessionTemplate);
}
static class WarehouseQueryExecutionProvider extends MybatisQueryExecutionProvider {
WarehouseQueryExecutionProvider(SqlSessionTemplate sqlSessionTemplate) {
super(sqlSessionTemplate);
}
@Override
public String getProviderName() {
return "warehouse";
}
@Override
public void applyPagination(Map<String, Object> filters, int startRow, int numRowsInPage) {
filters.put(PAGINATION_PART, "fetch " + numRowsInPage + " skip " + (startRow - 1));
}
}
}
Enable it with:
query:
provider: warehouse
The provider is selected by getProviderName(). Provider names are case-insensitive.
Non-SQL Provider
For a backend that does not use MyBatis, implement QueryExecutionProvider directly:
package com.example.query;
import java.util.List;
import java.util.Map;
import org.chenile.query.model.QueryMetadata;
import org.chenile.query.model.SortCriterion;
import org.chenile.query.service.impl.QueryExecutionProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DocumentQueryProviderConfiguration {
@Bean
public QueryExecutionProvider documentQueryExecutionProvider(DocumentQueryClient client) {
return new DocumentQueryExecutionProvider(client);
}
static class DocumentQueryExecutionProvider implements QueryExecutionProvider {
private final DocumentQueryClient client;
DocumentQueryExecutionProvider(DocumentQueryClient client) {
this.client = client;
}
@Override
public String getProviderName() {
return "document";
}
@Override
public void applySort(Map<String, Object> filters, List<SortCriterion> sortCriteria,
QueryMetadata queryMetadata) {
filters.put("sortCriteria", sortCriteria);
}
@Override
public void applyPagination(Map<String, Object> filters, int startRow, int numRowsInPage) {
filters.put("startRow", startRow);
filters.put("numRowsInPage", numRowsInPage);
}
@Override
public Object executeCount(String queryName, Map<String, Object> filters) {
return client.count(queryName, filters);
}
@Override
public List<Object> executeQuery(String queryName, Map<String, Object> filters) {
return client.search(queryName, filters);
}
}
}
For a non-MyBatis provider, disable the framework MyBatis infrastructure:
query:
provider: document
mybatis:
enabled: false
definitionFiles: classpath*:query/definitions/*.json
The query definition JSON is still used for filter enrichment, security metadata, pagination flags, and response metadata. The custom provider owns the actual backend execution.