public TupleKey[] getTupleKeys(TupleSchema schema) { return Stream.of(names).map(name -> schema.getKey(name, typesByName.get(name))).toArray(TupleKey[]::new); } }
/** * Create a tuple from a map of name/value pairs. * @param values The values to put in the tuple. * @return The created tuple. */ public Tuple make(Map<String, Object> values) { if (values == null) throw new IllegalArgumentException("values must not be null"); checkMatchingKeys(values); Object[] valueArray = new Object[slots.length]; getIndices().forEach(i -> valueArray[i] = values.get(slots[i].getName())); return make(valueArray); }
@Override public boolean equals(Object o) { return this == o || (o instanceof TupleKey && ((TupleKey<?>) o).schema.equals(schema) && ((TupleKey<?>) o).index == index); }
/** * Make a tuple of the supplied values, first validating that they conform to this schema. * @param values The values to put in the Tuple. * @return The created Tuple. */ public Tuple makeWith(Object...values) { return make(values); }
/** * Convert this {@link EventJson} to an {@link Event}, using the supplied {@link EventTypeMatcher} and * {@link ObjectMapper}. * @param typeMatcher The {@link EventTypeMatcher} to use to resolve {@link EventType}s to * {@link com.opencredo.concursus.data.tuples.TupleSchema}s * @param objectMapper The {@link ObjectMapper} to use to deserialise event parameters. * @return The converted {@link Event}, iff the {@link EventTypeMatcher} matches its type. */ public Optional<Event> toEvent(EventTypeMatcher typeMatcher, ObjectMapper objectMapper) { EventType eventType = EventType.of(aggregateType, VersionedName.of(name, version)); BiFunction<JsonNode, Type, Object> deserialiser = makeDeserialiser(objectMapper); return typeMatcher.match(eventType).map(tupleSchema -> eventType.makeEvent( aggregateId, StreamTimestamp.of(streamId, Instant.ofEpochMilli(eventTimestamp)), tupleSchema.deserialise(deserialiser, parameters), characteristics )) .map(event -> processingId.isEmpty() ? event : event.processed(UUID.fromString(processingId)) ); }
/** * Make a tuple of the supplied values, first validating that they conform to this schema. * @param values The values to put in the Tuple. * @return The created Tuple. */ public Tuple make(Object[] values) { if (values == null) throw new IllegalArgumentException("value must not be null"); if (values.length != slots.length) throw new IllegalArgumentException( String.format("Expected %s values, but received %s", slots.length, values.length)); if (!typesMatch(values)) { throw new IllegalArgumentException(describeTypeMismatches(values)); } return new Tuple(this, values); }
private String describeTypeMismatches(Object[] values) { return getIndices() .filter(i -> !slots[i].accepts(values[i])) .mapToObj(i -> String.format("Slot (%s) does not accept value <%s>", slots[i], values[i])) .collect(joining(", ")); }
@Override public String toString() { return schema.format(values); } }
/** * Get the value contained in the slot with the supplied name. * @param name The name of the slot to get the value from. * @return The value stored in that slot. */ public Object get(String name) { if (name == null) throw new IllegalArgumentException("name must not be null"); return schema.get(name, values); }
/** * Create a TupleSchema having the supplied TupleSlots. * @param slots The TupleSlots in the schema. * @return The created TupleSchema. */ public static TupleSchema of(String name, TupleSlot...slots) { if (name == null) throw new IllegalArgumentException("name must not be null"); if (slots == null) throw new IllegalArgumentException("slots must not be null"); Map<String, Integer> slotLookup = IntStream.range(0, slots.length) .collect(HashMap::new, (m, i) -> m.put(slots[i].getName(), i), Map::putAll); if (slots.length != slotLookup.size()) throw new IllegalArgumentException("Slot names are not unique"); return new TupleSchema(name, slots, slotLookup); }
/** * Build a tuple using a map of tuple values constructed by the supplied builders. * @param builders The builders to use to build up a map of tuple values. * @return The created tuple. */ public Tuple make(NamedValue...builders) { Map<String, Object> values = new HashMap<>(); Stream.of(builders).forEach(builder -> builder.accept(values)); return make(values); }
/** * Convert this {@link CommandJson} to an {@link Command}, using the supplied {@link CommandTypeMatcher} and * {@link ObjectMapper}. * @param typeMatcher The {@link CommandTypeMatcher} to use to resolve {@link CommandType}s to * {@link com.opencredo.concursus.domain.commands.CommandTypeInfo}. * @param objectMapper The {@link ObjectMapper} to use to deserialise event parameters. * @return The converted {@link Command}, iff the {@link CommandTypeMatcher} matches its type. */ public Optional<Command> toCommand(CommandTypeMatcher typeMatcher, ObjectMapper objectMapper) { CommandType commandType = getCommandType(); BiFunction<JsonNode, Type, Object> deserialiser = makeDeserialiser(objectMapper); return typeMatcher.match(commandType).map(typeInfo -> commandType.makeCommand( aggregateId, StreamTimestamp.of(streamId, Instant.ofEpochMilli(commandTimestamp)), typeInfo.getTupleSchema().deserialise(deserialiser, parameters), typeInfo.getReturnType() )) .map(command -> processingId.isEmpty() ? command : command.processed(UUID.fromString(processingId)) ); }
String format(Object[] values) { return name + getIndices() .mapToObj(i -> slots[i].getName() + "=" + values[i]) .collect(joining(", ", "{", "}")); }
/** * Create a tuple using the supplied deserialiser, out of a map of serialised values. * @param deserialiser The deserialiser to use to deserialise values from the map. * @param values A map of serialised tuple values. * @param <V> The type to which tuple value have been serialised, e.g. String. * @return The created tuple. */ public <V> Tuple deserialise(BiFunction<V, Type, Object> deserialiser, Map<String, V> values) { if (deserialiser == null) throw new IllegalArgumentException("deserialiser must not be null"); if (values == null) throw new IllegalArgumentException("values must not be null"); checkMatchingKeys(values); Object[] valueArray = new Object[slots.length]; getIndices().forEach(i -> valueArray[i] = slots[i].deserialise(deserialiser, values)); return make(valueArray); }
/** * Get a key which can be used to retrieve a map of values from a tuple in a type-safe way, without having to do an index lookup. * @param name The name of the slot to get a key for. * @param keyType The key class of the map to retrieve with the key. * @param valueType The value class of the map to retrieve with the key. * @param <K> The key type of the value to retrieve with the key. * @param <V> The value type of the value to retrieve with the key. * @return The created key. */ public <K, V> TupleKey<Map<K, V>> getMapKey(String name, Class<K> keyType, Class<V> valueType) { return getKey(name, Types.mapOf(keyType, valueType)); }
private Tuple makeTupleFromArgs(Object[] args) { return tupleSchema.make(IntStream.range(0, tupleKeys.length) .mapToObj(getValueFrom(args)) .toArray(TupleKeyValue[]::new)); }
private void createEvent(Row row, String aggregateType, VersionedName versionedName, TupleSchema tupleSchema) { Map<String, String> parameterData = row.getMap(PARAMETERS, String.class, String.class); Tuple parameters = tupleSchema.deserialise(deserialiser, parameterData); Event event = Event.of( AggregateId.of(aggregateType, row.getString(AGGREGATE_ID)), StreamTimestamp.of(row.getString(STREAM_ID), row.getDate(EVENT_TIMESTAMP).toInstant()), row.getUUID(PROCESSING_ID), versionedName, parameters, row.getInt(CHARACTERISTICS)); eventCollector.accept(event); }
<V> Map<String, V> serialise(Function<Object, V> serialiser, Object[] values) { return getIndices() .collect(LinkedHashMap::new, (m, i) -> m.put(slots[i].getName(), serialiser.apply(values[i])), Map::putAll); }
boolean belongsToSchema(TupleSchema schema) { return this.schema.equals(schema); }
private static Map<Method, TupleKey> getTupleMapUncached(Class pojoClass, TupleSchema mappedSchema) { return Stream.of(safeGetBeanInfo(pojoClass).getPropertyDescriptors()) .collect(Collectors.toMap( PropertyDescriptor::getReadMethod, pd -> mappedSchema.getKey(pd.getName(), pd.getReadMethod().getGenericReturnType()) )); }