Добавил тесты и стабилизировал сущности. Рефакторинг ValueTransformationChain

This commit is contained in:
kirillius 2026-01-08 09:47:38 +03:00
parent 2d7c7fea9c
commit dcb15ebdc1
35 changed files with 836 additions and 129 deletions

View File

@ -0,0 +1,7 @@
package ru.kirillius.XCP.Commons;
import java.io.Closeable;
public interface Initializable extends Closeable {
void initialize(Context context);
}

View File

@ -1,7 +1,5 @@
package ru.kirillius.XCP.Commons;
import java.io.Closeable;
public interface Service extends Initializable {
public interface Service extends Closeable {
void initialize(Context context);
}

View File

@ -0,0 +1,17 @@
package ru.kirillius.XCP.Data;
import ru.kirillius.XCP.Commons.Initializable;
import ru.kirillius.java.utils.events.EventHandler;
import tools.jackson.databind.node.ObjectNode;
public interface DataAdapter extends Initializable {
Object send(Object value, ObjectNode properties);
Object receive(ObjectNode properties);
EventHandler<Object> subscribe();
void unsubscribe(EventHandler<Object> subscription);
}

View File

@ -1,6 +0,0 @@
package ru.kirillius.XCP.Data;
@Deprecated
public interface DataTransferProtocol {
//TODO
}

View File

@ -1,20 +1,19 @@
package ru.kirillius.XCP.Data;
public interface PollSettings {
int getMaxValueCount();
void setMaxValueCount(int maxValueCount);
long getPollInterval();
void setPollInterval(long pollInterval);
boolean isInterruptIfBusy();
boolean isInterruptable();
void setInterruptIfBusy(boolean interruptIfBusy);
void setInterruptable(boolean interruptable);
boolean setEnabled();
boolean isRateMeasurement();
void setRateMeasurement(boolean rateMeasurement);
void setEnabled(boolean enabled);
boolean isEnabled();
}

View File

@ -1,6 +0,0 @@
package ru.kirillius.XCP.Data;
@Deprecated
public interface ValueModifier {
//TODO
}

View File

@ -1,14 +0,0 @@
package ru.kirillius.XCP.Data;
import tools.jackson.databind.node.ObjectNode;
public interface ValueModifierSettings {
Class<? extends ValueModifier> getModifierClass();
void setModifierClass(Class<? extends ValueModifier> modifierClass);
ObjectNode getParameters();
void setParameters(ObjectNode parameters);
}

View File

@ -0,0 +1,24 @@
package ru.kirillius.XCP.Data;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import tools.jackson.databind.annotation.JsonDeserialize;
import java.util.ArrayList;
import java.util.List;
@NoArgsConstructor
@AllArgsConstructor
public final class ValueTransformationChain {
@Getter
@Setter
@JsonSetter(nulls = Nulls.SKIP)
@JsonProperty
@JsonDeserialize(contentAs = ValueTransformationStep.class)
private List<ValueTransformationStep> steps = new ArrayList<>();
}

View File

@ -0,0 +1,19 @@
package ru.kirillius.XCP.Data;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import tools.jackson.databind.node.ObjectNode;
@NoArgsConstructor
@AllArgsConstructor
public final class ValueTransformationStep {
@Getter
@Setter
private String transformerId;
@Getter
@Setter
ObjectNode configuration;
}

View File

@ -0,0 +1,10 @@
package ru.kirillius.XCP.Data;
import org.javatuples.Pair;
import tools.jackson.databind.node.ObjectNode;
import java.util.function.Function;
public interface ValueTransformer extends Function<Pair<Object, ObjectNode>, Object> {
}

View File

@ -0,0 +1,12 @@
package ru.kirillius.XCP.Data;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ValueTransformerDescriptor {
String transformerId() default "";
}

View File

@ -1,16 +1,14 @@
package ru.kirillius.XCP.Persistence;
import ru.kirillius.XCP.Data.DataTransferProtocol;
import ru.kirillius.XCP.Data.ValueModifierSettings;
import java.util.List;
import ru.kirillius.XCP.Data.ValueTransformationChain;
public interface IOEntity extends NodeEntity {
List<ValueModifierSettings> getModifiers();
ValueTransformationChain getTransformationChain();
void setModifiers(List<ValueModifierSettings> modifiers);
void setTransformationChain(ValueTransformationChain transformationChain);
Class<? extends DataTransferProtocol> getProtocol();
String getAdapterId();
void setAdapterId(String adapterId);
void setProtocol(Class<? extends DataTransferProtocol> protocol);
}

View File

@ -9,5 +9,7 @@ import java.util.Collection;
public interface NodeRepository<E extends NodeEntity> extends Repository<E> {
StreamHandler<E> getByGroup(Group group);
StreamHandler<E> getByTags(Collection<Tag> tags);
StreamHandler<E> getByAllTags(Collection<Tag> tags);
StreamHandler<E> getByAnyTag(Collection<Tag> tags);
}

View File

@ -1,8 +1,8 @@
package ru.kirillius.XCP.Persistence.Repositories;
import ru.kirillius.XCP.Persistence.Entities.Input;
import ru.kirillius.XCP.Persistence.Entities.Output;
import ru.kirillius.XCP.Persistence.NodeRepository;
public interface OutputRepository extends NodeRepository<Input> {
public interface OutputRepository extends NodeRepository<Output> {
}

View File

@ -9,9 +9,11 @@ import java.util.Collection;
import java.util.stream.Stream;
public interface TagRepository extends Repository<Tag> {
Tag getByName(String name);
Tag getByNameOrCreate(String name);
ResourceHandler<Stream<Tag>> getByNames(Collection<String> names);
TagCollection getByNamesOrCreate(Collection<String> names);
TagCollection createCollection();
TagCollection createCollection(ResourceHandler<Stream<Tag>> handler);
}

View File

@ -13,10 +13,6 @@ public class EntityReferenceSerializer extends StdSerializer<EntityReference> {
this.repositoryService = repositoryService;
}
// protected EntityReferenceSerializer(Class<PersistenceEntity> t) {
// super(t);
// }
@Override
public void serialize(EntityReference reference, JsonGenerator gen, SerializationContext provider) throws JacksonException {
var value = reference.get();

View File

@ -8,7 +8,6 @@ import tools.jackson.databind.module.SimpleSerializers;
import java.util.List;
import java.util.Map;
import java.util.Set;
class PersistenceSerializationModule extends JacksonModule {
public PersistenceSerializationModule(RepositoryServiceImpl repositoryService) {
@ -31,12 +30,12 @@ class PersistenceSerializationModule extends JacksonModule {
@Override
public void setupModule(SetupContext context) {
context.addSerializers(new SimpleSerializers(List.of(
new EntityReferenceSerializer(repositoryService)
// new TagSetSerializer(repositoryService)
new EntityReferenceSerializer(repositoryService),
new TagCollectionSerializer()
)));
context.addDeserializers(new SimpleDeserializers(Map.of(
EntityReference.class, new EntityReferenceDeserializer(repositoryService)
// Set.class, new TagSetDeserializer(repositoryService)
EntityReference.class, new EntityReferenceDeserializer(repositoryService),
TagCollection.class, new TagCollectionDeserializer(repositoryService)
)));
}
}

View File

@ -0,0 +1,21 @@
package ru.kirillius.XCP.Persistence;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
import ru.kirillius.XCP.Data.PollSettings;
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class PollSettingsImpl implements PollSettings {
@JsonProperty
private long pollInterval = 300;
@JsonProperty
private boolean interruptable = true;
@JsonProperty
private boolean rateMeasurement = false;
@JsonProperty
private boolean enabled = true;
}

View File

@ -20,22 +20,37 @@ public abstract class AbstractNodeRepository<E extends NodeEntity> extends Abstr
@Override
public StreamHandler<E> getByGroup(Group group) {
return search("WHERE group = ?1", List.of(group));
return search("WHERE parent = ?1", List.of(group));
}
@SuppressWarnings("unchecked")
@Override
public StreamHandler<E> getByTags(Collection<Tag> tags) {
public StreamHandler<E> getByAllTags(Collection<Tag> tags) {
var hql = "SELECT n FROM " + tableName + " n JOIN n.tags t " +
"WHERE t.name IN :tagNames " +
"GROUP BY n " +
"HAVING COUNT(DISTINCT t.name) = :tagCount";
"WHERE t IN :tags " +
"GROUP BY n.id " +
"HAVING COUNT(DISTINCT t.id) = :tagCount";
var session = repositoryService.openSession();
var transaction = session.beginTransaction();
var query = (Query<E>) session.createQuery(hql, entityImplementationClass);
query.setParameter("tagNames", tags);
query.setParameter("tagCount", tags.size());
query.setParameter("tags", tags);
query.setParameter("tagCount", (long) tags.size());
return new ResourceHandlerImpl<>(query, transaction, session);
}
@SuppressWarnings("unchecked")
@Override
public StreamHandler<E> getByAnyTag(Collection<Tag> tags) {
var hql = "SELECT DISTINCT n FROM " + tableName + " n " +
"JOIN n.tags t " +
"WHERE t.name IN :tagNames";
var session = repositoryService.openSession();
var transaction = session.beginTransaction();
var query = (Query<E>) session.createQuery(hql, entityImplementationClass);
query.setParameter("tagNames", tags.stream().map(Tag::getName).toList());
return new ResourceHandlerImpl<>(query, transaction, session);
}
}

View File

@ -6,9 +6,8 @@ import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.UuidGenerator;
import ru.kirillius.XCP.Commons.StreamHandler;
import ru.kirillius.XCP.Persistence.*;
import ru.kirillius.XCP.Persistence.Entities.Group;
import ru.kirillius.XCP.Persistence.Entities.Tag;
import ru.kirillius.XCP.Persistence.*;
import ru.kirillius.XCP.Serialization.SerializationUtils;
import tools.jackson.databind.node.ObjectNode;
@ -145,13 +144,13 @@ public class GroupRepositoryImpl extends AbstractNodeRepository<Group> implement
@Override
public void setTags(Set<Tag> tags) {
public void setTags(TagCollection tags) {
this.tags = tags.stream().map(t -> (TagRepositoryImpl.TagEntity) t).collect(Collectors.toSet());
}
@Override
public Set<Tag> getTags() {
return new HashSet<>(tags);
public TagCollection getTags() {
return new TagCollectionImpl(tags);
}
@Column(nullable = false)

View File

@ -0,0 +1,160 @@
package ru.kirillius.XCP.Persistence.Repositories;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.UuidGenerator;
import ru.kirillius.XCP.Data.PollSettings;
import ru.kirillius.XCP.Data.ValueTransformationChain;
import ru.kirillius.XCP.Persistence.Entities.Group;
import ru.kirillius.XCP.Persistence.Entities.Input;
import ru.kirillius.XCP.Persistence.*;
import ru.kirillius.XCP.Serialization.PollSettingsConverter;
import ru.kirillius.XCP.Serialization.SerializationUtils;
import ru.kirillius.XCP.Serialization.ValueTransformationChainConverter;
import tools.jackson.databind.annotation.JsonDeserialize;
import tools.jackson.databind.node.ObjectNode;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
@EntityImplementation(InputRepositoryImpl.InputEntity.class)
public class InputRepositoryImpl extends AbstractNodeRepository<Input> implements InputRepository {
public InputRepositoryImpl(RepositoryServiceImpl repositoryService) {
super(repositoryService);
}
@Override
public void store(Input entity) {
if (entity != null && entity.getParent() == null) {
throw new IllegalStateException("Saving inputs without group is prohibited");
}
super.store(entity);
}
@Entity
@Table(name = "Inputs")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public static class InputEntity implements Input {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@JsonProperty
private long id = 0;
@JsonProperty
@Column(unique = true, nullable = false)
@UuidGenerator
private UUID uuid;
@Column(nullable = false)
@JsonProperty
private String name = "";
@Column(nullable = false)
@JsonProperty
@Getter
@Setter
private boolean protectedEntity;
@Column(nullable = false)
@JsonProperty
@Getter
@Setter
private boolean enabled;
@ManyToOne(fetch = FetchType.EAGER)
@JsonIgnore
private GroupRepositoryImpl.GroupEntity parent;
@JsonProperty("parent")
EntityReference getParentReference() {
return new EntityReference(getParent());
}
@JsonProperty("parent")
void setParentReference(EntityReference entityReference) {
parent = entityReference == null ? null : (GroupRepositoryImpl.GroupEntity) entityReference.get();
}
public Group getParent() {
return parent;
}
public void setParent(Group parent) {
this.parent = (GroupRepositoryImpl.GroupEntity) parent;
}
@Override
public void setTags(TagCollection tags) {
this.tags = tags.stream().map(t -> (TagRepositoryImpl.TagEntity) t).collect(Collectors.toSet());
}
@Override
public TagCollection getTags() {
return new TagCollectionImpl(tags);
}
@Column(nullable = false)
@JsonProperty
@Getter
@Setter
private ObjectNode properties = SerializationUtils.EmptyObject();
@JsonIgnore
@ManyToMany(fetch = FetchType.EAGER)
private Set<TagRepositoryImpl.TagEntity> tags = new HashSet<>();
@Override
public boolean equals(Object o) {
if (!(o instanceof InputEntity that)) return false;
return Objects.equals(uuid, that.uuid);
}
@Override
public int hashCode() {
return Objects.hashCode(uuid);
}
@Override
public PollSettings getPollSettings() {
return pollSettings;
}
@Override
public void setPollSettings(PollSettings pollSettings) {
this.pollSettings = (PollSettingsImpl) pollSettings;
}
@Column(nullable = false)
@JsonProperty
@Convert(converter = PollSettingsConverter.class)
@JsonDeserialize(as = PollSettingsImpl.class)
private PollSettingsImpl pollSettings = new PollSettingsImpl();
@Column(nullable = false)
@JsonProperty
@Getter
@Setter
private String adapterId = "";
@Getter
@Setter
@JsonProperty
@Convert(converter = ValueTransformationChainConverter.class)
@Column(nullable = false)
private ValueTransformationChain transformationChain = new ValueTransformationChain();
}
}

View File

@ -0,0 +1,141 @@
package ru.kirillius.XCP.Persistence.Repositories;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.UuidGenerator;
import ru.kirillius.XCP.Data.ValueTransformationChain;
import ru.kirillius.XCP.Persistence.Entities.Group;
import ru.kirillius.XCP.Persistence.Entities.Output;
import ru.kirillius.XCP.Persistence.*;
import ru.kirillius.XCP.Serialization.SerializationUtils;
import ru.kirillius.XCP.Serialization.ValueTransformationChainConverter;
import tools.jackson.databind.node.ObjectNode;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
@EntityImplementation(OutputRepositoryImpl.OutputEntity.class)
public class OutputRepositoryImpl extends AbstractNodeRepository<Output> implements OutputRepository {
public OutputRepositoryImpl(RepositoryServiceImpl repositoryService) {
super(repositoryService);
}
@Override
public void store(Output entity) {
if (entity != null && entity.getParent() == null) {
throw new IllegalStateException("Saving outputs without group is prohibited");
}
super.store(entity);
}
@Entity
@Table(name = "Outputs")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public static class OutputEntity implements Output {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@JsonProperty
private long id = 0;
@JsonProperty
@Column(unique = true, nullable = false)
@UuidGenerator
private UUID uuid;
@Column(nullable = false)
@JsonProperty
private String name = "";
@Column(nullable = false)
@JsonProperty
@Getter
@Setter
private boolean protectedEntity;
@Column(nullable = false)
@JsonProperty
@Getter
@Setter
private boolean enabled;
@ManyToOne(fetch = FetchType.EAGER)
@JsonIgnore
private GroupRepositoryImpl.GroupEntity parent;
@JsonProperty("parent")
EntityReference getParentReference() {
return new EntityReference(getParent());
}
@JsonProperty("parent")
void setParentReference(EntityReference entityReference) {
parent = entityReference == null ? null : (GroupRepositoryImpl.GroupEntity) entityReference.get();
}
public Group getParent() {
return parent;
}
public void setParent(Group parent) {
this.parent = (GroupRepositoryImpl.GroupEntity) parent;
}
@Override
public void setTags(TagCollection tags) {
this.tags = tags.stream().map(t -> (TagRepositoryImpl.TagEntity) t).collect(Collectors.toSet());
}
@Override
public TagCollection getTags() {
return new TagCollectionImpl(tags);
}
@Column(nullable = false)
@JsonProperty
@Getter
@Setter
private ObjectNode properties = SerializationUtils.EmptyObject();
@JsonIgnore
@ManyToMany(fetch = FetchType.EAGER)
private Set<TagRepositoryImpl.TagEntity> tags = new HashSet<>();
@Override
public boolean equals(Object o) {
if (!(o instanceof OutputEntity that)) return false;
return Objects.equals(uuid, that.uuid);
}
@Override
public int hashCode() {
return Objects.hashCode(uuid);
}
@Column(nullable = false)
@JsonProperty
@Getter
@Setter
private String adapterId = "";
@Getter
@Setter
@JsonProperty
@Convert(converter = ValueTransformationChainConverter.class)
@Column(nullable = false)
private ValueTransformationChain transformationChain = new ValueTransformationChain();
}
}

View File

@ -23,9 +23,8 @@ public class TagRepositoryImpl extends AbstractRepository<Tag> implements TagRep
super(repositoryService);
}
@Override
public Tag getByName(String name) {
public Tag getByNameOrCreate(String name) {
try (var handler = buildQueryParametrized("WHERE name = ?1", name)) {
var result = handler.get().findFirst();
if (result.isPresent()) {
@ -43,8 +42,29 @@ public class TagRepositoryImpl extends AbstractRepository<Tag> implements TagRep
}
@Override
public ResourceHandler<Stream<Tag>> getByNames(Collection<String> names) {
return search("where name IN (?1)", List.of(names));
public TagCollection getByNamesOrCreate(Collection<String> names) {
var tags = new TagCollectionImpl();
try (var handler = search("where name IN (?1)", List.of(names))) {
tags.addAll(handler.get().toList());
} catch (IOException e) {
throw new RuntimeException("Unable to find tags by names " + names, e);
}
if (tags.size() != names.size()) {
var foundNames = tags.stream().map(Tag::getName).toList();
names.forEach(tagName -> {
if(!foundNames.contains(tagName)) {
var tag = create();
tag.setName(tagName);
store(tag);
tags.add(tag);
}
});
}
return tags;
}
@Override
@ -52,6 +72,11 @@ public class TagRepositoryImpl extends AbstractRepository<Tag> implements TagRep
return new TagCollectionImpl();
}
@Override
public TagCollection createCollection(ResourceHandler<Stream<Tag>> handler) {
return new TagCollectionImpl(handler.get().toList());
}
@Entity
@Table(name = "Tags")
@Builder
@ -112,6 +137,5 @@ public class TagRepositoryImpl extends AbstractRepository<Tag> implements TagRep
return Objects.hashCode(name);
}
}
}

View File

@ -1,37 +1,29 @@
package ru.kirillius.XCP.Persistence;
import ru.kirillius.XCP.Persistence.Entities.Tag;
import ru.kirillius.XCP.Persistence.Repositories.TagRepository;
import tools.jackson.core.JacksonException;
import tools.jackson.core.JsonGenerator;
import tools.jackson.core.JsonParser;
import tools.jackson.core.JsonToken;
import tools.jackson.databind.DeserializationContext;
import tools.jackson.databind.SerializationContext;
import tools.jackson.databind.deser.std.StdDeserializer;
import tools.jackson.databind.ser.std.StdSerializer;
import java.util.HashSet;
import java.util.Set;
public class TagSetDeserializer extends StdDeserializer<Set<Tag>> {
public class TagCollectionDeserializer extends StdDeserializer<TagCollection> {
private final RepositoryServiceImpl repositoryService;
public TagSetDeserializer(RepositoryServiceImpl repositoryService) {
super(Set.class);
public TagCollectionDeserializer(RepositoryServiceImpl repositoryService) {
super(TagCollection.class);
this.repositoryService = repositoryService;
}
@Override
public Set<Tag> deserialize(JsonParser p, DeserializationContext ctxt) throws JacksonException {
var result = new HashSet<Tag>();
public TagCollection deserialize(JsonParser p, DeserializationContext ctxt) throws JacksonException {
var result = new TagCollectionImpl();
var tagNames = p.readValueAs(String[].class);
var repository = repositoryService.getRepository(TagRepository.class);
for (var name : tagNames) {
var tag = repository.getByName(name);
var tag = repository.getByNameOrCreate(name);
result.add(tag);
}
return result;

View File

@ -2,7 +2,14 @@ package ru.kirillius.XCP.Persistence;
import ru.kirillius.XCP.Persistence.Entities.Tag;
import java.util.Collection;
import java.util.HashSet;
public class TagCollectionImpl extends HashSet<Tag> implements TagCollection {
public TagCollectionImpl() {
}
public TagCollectionImpl(Collection<? extends Tag> c) {
super(c);
}
}

View File

@ -0,0 +1,24 @@
package ru.kirillius.XCP.Persistence;
import tools.jackson.core.JacksonException;
import tools.jackson.core.JsonGenerator;
import tools.jackson.databind.SerializationContext;
import tools.jackson.databind.ser.std.StdSerializer;
public class TagCollectionSerializer extends StdSerializer<TagCollection> {
public TagCollectionSerializer() {
super(TagCollection.class);
}
@Override
public void serialize(TagCollection set, JsonGenerator gen, SerializationContext provider) throws JacksonException {
if(set == null) {
gen.writeNull();
return;
}
gen.writeStartArray();
set.forEach(tag -> gen.writeString(tag.getName()));
gen.writeEndArray();
}
}

View File

@ -1,30 +0,0 @@
package ru.kirillius.XCP.Persistence;
import ru.kirillius.XCP.Persistence.Entities.Tag;
import tools.jackson.core.JacksonException;
import tools.jackson.core.JsonGenerator;
import tools.jackson.databind.JavaType;
import tools.jackson.databind.SerializationContext;
import tools.jackson.databind.ser.std.StdSerializer;
import java.util.Set;
public class TagSetSerializer extends StdSerializer<Set<Tag>> {
private final RepositoryServiceImpl repositoryService;
public TagSetSerializer(RepositoryServiceImpl repositoryService) {
super(Set.class);
this.repositoryService = repositoryService;
}
@Override
public void serialize(Set<Tag> set, JsonGenerator gen, SerializationContext provider) throws JacksonException {
if(set == null) {
gen.writeNull();
return;
}
gen.writeStartArray();
set.forEach(tag -> gen.writeString(tag.getName()));
gen.writeEndArray();
}
}

View File

@ -0,0 +1,19 @@
package ru.kirillius.XCP.Serialization;
import jakarta.persistence.AttributeConverter;
import ru.kirillius.XCP.Persistence.PollSettingsImpl;
import tools.jackson.databind.ObjectMapper;
public class PollSettingsConverter implements AttributeConverter<PollSettingsImpl, String> {
private final static ObjectMapper mapper = new ObjectMapper();
@Override
public String convertToDatabaseColumn(PollSettingsImpl pollSettings) {
return mapper.writeValueAsString(pollSettings);
}
@Override
public PollSettingsImpl convertToEntityAttribute(String s) {
return mapper.readValue(s, PollSettingsImpl.class);
}
}

View File

@ -0,0 +1,19 @@
package ru.kirillius.XCP.Serialization;
import jakarta.persistence.AttributeConverter;
import ru.kirillius.XCP.Data.ValueTransformationChain;
import tools.jackson.databind.ObjectMapper;
public class ValueTransformationChainConverter implements AttributeConverter<ValueTransformationChain, String> {
private final static ObjectMapper mapper = new ObjectMapper();
@Override
public String convertToDatabaseColumn(ValueTransformationChain pollSettings) {
return mapper.writeValueAsString(pollSettings);
}
@Override
public ValueTransformationChain convertToEntityAttribute(String s) {
return mapper.readValue(s, ValueTransformationChain.class);
}
}

View File

@ -0,0 +1,115 @@
package ru.kirillius.XCP.Persistence.Repositories;
import org.junit.jupiter.api.Test;
import ru.kirillius.XCP.Persistence.NodeEntity;
import ru.kirillius.XCP.Persistence.NodeRepository;
import java.io.IOException;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
abstract class GenericNodeRepositoryTest<E extends NodeEntity, R extends AbstractNodeRepository<E>> extends GenericRepositoryTest<E, R> {
@Test
void getByGroup() throws IOException {
try (var service = spawnRepositoryService()) {
@SuppressWarnings("unchecked")
var repository = (NodeRepository<E>) service.getRepository(service.getRepositoryBaseType(repositoryClass));
var groupRepository = service.getRepository(GroupRepository.class);
var root = groupRepository.create();
groupRepository.store(root);
var firstChildGroup = groupRepository.create();
firstChildGroup.setParent(root);
groupRepository.store(firstChildGroup);
var secondChildGroup = groupRepository.create();
secondChildGroup.setParent(root);
groupRepository.store(secondChildGroup);
var firstChild = repository.create();
modify(firstChild, service);
firstChild.setParent(firstChildGroup);
repository.store(firstChild);
var secondChild = repository.create();
modify(secondChild, service);
secondChild.setParent(secondChildGroup);
repository.store(secondChild);
try (var handler = repository.getByGroup(firstChildGroup)) {
var found = handler.get().findFirst().orElse(null);
assertThat(found).isNotNull().isEqualTo(firstChild);
}
try (var handler = repository.getByGroup(secondChildGroup)) {
var found = handler.get().findFirst().orElse(null);
assertThat(found).isNotNull().isEqualTo(secondChild);
}
}
}
@Test
void testByTags() throws IOException {
try (var service = spawnRepositoryService()) {
var tagRepository = service.getRepository(TagRepository.class);
@SuppressWarnings("unchecked")
var repository = (NodeRepository<E>) service.getRepository(service.getRepositoryBaseType(repositoryClass));
var first = repository.create();
modify(first, service);
first.setTags(tagRepository.getByNamesOrCreate(List.of(
"first",
"foo",
"bar"
)));
repository.store(first);
var second = repository.create();
modify(second, service);
second.setTags(tagRepository.getByNamesOrCreate(List.of(
"second",
"foo",
"third"
)));
repository.store(second);
var third = repository.create();
modify(third, service);
third.setTags(tagRepository.getByNamesOrCreate(List.of(
"omg",
"third",
"yabba"
)));
repository.store(third);
try (var handler = repository.getByAllTags(tagRepository.getByNamesOrCreate(List.of("first")))) {
assertThat(handler.get().toList()).containsExactlyInAnyOrder(first).doesNotContain(second, third);
}
try (var handler = repository.getByAllTags(tagRepository.getByNamesOrCreate(List.of("foo")))) {
assertThat(handler.get().toList()).containsExactlyInAnyOrder(first, second).doesNotContain(third);
}
try (var handler = repository.getByAllTags(tagRepository.getByNamesOrCreate(List.of("third")))) {
assertThat(handler.get().toList()).containsExactlyInAnyOrder(third, second).doesNotContain(first);
}
try (var handler = repository.getByAnyTag(tagRepository.getByNamesOrCreate(List.of("first", "second", "third")))) {
assertThat(handler.get().toList()).containsExactlyInAnyOrder(first, second, third);
}
try (var handler = repository.getByAnyTag(tagRepository.getByNamesOrCreate(List.of("omg", "yabba")))) {
assertThat(handler.get().toList()).containsExactlyInAnyOrder(third).doesNotContain(second, first);
}
try (var handler = repository.getByAllTags(tagRepository.getByNamesOrCreate(List.of("shrash")))) {
assertThat(handler.get().toList()).isEmpty();
}
}
}
}

View File

@ -52,6 +52,7 @@ abstract class GenericRepositoryTest<E extends PersistenceEntity, R extends Abst
try (var service = spawnRepositoryService()) {
var repository = service.getRepositoryForEntity(entityClass);
var entity = repository.create();
modify(entity, service);
repository.store(entity);
assertThat(entity.getId()).isNotZero();
}
@ -62,6 +63,7 @@ abstract class GenericRepositoryTest<E extends PersistenceEntity, R extends Abst
try (var service = spawnRepositoryService()) {
var repository = service.getRepositoryForEntity(entityClass);
var entity = repository.create();
modify(entity, service);
repository.store(entity);
var loaded = repository.load(entity.getId());
assertThat(loaded).isNotNull().isEqualTo(entity);
@ -76,8 +78,9 @@ abstract class GenericRepositoryTest<E extends PersistenceEntity, R extends Abst
try (var service = spawnRepositoryService()) {
var repository = service.getRepositoryForEntity(entityClass);
var entity = repository.create();
modify(entity, service);
repository.store(entity);
modify(entity,service);
modify(entity, service);
repository.store(entity);
var loaded = repository.load(entity.getId());
assertThat(loaded).isNotNull().isEqualTo(entity);
@ -89,6 +92,7 @@ abstract class GenericRepositoryTest<E extends PersistenceEntity, R extends Abst
try (var service = spawnRepositoryService()) {
var repository = service.getRepositoryForEntity(entityClass);
var entity = repository.create();
modify(entity, service);
repository.store(entity);
assertThat(repository.getCount()).isEqualTo(1);
repository.remove(entity);
@ -101,6 +105,7 @@ abstract class GenericRepositoryTest<E extends PersistenceEntity, R extends Abst
try (var service = spawnRepositoryService()) {
var repository = service.getRepositoryForEntity(entityClass);
var entity = repository.create();
modify(entity, service);
repository.store(entity);
var serialized = repository.serialize(entity);
@ -109,7 +114,7 @@ abstract class GenericRepositoryTest<E extends PersistenceEntity, R extends Abst
assertThat(deserialized).isNotNull().isEqualTo(entity);
var anotherEntity = repository.create();
modify(anotherEntity,service);
modify(anotherEntity, service);
repository.store(anotherEntity);
var anotherSerialized = repository.serialize(anotherEntity);

View File

@ -1,22 +1,20 @@
package ru.kirillius.XCP.Persistence.Repositories;
import org.junit.jupiter.api.Test;
import ru.kirillius.XCP.Commons.StreamHandler;
import ru.kirillius.XCP.Persistence.Entities.Group;
import ru.kirillius.XCP.Persistence.Entities.Tag;
import ru.kirillius.XCP.Persistence.Repository;
import ru.kirillius.XCP.Persistence.RepositoryService;
import ru.kirillius.XCP.Persistence.TagCollectionImpl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
import static ru.kirillius.XCP.Persistence.TestEnvironment.instantiateTestService;
class GroupRepositoryImplTest extends GenericRepositoryTest<Group, GroupRepositoryImpl> {
class GroupRepositoryImplTest extends GenericNodeRepositoryTest<Group, GroupRepositoryImpl> {
@Override
protected RepositoryService spawnRepositoryService() {
var service = instantiateTestService(List.of(repositoryClass, TagRepositoryImpl.class));
@ -29,6 +27,7 @@ class GroupRepositoryImplTest extends GenericRepositoryTest<Group, GroupReposito
return service;
}
@Test
void getChildrenOf() throws IOException {
try (var service = spawnRepositoryService()) {
@ -139,7 +138,7 @@ class GroupRepositoryImplTest extends GenericRepositoryTest<Group, GroupReposito
}
try (var handler = service.getRepositoryForEntity(Tag.class).loadAll()) {
entity.setTags(new HashSet<>(handler.get().toList()));
entity.setTags(new TagCollectionImpl(handler.get().toList()));
} catch (IOException e) {
throw new RuntimeException(e);
}

View File

@ -0,0 +1,47 @@
package ru.kirillius.XCP.Persistence.Repositories;
import ru.kirillius.XCP.Persistence.Entities.Input;
import ru.kirillius.XCP.Persistence.Entities.Tag;
import ru.kirillius.XCP.Persistence.RepositoryService;
import ru.kirillius.XCP.Persistence.TagCollectionImpl;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
import static ru.kirillius.XCP.Persistence.TestEnvironment.instantiateTestService;
class InputRepositoryImplTest extends GenericNodeRepositoryTest<Input, InputRepositoryImpl> {
@Override
protected RepositoryService spawnRepositoryService() {
var service = instantiateTestService(List.of(repositoryClass, TagRepositoryImpl.class, GroupRepositoryImpl.class));
for (var i = 0; i < 5; i++) {
var tagRepository = service.getRepositoryForEntity(Tag.class);
var tag = tagRepository.create();
tag.setName("tag" + i);
tagRepository.store(tag);
}
return service;
}
@Override
protected void modify(Input entity, RepositoryService service) {
var groupRepository = service.getRepository(GroupRepository.class);
var root = groupRepository.getRoot();
if (root == null) {
root = groupRepository.create();
groupRepository.store(root);
}
entity.setParent(root);
entity.setName(UUID.randomUUID().toString());
//var inputRepository = service.getRepository(InputRepository.class);
try (var handler = service.getRepositoryForEntity(Tag.class).loadAll()) {
entity.setTags(new TagCollectionImpl(handler.get().toList()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,47 @@
package ru.kirillius.XCP.Persistence.Repositories;
import ru.kirillius.XCP.Persistence.Entities.Output;
import ru.kirillius.XCP.Persistence.Entities.Tag;
import ru.kirillius.XCP.Persistence.RepositoryService;
import ru.kirillius.XCP.Persistence.TagCollectionImpl;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
import static ru.kirillius.XCP.Persistence.TestEnvironment.instantiateTestService;
class OutputRepositoryImplTest extends GenericNodeRepositoryTest<Output, OutputRepositoryImpl> {
@Override
protected RepositoryService spawnRepositoryService() {
var service = instantiateTestService(List.of(repositoryClass, TagRepositoryImpl.class, GroupRepositoryImpl.class));
for (var i = 0; i < 5; i++) {
var tagRepository = service.getRepositoryForEntity(Tag.class);
var tag = tagRepository.create();
tag.setName("tag" + i);
tagRepository.store(tag);
}
return service;
}
@Override
protected void modify(Output entity, RepositoryService service) {
var groupRepository = service.getRepository(GroupRepository.class);
var root = groupRepository.getRoot();
if (root == null) {
root = groupRepository.create();
groupRepository.store(root);
}
entity.setParent(root);
entity.setName(UUID.randomUUID().toString());
//var inputRepository = service.getRepository(InputRepository.class);
try (var handler = service.getRepositoryForEntity(Tag.class).loadAll()) {
entity.setTags(new TagCollectionImpl(handler.get().toList()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -5,22 +5,68 @@ import ru.kirillius.XCP.Persistence.Entities.Tag;
import ru.kirillius.XCP.Persistence.RepositoryService;
import java.io.IOException;
import java.util.ArrayList;
import static org.assertj.core.api.Assertions.assertThat;
class TagRepositoryImplTest extends GenericRepositoryTest<Tag, TagRepositoryImpl> {
@Test
void testGetByName() throws IOException {
void testGetByNameOrCreate() throws IOException {
try (var service = spawnRepositoryService()) {
var repository = service.getRepository(TagRepository.class);
var tag = repository.create();
tag.setName("test");
repository.store(tag);
var found = repository.getByName(tag.getName());
var found = repository.getByNameOrCreate(tag.getName());
assertThat(found).isEqualTo(tag);
}
}
@Test
public void testGetByNamesOrCreateAsCollectionOrCreate() throws IOException {
try (var service = spawnRepositoryService()) {
var repository = service.getRepository(TagRepository.class);
var tags = new ArrayList<Tag>();
for (var i = 0; i < 10; i++) {
var tag = repository.create();
tag.setName("test" + i);
repository.store(tag);
tags.add(tag);
}
var tagNames = tags.stream().map(Tag::getName).toList();
assertThat(repository.getByNamesOrCreate(tagNames)).containsExactlyInAnyOrderElementsOf(tags);
}
}
@Test
public void testCreateCollection() throws IOException {
try (var service = spawnRepositoryService()) {
var repository = service.getRepository(TagRepository.class);
var tags = new ArrayList<Tag>();
for (var i = 0; i < 10; i++) {
var tag = repository.create();
tag.setName("test" + i);
repository.store(tag);
tags.add(tag);
}
var emptyCollection = repository.createCollection();
assertThat(emptyCollection).isNotNull().isEmpty();
try (var handler = repository.loadAll()) {
var collection = repository.createCollection(handler);
assertThat(collection).containsExactlyInAnyOrderElementsOf(tags);
}
}
}
@Override
protected void modify(Tag entity, RepositoryService service) {
entity.setName("test" + Math.random());