debezium/dbz#285 add csv connector example to debezium-examples#407
debezium/dbz#285 add csv connector example to debezium-examples#407yuanglili wants to merge 2 commits into
Conversation
Signed-off-by: nonononoonononon <yuangli971@gmail.com>
Signed-off-by: nonononoonononon <yuangli971@gmail.com>
|
@kmos, I created an example based on your debezium-connector-csv and it works as expected. I'm also thinking about whether it would be helpful to add diagrams showing the relationships between the key components, or a simple UI for performing insert/update/delete operations to make it more intuitive. Let me know if there's anything that needs to be changed! |
|
@yuanglili I’m a big supporter of diagrams and visualization. I totally agree. |
Naros
left a comment
There was a problem hiding this comment.
Hi @yuanglili, great work. I've left some inline comments to bring the PR more in line with how most Debezium connectors are structured, for those who may use this as a skeleton for future connectors.
Btw, I noticed the PR uses Debezium 3.0.8, which is very old. Could we move this up to Debezium 3.5 by any chance?
|
|
||
| @Override | ||
| public String getContextName() { | ||
| return "CSV"; |
There was a problem hiding this comment.
Let's add a Module class like other connectors and replace the hard-coded values here for context and connector to refer to the Module class.
| } | ||
|
|
||
| @Override | ||
| protected SourceInfoStructMaker<?> getSourceInfoStructMaker(Version version) { |
There was a problem hiding this comment.
Is there a reason for not delegating CommonConnectorConfig#getSourceInfoStructMaker like other connectors? If there is, we should document the reason.
|
|
||
| @Override | ||
| public String version() { | ||
| return "1.0"; |
| * {@link #doStop} is a no-op; | ||
| * the coordinator manages its own shutdown. | ||
| */ | ||
| public class CsvConnectorTask extends BaseSourceTask<CsvPartition, CsvOffsetContext> { |
There was a problem hiding this comment.
I believe we may be missing overrides for getConnectorName and getErrorHandler?
| import io.debezium.connector.base.ChangeEventQueue; | ||
| import io.debezium.pipeline.ErrorHandler; | ||
|
|
||
| public class CsvErrorHandler extends ErrorHandler { |
There was a problem hiding this comment.
We probably should include some class-level Java docs.
| Schema keySchema = collectionSchema.keySchema(); | ||
| Schema valueSchema = collectionSchema.getEnvelopeSchema().schema() | ||
| .field("after").schema(); | ||
|
|
||
| ColumnDef keyCol = cols.get(0); | ||
| Struct keyStruct = new Struct(keySchema) | ||
| .put(keyCol.name(), convertValue(parts[1], keyCol.type())); | ||
|
|
||
| Struct valueStruct = new Struct(valueSchema); | ||
| for (int i = 0; i < cols.size(); i++) { | ||
| ColumnDef col = cols.get(i); | ||
| String rawValue = (i + 1 < parts.length) ? parts[i + 1] : null; | ||
| valueStruct.put(col.name(), rawValue == null ? null : convertValue(rawValue, col.type())); | ||
| } |
There was a problem hiding this comment.
Could we move this logic into the emitter class? In practice, we often centralize this in the emitter because it's shared logic that you'll need for snapshot and streaming, and you reuse the emitter in both contexts.
| * handover line. The fine-grained snapshot/skip decision is made in | ||
| * {@link CsvSnapshotChangeEventSource#getSnapshottingTask} via the line-number offset. | ||
| */ | ||
| class CsvSnapshotter implements Snapshotter { |
There was a problem hiding this comment.
Any reason we could not just use the existing InitialSnapshotter from debezium-connector-common?
|
|
||
| @Override | ||
| public String version() { | ||
| return "1.0"; |
There was a problem hiding this comment.
Another Module.version() reference opportunity.
| @Override | ||
| public <T extends DataCollectionId> List<T> getMatchingCollections(Configuration configuration) { | ||
| return List.of(); | ||
| } |
There was a problem hiding this comment.
I believe this has since been removed, depending on the version of Debezium this is based.
| org.apache.kafka.connect.data.Schema keySchema = collectionSchema.keySchema(); | ||
| org.apache.kafka.connect.data.Schema valueSchema = collectionSchema.getEnvelopeSchema().schema() | ||
| .field("after").schema(); | ||
|
|
||
| ColumnDef keyCol = cols.get(0); | ||
| org.apache.kafka.connect.data.Struct keyStruct = | ||
| new org.apache.kafka.connect.data.Struct(keySchema) | ||
| .put(keyCol.name(), CsvSnapshotChangeEventSource.convertValue(parts[1], keyCol.type())); | ||
|
|
||
| org.apache.kafka.connect.data.Struct valueStruct = | ||
| new org.apache.kafka.connect.data.Struct(valueSchema); | ||
| for (int i = 0; i < cols.size(); i++) { | ||
| ColumnDef col = cols.get(i); | ||
| String rawValue = (i + 1 < parts.length) ? parts[i + 1] : null; | ||
| valueStruct.put(col.name(), | ||
| rawValue == null ? null : CsvSnapshotChangeEventSource.convertValue(rawValue, col.type())); | ||
| } |
There was a problem hiding this comment.
This is the shared logic I mentioned that we can move into the emitter.
|
I wonder if it would be possible to extend |
Sure, I'll switch it to Debezium 3.5 |
I totally agree. I’m working on a more detailed version of the section right now. I’ll first address the current review comments and then submit an updated version. |
Description
This PR adds a CSV file-based connector example to debezium-examples
It demonstrates the key concepts of building a Debezium connector including:
Checklist