Search in sources :

Example 86 with SchemaBuilder

use of org.apache.kafka.connect.data.SchemaBuilder in project debezium by debezium.

the class ByLogicalTableRouter method updateKeySchema.

private Schema updateKeySchema(Schema oldKeySchema, String newTopicName) {
    Schema newKeySchema = keySchemaUpdateCache.get(oldKeySchema);
    if (newKeySchema != null) {
        return newKeySchema;
    }
    final SchemaBuilder builder = copySchemaExcludingName(oldKeySchema, SchemaBuilder.struct());
    builder.name(schemaNameAdjuster.adjust(newTopicName + ".Key"));
    // Now that multiple physical tables can share a topic, the event's key may need to be augmented to include
    // fields other than just those for the record's primary/unique key, since these are not guaranteed to be unique
    // across tables. We need some identifier added to the key that distinguishes the different physical tables.
    builder.field(keyFieldName, Schema.STRING_SCHEMA);
    newKeySchema = builder.build();
    keySchemaUpdateCache.put(oldKeySchema, newKeySchema);
    return newKeySchema;
}
Also used : Schema(org.apache.kafka.connect.data.Schema) SchemaBuilder(org.apache.kafka.connect.data.SchemaBuilder)

Example 87 with SchemaBuilder

use of org.apache.kafka.connect.data.SchemaBuilder in project debezium by debezium.

the class ByLogicalTableRouter method updateEnvelopeSchema.

private Schema updateEnvelopeSchema(Schema oldEnvelopeSchema, String newTopicName) {
    Schema newEnvelopeSchema = envelopeSchemaUpdateCache.get(oldEnvelopeSchema);
    if (newEnvelopeSchema != null) {
        return newEnvelopeSchema;
    }
    final Schema oldValueSchema = oldEnvelopeSchema.field(Envelope.FieldName.BEFORE).schema();
    final SchemaBuilder valueBuilder = copySchemaExcludingName(oldValueSchema, SchemaBuilder.struct());
    valueBuilder.name(schemaNameAdjuster.adjust(newTopicName + ".Value"));
    final Schema newValueSchema = valueBuilder.build();
    final SchemaBuilder envelopeBuilder = copySchemaExcludingName(oldEnvelopeSchema, SchemaBuilder.struct(), false);
    for (org.apache.kafka.connect.data.Field field : oldEnvelopeSchema.fields()) {
        final String fieldName = field.name();
        Schema fieldSchema = field.schema();
        if (Objects.equals(fieldName, Envelope.FieldName.BEFORE) || Objects.equals(fieldName, Envelope.FieldName.AFTER)) {
            fieldSchema = newValueSchema;
        }
        envelopeBuilder.field(fieldName, fieldSchema);
    }
    envelopeBuilder.name(schemaNameAdjuster.adjust(newTopicName + ".Envelope"));
    newEnvelopeSchema = envelopeBuilder.build();
    envelopeSchemaUpdateCache.put(oldEnvelopeSchema, newEnvelopeSchema);
    return newEnvelopeSchema;
}
Also used : Schema(org.apache.kafka.connect.data.Schema) SchemaBuilder(org.apache.kafka.connect.data.SchemaBuilder)

Example 88 with SchemaBuilder

use of org.apache.kafka.connect.data.SchemaBuilder in project debezium by debezium.

the class TableSchemaBuilder method create.

/**
 * Create a {@link TableSchema} from the given {@link Table table definition}. The resulting TableSchema will have a
 * {@link TableSchema#keySchema() key schema} that contains all of the columns that make up the table's primary key,
 * and a {@link TableSchema#valueSchema() value schema} that contains only those columns that are not in the table's primary
 * key.
 * <p>
 * This is equivalent to calling {@code create(table,false)}.
 *
 * @param schemaPrefix the prefix added to the table identifier to construct the schema names; may be null if there is no
 *            prefix
 * @param envelopSchemaName the name of the schema of the built table's envelope
 * @param table the table definition; may not be null
 * @param filter the filter that specifies whether columns in the table should be included; may be null if all columns
 *            are to be included
 * @param mappers the mapping functions for columns; may be null if none of the columns are to be mapped to different values
 * @return the table schema that can be used for sending rows of data for this table to Kafka Connect; never null
 */
