How to Add Custom Value Processors for Database-Specific Data Types in Chat2DB
To add custom value processors in Chat2DB, implement the IValueProcessor interface (or extend DefaultValueProcessor), override the conversion methods for your specific data type, and register the new processor in the appropriate dialect factory such as MysqlValueProcessorFactory or PostgreSQLValueProcessorFactory.
Chat2DB renders query results and generates DML statements using a pluggable value-processing framework that isolates database-specific logic per dialect. By implementing custom value processors, you can extend support for vendor-specific types like PostgreSQL's JSONB or MySQL's GEOMETRY without affecting other database modules. This guide walks through the exact implementation steps using the Chat2DB source code structure.
Understanding the Value Processing Framework
The core contract for value processing is defined in IValueProcessor located in the SPI module. Each database dialect provides its own implementation of this interface to handle type-specific conversions.
A value processor has four responsibilities:
getSqlValueString(SQLDataValue)— Produces a SQL literal that can be embedded directly in INSERT or UPDATE statements.getJdbcValue(JDBCDataValue)— Converts a raw JDBC value into a user-readable string for the UI without additional quoting.getJdbcSqlValueString(JDBCDataValue)— Converts a JDBC value into a SQL literal for reuse in DML operations when copying result-set values.isStringDataType(String)— Indicates whether a column type should be treated as a string, affecting how the SQL builder applies quoting and comparison logic.
Most implementations extend DefaultValueProcessor and override only the necessary methods rather than implementing the full interface.
Step-by-Step Implementation Guide
Create a Custom Processor Class
Create a new class that extends DefaultValueProcessor and resides in your dialect's value package. Override the methods that correspond to how your data type should display in the UI and serialize to SQL.
For example, to handle PostgreSQL's JSONB type:
package ai.chat2db.plugin.postgresql.value.sub;
import ai.chat2db.spi.DefaultValueProcessor;
import ai.chat2db.community.domain.api.model.value.SQLDataValue;
import ai.chat2db.spi.model.value.JDBCDataValue;
/** Processor for PostgreSQL JSONB columns. */
public class PostgresJsonbProcessor extends DefaultValueProcessor {
@Override
public String getSqlValueString(SQLDataValue dataValue) {
// JSONB literals are written as a string with ::jsonb cast
String json = dataValue.getValue().toString().replace("'", "''");
return "'" + json + "'::jsonb";
}
@Override
public String getJdbcValue(JDBCDataValue dataValue) {
// Display the JSON text without additional quoting
return dataValue.getValue().toString();
}
@Override
public boolean isStringDataType(String dataType) {
// Treat JSONB as a string for comparison purposes
return true;
}
}
Register the Processor in the Dialect Factory
Each dialect maintains a factory that maps type names to processor instances. For PostgreSQL, modify PostgreSQLValueProcessorFactory to include your new mapping in the static initialization block.
If the factory uses an immutable map (as seen in the MySQL implementation), add a new entry to the map:
static {
PROCESSOR_MAP = Map.ofEntries(
// ... existing entries ...
Map.entry("JSONB", new PostgresJsonbProcessor())
);
}
For dialects using mutable maps, simply add the entry during static initialization. The framework automatically resolves type names to processors when rendering result sets or generating DML.
Verify the Integration
Once registered, any query returning a column of type JSONB will automatically invoke PostgresJsonbProcessor. The processor handles:
- UI display via
getJdbcValue() - INSERT/UPDATE generation via
getSqlValueString() - Copy-to-clipboard SQL literals via
getJdbcSqlValueString()
No additional code changes are required in the core application.
Key Source Files and Architecture
Understanding the repository structure helps locate the correct extension points:
chat2db-community-server/chat2db-community-spi/src/main/java/ai/chat2db/spi/IValueProcessor.java— Core interface defining the four conversion methods.chat2db-community-server/chat2db-community-spi/src/main/java/ai/chat2db/spi/DefaultValueProcessor.java— Base class providing default implementations.chat2db-community-server/chat2db-community-plugins/chat2db-community-mysql/src/main/java/ai/chat2db/plugin/mysql/value/factory/MysqlValueProcessorFactory.java— MySQL's processor registry.chat2db-community-server/chat2db-community-plugins/chat2db-community-postgresql/src/main/java/ai/chat2db/plugin/postgresql/value/factory/PostgreSQLValueProcessorFactory.java— PostgreSQL's processor registry.
The framework isolates processors per dialect, allowing you to add support for third-party or custom database extensions without impacting other modules.
Summary
- Implement
IValueProcessorby extendingDefaultValueProcessorand overriding specific conversion methods for your data type. - Register the processor in the appropriate dialect factory (e.g.,
PostgreSQLValueProcessorFactory) by mapping the type name to your implementation. - Handle three contexts: SQL literals for DML generation, raw display strings for the UI, and type classification for proper quoting.
- Maintain isolation: Changes to one dialect's value processors do not affect other databases in the Chat2DB ecosystem.
Frequently Asked Questions
What is the difference between getSqlValueString and getJdbcSqlValueString?
Use getSqlValueString(SQLDataValue) when generating SQL from user input or metadata, as it accepts the higher-level SQLDataValue object. Use getJdbcSqlValueString(JDBCDataValue) when converting values retrieved from a JDBC result set back into SQL literals, such as when users copy cell values from query results to reuse in DML statements.
Do I need to implement all four methods of IValueProcessor?
No. Extend DefaultValueProcessor and override only the methods relevant to your data type. The base class provides safe defaults: it returns the string value of the data for display methods and false for isStringDataType. Override only when you need custom serialization or specific string-type handling.
Which Chat2DB module contains the dialect-specific factories?
Dialect factories reside in the plugin modules under chat2db-community-plugins/chat2db-community-[dialect]. For example, MySQL processors are registered in chat2db-community-mysql, while PostgreSQL processors live in chat2db-community-postgresql. Each factory maintains a static map of type names to processor instances.
How does the isStringDataType method affect SQL generation?
When isStringDataType(String) returns true, Chat2DB's SQL builder treats the column as a string type, applying single quotes around literals and using string comparison operators. Returning false indicates numeric or binary handling, which affects quoting behavior in generated INSERT and UPDATE statements.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →