use of com.bakdata.quick.common.api.model.KeyValuePair in project quick by bakdata.
the class IngestController method convertIngestData.
/**
* Processes raw input data for ingesting.
*
* <p>
* Two steps are necessary to ingest the raw payload:
* <ul>
* <li> parse it
* <li> check for existing keys if the topic is immutable
* </ul>
*
* <p>
* This method handles both steps and then forwards all non-existing {@link KeyValuePair} to the
* {@link IngestService}.
* Further, it handles merging the error messages. The method returns an error for existing keys as well as possible
* errors in the ingest service.
*
* @param topic the topic to ingest to
* @param payload the raw payload
* @param data the topic information for the topic
* @param <K> the key type of the topic
* @param <V> the value type of the topic
* @return merged completable possibly containing errors from existing keys or the ingest service
*/
private <K, V> Completable convertIngestData(final String topic, final String payload, final QuickTopicData<K, V> data) {
final Single<List<KeyValuePair<K, V>>> list = Single.fromCallable(() -> this.parser.parseInputData(payload, data));
return list.flatMap(pairs -> this.filter.prepareIngest(data, pairs)).flatMapCompletable(pairs -> {
final Completable existingError = createErrorsForExistingKeys(topic, pairs);
final Completable ingest = this.ingestService.sendData(topic, pairs.getDataToIngest());
return Completable.mergeArrayDelayError(existingError, ingest);
});
}
use of com.bakdata.quick.common.api.model.KeyValuePair in project quick by bakdata.
the class IngestParser method parseInputData.
/**
* Parses an object or array of key value pairs into a list.
*
* @param payload the raw key value pairs as json, either a single one or an array
* @param topicData the registry's topicData about the topic
* @param <K> type of the key
* @param <V> type of the value
* @return list of parsed key value pairs
* @throws IOException Jackson JSON error
*/
public <K, V> List<KeyValuePair<K, V>> parseInputData(final String payload, final QuickTopicData<K, V> topicData) throws IOException {
final JsonNode jsonNode;
try (final JsonParser parser = this.objectMapper.getFactory().createParser(payload)) {
jsonNode = parser.readValueAsTree();
if (jsonNode.isObject()) {
return List.of(fromJsonNode(jsonNode, topicData));
}
if (jsonNode.isArray()) {
final List<KeyValuePair<K, V>> pairs = new ArrayList<>();
final Iterator<JsonNode> elements = jsonNode.elements();
while (elements.hasNext()) {
pairs.add(fromJsonNode(elements.next(), topicData));
}
return pairs;
}
throw new BadArgumentException("Expected key-value object or list of key-value objects. Got: " + jsonNode.getNodeType());
}
}
use of com.bakdata.quick.common.api.model.KeyValuePair in project quick by bakdata.
the class IngestParser method fromJsonNode.
/**
* Parses a single key value object.
*
* @param jsonNode node to parse
* @param data the registry's data about the topic
* @param <K> type of the key
* @param <V> type of the value
* @return parsed key value pair
*/
private static <K, V> KeyValuePair<K, V> fromJsonNode(final JsonNode jsonNode, final QuickTopicData<K, V> data) {
final JsonNode key = jsonNode.get("key");
final JsonNode value = jsonNode.get("value");
if (key == null || value == null) {
throw new BadArgumentException(String.format("Could not find 'key' or 'value' fields in: %s", jsonNode));
}
final TypeResolver<K> keyResolver = data.getKeyData().getResolver();
final TypeResolver<V> valueResolver = data.getValueData().getResolver();
return new KeyValuePair<>(parse(keyResolver, key), parse(valueResolver, value));
}
use of com.bakdata.quick.common.api.model.KeyValuePair in project quick by bakdata.
the class IngestController method createErrorsForExistingKeys.
/**
* Converts already existing keys into an error.
*
* @param topic the topic to ingest into
* @param pairs lists of existing and non existing keys respectively
* @return successful completable if there are no existing keys otherwise an error
*/
private static Completable createErrorsForExistingKeys(final String topic, final IngestLists<?, ?> pairs) {
if (pairs.getExistingData().isEmpty()) {
return Completable.complete();
} else {
final String existingKeys = pairs.getExistingData().stream().map(KeyValuePair::getKey).map(Object::toString).collect(Collectors.joining(", "));
final String errorMessage = String.format("The following keys already exist for immutable topic %s: %s", topic, existingKeys);
return Completable.error(new BadArgumentException(errorMessage));
}
}
Aggregations