Search in sources :

Example 76 with Field

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

the class KeyValueStore method sourceFor.

protected static Struct sourceFor(SourceRecord record) {
    Struct envelope = (Struct) record.value();
    Field field = envelope.schema().field(Envelope.FieldName.SOURCE);
    if (field != null) {
        return envelope.getStruct(field.name());
    }
    return null;
}
Also used : Field(org.apache.kafka.connect.data.Field) Struct(org.apache.kafka.connect.data.Struct)

Example 77 with Field

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

the class KeyValueStore method valueFor.

protected static Struct valueFor(SourceRecord record) {
    Struct envelope = (Struct) record.value();
    Field afterField = envelope.schema().field(Envelope.FieldName.AFTER);
    if (afterField != null) {
        return envelope.getStruct(afterField.name());
    }
    return null;
}
Also used : Field(org.apache.kafka.connect.data.Field) Struct(org.apache.kafka.connect.data.Struct)

Example 78 with Field

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

the class VerifyRecord method assertEquals.

@SuppressWarnings("unchecked")
protected static void assertEquals(Schema schema, Object o1, Object o2, String keyOrValue, String field, Predicate<String> ignoreFields, Map<String, RecordValueComparator> comparatorsByName, Map<String, RecordValueComparator> comparatorsBySchemaName) {
    if (o1 == o2)
        return;
    if (o1 == null) {
        if (o2 == null)
            return;
        fail(nameOf(keyOrValue, field) + " was null but expected " + SchemaUtil.asString(o2));
    } else if (o2 == null) {
        fail("expecting a null " + nameOf(keyOrValue, field) + " but found " + SchemaUtil.asString(o1));
    }
    // See if there is a custom comparator for this field ...
    String pathToField = keyOrValue.toUpperCase() + "/" + field;
    RecordValueComparator comparator = comparatorsByName.get(pathToField);
    if (comparator != null) {
        comparator.assertEquals(nameOf(keyOrValue, field), o1, o2);
        return;
    }
    // See if there is a custom comparator for this schema type ...
    String schemaName = schemaName(schema);
    if (schemaName != null) {
        comparator = comparatorsBySchemaName.get(schemaName);
        if (comparator != null) {
            comparator.assertEquals(nameOf(keyOrValue, field), o1, o2);
        }
    }
    if (o1 instanceof ByteBuffer) {
        o1 = ((ByteBuffer) o1).array();
    }
    if (o2 instanceof ByteBuffer) {
        o2 = ((ByteBuffer) o2).array();
    }
    if (o2 instanceof byte[]) {
        if (!(o1 instanceof byte[])) {
            fail("expecting " + nameOf(keyOrValue, field) + " to be byte[] but found " + o1.getClass().toString());
        }
        if (!Arrays.equals((byte[]) o1, (byte[]) o2)) {
            fail("byte[] at " + nameOf(keyOrValue, field) + " is " + o1 + " but was expected to be " + o2);
        }
    } else if (o2 instanceof Object[]) {
        if (!(o1 instanceof Object[])) {
            fail("expecting " + nameOf(keyOrValue, field) + " to be Object[] but was " + o1.getClass().toString());
        }
        if (!deepEquals((Object[]) o1, (Object[]) o2)) {
            fail("Object[] at " + nameOf(keyOrValue, field) + " is " + o1 + " but was expected to be " + o2);
        }
    } else if (o2 instanceof Map) {
        if (!(o1 instanceof Map)) {
            fail("expecting " + nameOf(keyOrValue, field) + " to be Map<String,?> but was " + o1.getClass().toString());
        }
        Map<String, Object> m1 = (Map<String, Object>) o1;
        Map<String, Object> m2 = (Map<String, Object>) o2;
        if (!m1.keySet().equals(m2.keySet())) {
            fail("Map at " + nameOf(keyOrValue, field) + " has entry keys " + m1.keySet() + " but expected " + m2.keySet());
        }
        for (Map.Entry<String, Object> entry : m1.entrySet()) {
            String key = entry.getKey();
            String fieldName = field.isEmpty() ? key : field + "/" + key;
            String predicate = keyOrValue.toUpperCase() + "/" + fieldName;
            if (ignoreFields != null && ignoreFields.test(predicate)) {
                continue;
            }
            Object v1 = entry.getValue();
            Object v2 = m2.get(key);
            assertEquals(null, v1, v2, keyOrValue, fieldName(field, key), ignoreFields, comparatorsByName, comparatorsBySchemaName);
        }
    } else if (o2 instanceof Collection) {
        if (!(o1 instanceof Collection)) {
            fail("expecting " + nameOf(keyOrValue, field) + " to be Collection<?> but was " + o1.getClass().toString());
        }
        Collection<Object> m1 = (Collection<Object>) o1;
        Collection<Object> m2 = (Collection<Object>) o2;
        if (m1.size() != m2.size()) {
            fail("Collection at " + nameOf(keyOrValue, field) + " has " + SchemaUtil.asString(m1) + " but expected " + SchemaUtil.asString(m2));
        }
        Iterator<?> iter1 = m1.iterator();
        Iterator<?> iter2 = m2.iterator();
        int index = 0;
        while (iter1.hasNext() && iter2.hasNext()) {
            assertEquals(null, iter1.next(), iter2.next(), keyOrValue, field + "[" + (index++) + "]", ignoreFields, comparatorsByName, comparatorsBySchemaName);
        }
    } else if (o2 instanceof Struct) {
        if (!(o1 instanceof Struct)) {
            fail("expecting " + nameOf(keyOrValue, field) + " to be Struct but was " + o1.getClass().toString());
        }
        // Unfortunately, the Struct.equals() method has a bug in that it is not using Arrays.deepEquals(...) to
        // compare values in two Struct objects. The result is that the equals only works if the values of the
        // first level Struct are non arrays; otherwise, the array values are compared using == and that obviously
        // does not work for non-primitive values.
        Struct struct1 = (Struct) o1;
        Struct struct2 = (Struct) o2;
        if (!Objects.equals(struct1.schema(), struct2.schema())) {
            fail("Schema at " + nameOf(keyOrValue, field) + " is " + SchemaUtil.asString(struct1.schema()) + " but expected " + SchemaUtil.asString(struct2.schema()));
        }
        for (Field f : struct1.schema().fields()) {
            String fieldName = fieldName(field, f.name());
            String predicate = keyOrValue.toUpperCase() + "/" + fieldName;
            if (ignoreFields != null && ignoreFields.test(predicate)) {
                continue;
            }
            Object value1 = struct1.get(f);
            Object value2 = struct2.get(f);
            assertEquals(f.schema(), value1, value2, keyOrValue, fieldName, ignoreFields, comparatorsByName, comparatorsBySchemaName);
        }
        return;
    } else if (o2 instanceof Double || o2 instanceof Float || o2 instanceof BigDecimal) {
        // Value should be within 1%
        double expectedNumericValue = ((Number) o2).doubleValue();
        double actualNumericValue = ((Number) o1).doubleValue();
        String desc = "found " + nameOf(keyOrValue, field) + " is " + o1 + " but expected " + o2;
        assertThat(actualNumericValue).as(desc).isEqualTo(expectedNumericValue, Delta.delta(0.01d * expectedNumericValue));
    } else if (o2 instanceof Integer || o2 instanceof Long || o2 instanceof Short) {
        long expectedNumericValue = ((Number) o2).longValue();
        long actualNumericValue = ((Number) o1).longValue();
        String desc = "found " + nameOf(keyOrValue, field) + " is " + o1 + " but expected " + o2;
        assertThat(actualNumericValue).as(desc).isEqualTo(expectedNumericValue);
    } else if (o2 instanceof Boolean) {
        boolean expectedValue = ((Boolean) o2).booleanValue();
        boolean actualValue = ((Boolean) o1).booleanValue();
        String desc = "found " + nameOf(keyOrValue, field) + " is " + o1 + " but expected " + o2;
        assertThat(actualValue).as(desc).isEqualTo(expectedValue);
    } else if (ZonedTimestamp.SCHEMA_NAME.equals(schemaName)) {
        // the actual value (produced by the connectors) should always be properly formatted
        String actualValueString = o1.toString();
        ZonedDateTime actualValue = ZonedDateTime.parse(o1.toString(), ZonedTimestamp.FORMATTER);
        String expectedValueString = o2.toString();
        ZonedDateTime expectedValue;
        try {
            // first try a standard offset format which contains the TZ information
            expectedValue = ZonedDateTime.parse(expectedValueString, ZonedTimestamp.FORMATTER);
        } catch (DateTimeParseException e) {
            // then try a local format using the system default offset
            LocalDateTime localDateTime = LocalDateTime.parse(expectedValueString);
            expectedValue = ZonedDateTime.of(localDateTime, ZoneId.systemDefault());
        }
        assertThat(actualValue.toInstant()).as(actualValueString).isEqualTo(expectedValue.toInstant()).as(expectedValueString);
    } else {
        assertThat(o1).isEqualTo(o2);
    }
}
Also used : LocalDateTime(java.time.LocalDateTime) ByteBuffer(java.nio.ByteBuffer) BigDecimal(java.math.BigDecimal) Struct(org.apache.kafka.connect.data.Struct) Field(org.apache.kafka.connect.data.Field) DateTimeParseException(java.time.format.DateTimeParseException) ZonedDateTime(java.time.ZonedDateTime) Iterator(java.util.Iterator) Collection(java.util.Collection) HashMap(java.util.HashMap) Map(java.util.Map)