public TableSchema create(String schemaPrefix, String envelopSchemaName, Table table, Predicate<ColumnId> filter, ColumnMappers mappers) {
    if (schemaPrefix == null)
        schemaPrefix = "";
    // Build the schemas ...
    final TableId tableId = table.id();
    final String tableIdStr = tableId.toString();
    final String schemaNamePrefix = schemaPrefix + tableIdStr;
    LOGGER.debug("Mapping table '{}' to schemas under '{}'", tableId, schemaNamePrefix);
    SchemaBuilder valSchemaBuilder = SchemaBuilder.struct().name(schemaNameAdjuster.adjust(schemaNamePrefix + ".Value"));
    SchemaBuilder keySchemaBuilder = SchemaBuilder.struct().name(schemaNameAdjuster.adjust(schemaNamePrefix + ".Key"));
    AtomicBoolean hasPrimaryKey = new AtomicBoolean(false);
    table.columns().forEach(column -> {
        if (table.isPrimaryKeyColumn(column.name())) {
            // The column is part of the primary key, so ALWAYS add it to the PK schema ...
            addField(keySchemaBuilder, column, null);
            hasPrimaryKey.set(true);
        }
        if (filter == null || filter.test(new ColumnId(tableId, column.name()))) {
            // Add the column to the value schema only if the column has not been filtered ...
            ColumnMapper mapper = mappers == null ? null : mappers.mapperFor(tableId, column);
            addField(valSchemaBuilder, column, mapper);
        }
    });
    Schema valSchema = valSchemaBuilder.optional().build();
    Schema keySchema = hasPrimaryKey.get() ? keySchemaBuilder.build() : null;
    if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Mapped primary key for table '{}' to schema: {}", tableId, SchemaUtil.asDetailedString(keySchema));
        LOGGER.debug("Mapped columns for table '{}' to schema: {}", tableId, SchemaUtil.asDetailedString(valSchema));
    }
    Envelope envelope = Envelope.defineSchema().withName(schemaNameAdjuster.adjust(envelopSchemaName)).withRecord(valSchema).withSource(sourceInfoSchema).build();
    // Create the generators ...
    Function<Object[], Object> keyGenerator = createKeyGenerator(keySchema, tableId, table.primaryKeyColumns());
    Function<Object[], Struct> valueGenerator = createValueGenerator(valSchema, tableId, table.columns(), filter, mappers);
    // And the table schema ...
    return new TableSchema(keySchema, keyGenerator, envelope, valSchema, valueGenerator);
}
Also used : Schema(org.apache.kafka.connect.data.Schema) Envelope(io.debezium.data.Envelope) Struct(org.apache.kafka.connect.data.Struct) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) SchemaBuilder(org.apache.kafka.connect.data.SchemaBuilder) ColumnMapper(io.debezium.relational.mapping.ColumnMapper)

Aggregations

SchemaBuilder (org.apache.kafka.connect.data.SchemaBuilder)88 Schema (org.apache.kafka.connect.data.Schema)40 Test (org.junit.Test)40 Struct (org.apache.kafka.connect.data.Struct)23 Field (org.apache.kafka.connect.data.Field)13 SourceRecord (org.apache.kafka.connect.source.SourceRecord)13 Test (org.junit.jupiter.api.Test)9 ConnectSchema (org.apache.kafka.connect.data.ConnectSchema)6 BigDecimal (java.math.BigDecimal)5 Date (java.util.Date)5 Requirements.requireStruct (org.apache.kafka.connect.transforms.util.Requirements.requireStruct)5 ArrayList (java.util.ArrayList)4 HashMap (java.util.HashMap)4 DataException (org.apache.kafka.connect.errors.DataException)4 KsqlStream (io.confluent.ksql.metastore.KsqlStream)3 KsqlTopic (io.confluent.ksql.metastore.KsqlTopic)3 Expression (io.confluent.ksql.parser.tree.Expression)3 JsonNode (com.fasterxml.jackson.databind.JsonNode)2 SelectItem (io.confluent.ksql.parser.tree.SelectItem)2 SingleColumn (io.confluent.ksql.parser.tree.SingleColumn)2