Example 79 with Field

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

the class TableSchemaBuilder method createKeyGenerator.

/**
 * Creates the function that produces a Kafka Connect key object for a row of data.
 *
 * @param schema the Kafka Connect schema for the key; may be null if there is no known schema, in which case the generator
 *            will be null
 * @param columnSetName the name for the set of columns, used in error messages; may not be null
 * @param columns the column definitions for the table that defines the row; may not be null
 * @return the key-generating function, or null if there is no key schema
 */
protected Function<Object[], Object> createKeyGenerator(Schema schema, TableId columnSetName, List<Column> columns) {
    if (schema != null) {
        int[] recordIndexes = indexesForColumns(columns);
        Field[] fields = fieldsForColumns(schema, columns);
        int numFields = recordIndexes.length;
        ValueConverter[] converters = convertersForColumns(schema, columnSetName, columns, null, null);
        return (row) -> {
            Struct result = new Struct(schema);
            for (int i = 0; i != numFields; ++i) {
                Object value = row[recordIndexes[i]];
                ValueConverter converter = converters[i];
                if (converter != null) {
                    value = value == null ? value : converter.convert(value);
                    try {
                        result.put(fields[i], value);
                    } catch (DataException e) {
                        Column col = columns.get(i);
                        LOGGER.error("Failed to properly convert key value for '{}.{}' of type {} for row {}:", columnSetName, col.name(), col.typeName(), row, e);
                    }
                }
            }
            return result;
        };
    }
    return null;
}
Also used : ColumnMapper(io.debezium.relational.mapping.ColumnMapper) DataException(org.apache.kafka.connect.errors.DataException) Logger(org.slf4j.Logger) Field(org.apache.kafka.connect.data.Field) Predicate(java.util.function.Predicate) LoggerFactory(org.slf4j.LoggerFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Function(java.util.function.Function) ThreadSafe(io.debezium.annotation.ThreadSafe) Schema(org.apache.kafka.connect.data.Schema) List(java.util.List) ColumnMappers(io.debezium.relational.mapping.ColumnMappers) Immutable(io.debezium.annotation.Immutable) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Struct(org.apache.kafka.connect.data.Struct) SchemaBuilder(org.apache.kafka.connect.data.SchemaBuilder) SchemaNameAdjuster(io.debezium.util.SchemaNameAdjuster) Types(java.sql.Types) Envelope(io.debezium.data.Envelope) SchemaUtil(io.debezium.data.SchemaUtil) Field(org.apache.kafka.connect.data.Field) DataException(org.apache.kafka.connect.errors.DataException) Struct(org.apache.kafka.connect.data.Struct)

Example 80 with Field

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

the class TableSchemaBuilder method createValueGenerator.

/**
 * Creates the function that produces a Kafka Connect value object for a row of data.
 *
 * @param schema the Kafka Connect schema for the value; may be null if there is no known schema, in which case the generator
 *            will be null
 * @param tableId the table identifier; may not be null
 * @param columns the column definitions for the table that defines the row; 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 value-generating function, or null if there is no value schema
 */
protected Function<Object[], Struct> createValueGenerator(Schema schema, TableId tableId, List<Column> columns, Predicate<ColumnId> filter, ColumnMappers mappers) {
    if (schema != null) {
        int[] recordIndexes = indexesForColumns(columns);
        Field[] fields = fieldsForColumns(schema, columns);
        int numFields = recordIndexes.length;
        ValueConverter[] converters = convertersForColumns(schema, tableId, columns, filter, mappers);
        return (row) -> {
            Struct result = new Struct(schema);
            for (int i = 0; i != numFields; ++i) {
                Object value = row[recordIndexes[i]];
                ValueConverter converter = converters[i];
                if (converter != null) {
                    try {
                        value = converter.convert(value);
                        result.put(fields[i], value);
                    } catch (DataException | IllegalArgumentException e) {
                        Column col = columns.get(i);
                        LOGGER.error("Failed to properly convert data value for '{}.{}' of type {} for row {}:", tableId, col.name(), col.typeName(), row, e);
                    } catch (final Exception e) {
                        Column col = columns.get(i);
                        LOGGER.error("Failed to properly convert data value for '{}.{}' of type {} for row {}:", tableId, col.name(), col.typeName(), row, e);
                    }
                }
            }
            return result;
        };
    }
    return null;
}
Also used : ColumnMapper(io.debezium.relational.mapping.ColumnMapper) DataException(org.apache.kafka.connect.errors.DataException) Logger(org.slf4j.Logger) Field(org.apache.kafka.connect.data.Field) Predicate(java.util.function.Predicate) LoggerFactory(org.slf4j.LoggerFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Function(java.util.function.Function) ThreadSafe(io.debezium.annotation.ThreadSafe) Schema(org.apache.kafka.connect.data.Schema) List(java.util.List) ColumnMappers(io.debezium.relational.mapping.ColumnMappers) Immutable(io.debezium.annotation.Immutable) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Struct(org.apache.kafka.connect.data.Struct) SchemaBuilder(org.apache.kafka.connect.data.SchemaBuilder) SchemaNameAdjuster(io.debezium.util.SchemaNameAdjuster) Types(java.sql.Types) Envelope(io.debezium.data.Envelope) SchemaUtil(io.debezium.data.SchemaUtil) Field(org.apache.kafka.connect.data.Field) DataException(org.apache.kafka.connect.errors.DataException) Struct(org.apache.kafka.connect.data.Struct)

Aggregations

Field (org.apache.kafka.connect.data.Field)82 Struct (org.apache.kafka.connect.data.Struct)38 Schema (org.apache.kafka.connect.data.Schema)33 SchemaBuilder (org.apache.kafka.connect.data.SchemaBuilder)17 DataException (org.apache.kafka.connect.errors.DataException)14 List (java.util.List)12 ArrayList (java.util.ArrayList)11 Requirements.requireStruct (org.apache.kafka.connect.transforms.util.Requirements.requireStruct)11 HashMap (java.util.HashMap)10 Map (java.util.Map)8 Test (org.junit.Test)8 Date (java.util.Date)7 ConnectSchema (org.apache.kafka.connect.data.ConnectSchema)6 KsqlException (io.confluent.ksql.util.KsqlException)5 BigDecimal (java.math.BigDecimal)5 ArrayNode (com.fasterxml.jackson.databind.node.ArrayNode)4 ObjectNode (com.fasterxml.jackson.databind.node.ObjectNode)4 SchemaKStream (io.confluent.ksql.structured.SchemaKStream)4 ByteBuffer (java.nio.ByteBuffer)4 JsonNode (com.fasterxml.jackson.databind.JsonNode)3