From dcb15ebdc1b6e812c97a722d09372eb9a9c8937d Mon Sep 17 00:00:00 2001 From: kirillius Date: Thu, 8 Jan 2026 09:47:38 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B8=20=D1=81=D1=82=D0=B0?= =?UTF-8?q?=D0=B1=D0=B8=D0=BB=D0=B8=D0=B7=D0=B8=D1=80=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D0=BB=20=D1=81=D1=83=D1=89=D0=BD=D0=BE=D1=81=D1=82=D0=B8.=20?= =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE=D1=80=D0=B8=D0=BD?= =?UTF-8?q?=D0=B3=20ValueTransformationChain?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kirillius/XCP/Commons/Initializable.java | 7 + .../ru/kirillius/XCP/Commons/Service.java | 4 +- .../ru/kirillius/XCP/Data/DataAdapter.java | 17 ++ .../XCP/Data/DataTransferProtocol.java | 6 - .../ru/kirillius/XCP/Data/PollSettings.java | 15 +- .../ru/kirillius/XCP/Data/ValueModifier.java | 6 - .../XCP/Data/ValueModifierSettings.java | 14 -- .../XCP/Data/ValueTransformationChain.java | 24 +++ .../XCP/Data/ValueTransformationStep.java | 19 +++ .../kirillius/XCP/Data/ValueTransformer.java | 10 ++ .../XCP/Data/ValueTransformerDescriptor.java | 12 ++ .../kirillius/XCP/Persistence/IOEntity.java | 14 +- .../XCP/Persistence/NodeRepository.java | 4 +- .../Repositories/OutputRepository.java | 4 +- .../Repositories/TagRepository.java | 6 +- .../EntityReferenceSerializer.java | 4 - .../PersistenceSerializationModule.java | 9 +- .../XCP/Persistence/PollSettingsImpl.java | 21 +++ .../Repositories/AbstractNodeRepository.java | 29 +++- .../Repositories/GroupRepositoryImpl.java | 9 +- .../Repositories/InputRepositoryImpl.java | 160 ++++++++++++++++++ .../Repositories/OutputRepositoryImpl.java | 141 +++++++++++++++ .../Repositories/TagRepositoryImpl.java | 34 +++- ...er.java => TagCollectionDeserializer.java} | 20 +-- .../XCP/Persistence/TagCollectionImpl.java | 7 + .../Persistence/TagCollectionSerializer.java | 24 +++ .../XCP/Persistence/TagSetSerializer.java | 30 ---- .../Serialization/PollSettingsConverter.java | 19 +++ .../ValueTransformationChainConverter.java | 19 +++ .../GenericNodeRepositoryTest.java | 115 +++++++++++++ .../Repositories/GenericRepositoryTest.java | 9 +- .../Repositories/GroupRepositoryImplTest.java | 9 +- .../Repositories/InputRepositoryImplTest.java | 47 +++++ .../OutputRepositoryImplTest.java | 47 +++++ .../Repositories/TagRepositoryImplTest.java | 50 +++++- 35 files changed, 836 insertions(+), 129 deletions(-) create mode 100644 api/src/main/java/ru/kirillius/XCP/Commons/Initializable.java create mode 100644 api/src/main/java/ru/kirillius/XCP/Data/DataAdapter.java delete mode 100644 api/src/main/java/ru/kirillius/XCP/Data/DataTransferProtocol.java delete mode 100644 api/src/main/java/ru/kirillius/XCP/Data/ValueModifier.java delete mode 100644 api/src/main/java/ru/kirillius/XCP/Data/ValueModifierSettings.java create mode 100644 api/src/main/java/ru/kirillius/XCP/Data/ValueTransformationChain.java create mode 100644 api/src/main/java/ru/kirillius/XCP/Data/ValueTransformationStep.java create mode 100644 api/src/main/java/ru/kirillius/XCP/Data/ValueTransformer.java create mode 100644 api/src/main/java/ru/kirillius/XCP/Data/ValueTransformerDescriptor.java create mode 100644 database/src/main/java/ru/kirillius/XCP/Persistence/PollSettingsImpl.java create mode 100644 database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/InputRepositoryImpl.java create mode 100644 database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/OutputRepositoryImpl.java rename database/src/main/java/ru/kirillius/XCP/Persistence/{TagSetDeserializer.java => TagCollectionDeserializer.java} (51%) create mode 100644 database/src/main/java/ru/kirillius/XCP/Persistence/TagCollectionSerializer.java delete mode 100644 database/src/main/java/ru/kirillius/XCP/Persistence/TagSetSerializer.java create mode 100644 database/src/main/java/ru/kirillius/XCP/Serialization/PollSettingsConverter.java create mode 100644 database/src/main/java/ru/kirillius/XCP/Serialization/ValueTransformationChainConverter.java create mode 100644 database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/GenericNodeRepositoryTest.java create mode 100644 database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/InputRepositoryImplTest.java create mode 100644 database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/OutputRepositoryImplTest.java diff --git a/api/src/main/java/ru/kirillius/XCP/Commons/Initializable.java b/api/src/main/java/ru/kirillius/XCP/Commons/Initializable.java new file mode 100644 index 0000000..3ccf0e9 --- /dev/null +++ b/api/src/main/java/ru/kirillius/XCP/Commons/Initializable.java @@ -0,0 +1,7 @@ +package ru.kirillius.XCP.Commons; + +import java.io.Closeable; + +public interface Initializable extends Closeable { + void initialize(Context context); +} diff --git a/api/src/main/java/ru/kirillius/XCP/Commons/Service.java b/api/src/main/java/ru/kirillius/XCP/Commons/Service.java index a026678..b2510ad 100644 --- a/api/src/main/java/ru/kirillius/XCP/Commons/Service.java +++ b/api/src/main/java/ru/kirillius/XCP/Commons/Service.java @@ -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); } diff --git a/api/src/main/java/ru/kirillius/XCP/Data/DataAdapter.java b/api/src/main/java/ru/kirillius/XCP/Data/DataAdapter.java new file mode 100644 index 0000000..1a3c392 --- /dev/null +++ b/api/src/main/java/ru/kirillius/XCP/Data/DataAdapter.java @@ -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 subscribe(); + + void unsubscribe(EventHandler subscription); + +} diff --git a/api/src/main/java/ru/kirillius/XCP/Data/DataTransferProtocol.java b/api/src/main/java/ru/kirillius/XCP/Data/DataTransferProtocol.java deleted file mode 100644 index 06d2728..0000000 --- a/api/src/main/java/ru/kirillius/XCP/Data/DataTransferProtocol.java +++ /dev/null @@ -1,6 +0,0 @@ -package ru.kirillius.XCP.Data; - -@Deprecated -public interface DataTransferProtocol { - //TODO -} diff --git a/api/src/main/java/ru/kirillius/XCP/Data/PollSettings.java b/api/src/main/java/ru/kirillius/XCP/Data/PollSettings.java index ac4bf14..d23e6ea 100644 --- a/api/src/main/java/ru/kirillius/XCP/Data/PollSettings.java +++ b/api/src/main/java/ru/kirillius/XCP/Data/PollSettings.java @@ -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(); - } diff --git a/api/src/main/java/ru/kirillius/XCP/Data/ValueModifier.java b/api/src/main/java/ru/kirillius/XCP/Data/ValueModifier.java deleted file mode 100644 index cd5eee0..0000000 --- a/api/src/main/java/ru/kirillius/XCP/Data/ValueModifier.java +++ /dev/null @@ -1,6 +0,0 @@ -package ru.kirillius.XCP.Data; - -@Deprecated -public interface ValueModifier { - //TODO -} diff --git a/api/src/main/java/ru/kirillius/XCP/Data/ValueModifierSettings.java b/api/src/main/java/ru/kirillius/XCP/Data/ValueModifierSettings.java deleted file mode 100644 index 656b652..0000000 --- a/api/src/main/java/ru/kirillius/XCP/Data/ValueModifierSettings.java +++ /dev/null @@ -1,14 +0,0 @@ -package ru.kirillius.XCP.Data; - -import tools.jackson.databind.node.ObjectNode; - -public interface ValueModifierSettings { - - Class getModifierClass(); - - void setModifierClass(Class modifierClass); - - ObjectNode getParameters(); - - void setParameters(ObjectNode parameters); -} diff --git a/api/src/main/java/ru/kirillius/XCP/Data/ValueTransformationChain.java b/api/src/main/java/ru/kirillius/XCP/Data/ValueTransformationChain.java new file mode 100644 index 0000000..a7c7492 --- /dev/null +++ b/api/src/main/java/ru/kirillius/XCP/Data/ValueTransformationChain.java @@ -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 steps = new ArrayList<>(); +} diff --git a/api/src/main/java/ru/kirillius/XCP/Data/ValueTransformationStep.java b/api/src/main/java/ru/kirillius/XCP/Data/ValueTransformationStep.java new file mode 100644 index 0000000..fb8c2bd --- /dev/null +++ b/api/src/main/java/ru/kirillius/XCP/Data/ValueTransformationStep.java @@ -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; +} diff --git a/api/src/main/java/ru/kirillius/XCP/Data/ValueTransformer.java b/api/src/main/java/ru/kirillius/XCP/Data/ValueTransformer.java new file mode 100644 index 0000000..d5cb92d --- /dev/null +++ b/api/src/main/java/ru/kirillius/XCP/Data/ValueTransformer.java @@ -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, Object> { + +} diff --git a/api/src/main/java/ru/kirillius/XCP/Data/ValueTransformerDescriptor.java b/api/src/main/java/ru/kirillius/XCP/Data/ValueTransformerDescriptor.java new file mode 100644 index 0000000..1bded98 --- /dev/null +++ b/api/src/main/java/ru/kirillius/XCP/Data/ValueTransformerDescriptor.java @@ -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 ""; +} diff --git a/api/src/main/java/ru/kirillius/XCP/Persistence/IOEntity.java b/api/src/main/java/ru/kirillius/XCP/Persistence/IOEntity.java index f2acec2..38aa758 100644 --- a/api/src/main/java/ru/kirillius/XCP/Persistence/IOEntity.java +++ b/api/src/main/java/ru/kirillius/XCP/Persistence/IOEntity.java @@ -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 getModifiers(); + ValueTransformationChain getTransformationChain(); - void setModifiers(List modifiers); + void setTransformationChain(ValueTransformationChain transformationChain); - Class getProtocol(); + String getAdapterId(); + + void setAdapterId(String adapterId); - void setProtocol(Class protocol); } diff --git a/api/src/main/java/ru/kirillius/XCP/Persistence/NodeRepository.java b/api/src/main/java/ru/kirillius/XCP/Persistence/NodeRepository.java index b7479b3..10ba4f9 100644 --- a/api/src/main/java/ru/kirillius/XCP/Persistence/NodeRepository.java +++ b/api/src/main/java/ru/kirillius/XCP/Persistence/NodeRepository.java @@ -9,5 +9,7 @@ import java.util.Collection; public interface NodeRepository extends Repository { StreamHandler getByGroup(Group group); - StreamHandler getByTags(Collection tags); + StreamHandler getByAllTags(Collection tags); + + StreamHandler getByAnyTag(Collection tags); } diff --git a/api/src/main/java/ru/kirillius/XCP/Persistence/Repositories/OutputRepository.java b/api/src/main/java/ru/kirillius/XCP/Persistence/Repositories/OutputRepository.java index 9600da7..2d4b64c 100644 --- a/api/src/main/java/ru/kirillius/XCP/Persistence/Repositories/OutputRepository.java +++ b/api/src/main/java/ru/kirillius/XCP/Persistence/Repositories/OutputRepository.java @@ -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 { +public interface OutputRepository extends NodeRepository { } diff --git a/api/src/main/java/ru/kirillius/XCP/Persistence/Repositories/TagRepository.java b/api/src/main/java/ru/kirillius/XCP/Persistence/Repositories/TagRepository.java index b8be6b7..322596a 100644 --- a/api/src/main/java/ru/kirillius/XCP/Persistence/Repositories/TagRepository.java +++ b/api/src/main/java/ru/kirillius/XCP/Persistence/Repositories/TagRepository.java @@ -9,9 +9,11 @@ import java.util.Collection; import java.util.stream.Stream; public interface TagRepository extends Repository { - Tag getByName(String name); + Tag getByNameOrCreate(String name); - ResourceHandler> getByNames(Collection names); + TagCollection getByNamesOrCreate(Collection names); TagCollection createCollection(); + + TagCollection createCollection(ResourceHandler> handler); } diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/EntityReferenceSerializer.java b/database/src/main/java/ru/kirillius/XCP/Persistence/EntityReferenceSerializer.java index 796ddff..9783f54 100644 --- a/database/src/main/java/ru/kirillius/XCP/Persistence/EntityReferenceSerializer.java +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/EntityReferenceSerializer.java @@ -13,10 +13,6 @@ public class EntityReferenceSerializer extends StdSerializer { this.repositoryService = repositoryService; } -// protected EntityReferenceSerializer(Class t) { -// super(t); -// } - @Override public void serialize(EntityReference reference, JsonGenerator gen, SerializationContext provider) throws JacksonException { var value = reference.get(); diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/PersistenceSerializationModule.java b/database/src/main/java/ru/kirillius/XCP/Persistence/PersistenceSerializationModule.java index 6513cca..907ba21 100644 --- a/database/src/main/java/ru/kirillius/XCP/Persistence/PersistenceSerializationModule.java +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/PersistenceSerializationModule.java @@ -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) ))); } } diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/PollSettingsImpl.java b/database/src/main/java/ru/kirillius/XCP/Persistence/PollSettingsImpl.java new file mode 100644 index 0000000..2fe62a2 --- /dev/null +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/PollSettingsImpl.java @@ -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; +} diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/AbstractNodeRepository.java b/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/AbstractNodeRepository.java index e6fec8f..52abbd1 100644 --- a/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/AbstractNodeRepository.java +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/AbstractNodeRepository.java @@ -20,22 +20,37 @@ public abstract class AbstractNodeRepository extends Abstr @Override public StreamHandler getByGroup(Group group) { - return search("WHERE group = ?1", List.of(group)); + return search("WHERE parent = ?1", List.of(group)); } + @SuppressWarnings("unchecked") @Override - public StreamHandler getByTags(Collection tags) { + public StreamHandler getByAllTags(Collection 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) 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 getByAnyTag(Collection 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) session.createQuery(hql, entityImplementationClass); + query.setParameter("tagNames", tags.stream().map(Tag::getName).toList()); return new ResourceHandlerImpl<>(query, transaction, session); } } diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/GroupRepositoryImpl.java b/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/GroupRepositoryImpl.java index 3552958..0f5d9cf 100644 --- a/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/GroupRepositoryImpl.java +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/GroupRepositoryImpl.java @@ -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 implement @Override - public void setTags(Set tags) { + public void setTags(TagCollection tags) { this.tags = tags.stream().map(t -> (TagRepositoryImpl.TagEntity) t).collect(Collectors.toSet()); } @Override - public Set getTags() { - return new HashSet<>(tags); + public TagCollection getTags() { + return new TagCollectionImpl(tags); } @Column(nullable = false) diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/InputRepositoryImpl.java b/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/InputRepositoryImpl.java new file mode 100644 index 0000000..e6f7210 --- /dev/null +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/InputRepositoryImpl.java @@ -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 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 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(); + + } +} diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/OutputRepositoryImpl.java b/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/OutputRepositoryImpl.java new file mode 100644 index 0000000..3b97722 --- /dev/null +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/OutputRepositoryImpl.java @@ -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 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 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(); + + } +} diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/TagRepositoryImpl.java b/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/TagRepositoryImpl.java index 4f06e8d..728c96f 100644 --- a/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/TagRepositoryImpl.java +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/TagRepositoryImpl.java @@ -23,9 +23,8 @@ public class TagRepositoryImpl extends AbstractRepository 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 implements TagRep } @Override - public ResourceHandler> getByNames(Collection names) { - return search("where name IN (?1)", List.of(names)); + public TagCollection getByNamesOrCreate(Collection 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 implements TagRep return new TagCollectionImpl(); } + @Override + public TagCollection createCollection(ResourceHandler> handler) { + return new TagCollectionImpl(handler.get().toList()); + } + @Entity @Table(name = "Tags") @Builder @@ -112,6 +137,5 @@ public class TagRepositoryImpl extends AbstractRepository implements TagRep return Objects.hashCode(name); } - } } diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/TagSetDeserializer.java b/database/src/main/java/ru/kirillius/XCP/Persistence/TagCollectionDeserializer.java similarity index 51% rename from database/src/main/java/ru/kirillius/XCP/Persistence/TagSetDeserializer.java rename to database/src/main/java/ru/kirillius/XCP/Persistence/TagCollectionDeserializer.java index 9559b26..617abe3 100644 --- a/database/src/main/java/ru/kirillius/XCP/Persistence/TagSetDeserializer.java +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/TagCollectionDeserializer.java @@ -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> { +public class TagCollectionDeserializer extends StdDeserializer { private final RepositoryServiceImpl repositoryService; - public TagSetDeserializer(RepositoryServiceImpl repositoryService) { - super(Set.class); + public TagCollectionDeserializer(RepositoryServiceImpl repositoryService) { + super(TagCollection.class); this.repositoryService = repositoryService; } @Override - public Set deserialize(JsonParser p, DeserializationContext ctxt) throws JacksonException { - var result = new HashSet(); + 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; diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/TagCollectionImpl.java b/database/src/main/java/ru/kirillius/XCP/Persistence/TagCollectionImpl.java index 67917b5..44e0045 100644 --- a/database/src/main/java/ru/kirillius/XCP/Persistence/TagCollectionImpl.java +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/TagCollectionImpl.java @@ -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 implements TagCollection { + public TagCollectionImpl() { + } + + public TagCollectionImpl(Collection c) { + super(c); + } } diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/TagCollectionSerializer.java b/database/src/main/java/ru/kirillius/XCP/Persistence/TagCollectionSerializer.java new file mode 100644 index 0000000..c965bc3 --- /dev/null +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/TagCollectionSerializer.java @@ -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 { + + 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(); + } +} diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/TagSetSerializer.java b/database/src/main/java/ru/kirillius/XCP/Persistence/TagSetSerializer.java deleted file mode 100644 index 52c2952..0000000 --- a/database/src/main/java/ru/kirillius/XCP/Persistence/TagSetSerializer.java +++ /dev/null @@ -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> { - private final RepositoryServiceImpl repositoryService; - - public TagSetSerializer(RepositoryServiceImpl repositoryService) { - super(Set.class); - this.repositoryService = repositoryService; - } - - @Override - public void serialize(Set set, JsonGenerator gen, SerializationContext provider) throws JacksonException { - if(set == null) { - gen.writeNull(); - return; - } - gen.writeStartArray(); - set.forEach(tag -> gen.writeString(tag.getName())); - gen.writeEndArray(); - } -} diff --git a/database/src/main/java/ru/kirillius/XCP/Serialization/PollSettingsConverter.java b/database/src/main/java/ru/kirillius/XCP/Serialization/PollSettingsConverter.java new file mode 100644 index 0000000..ab9e8d6 --- /dev/null +++ b/database/src/main/java/ru/kirillius/XCP/Serialization/PollSettingsConverter.java @@ -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 { + 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); + } +} \ No newline at end of file diff --git a/database/src/main/java/ru/kirillius/XCP/Serialization/ValueTransformationChainConverter.java b/database/src/main/java/ru/kirillius/XCP/Serialization/ValueTransformationChainConverter.java new file mode 100644 index 0000000..b8f6e3e --- /dev/null +++ b/database/src/main/java/ru/kirillius/XCP/Serialization/ValueTransformationChainConverter.java @@ -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 { + 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); + } +} \ No newline at end of file diff --git a/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/GenericNodeRepositoryTest.java b/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/GenericNodeRepositoryTest.java new file mode 100644 index 0000000..0a33bc7 --- /dev/null +++ b/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/GenericNodeRepositoryTest.java @@ -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> extends GenericRepositoryTest { + + @Test + void getByGroup() throws IOException { + try (var service = spawnRepositoryService()) { + @SuppressWarnings("unchecked") + var repository = (NodeRepository) 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) 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(); + } + } + } +} \ No newline at end of file diff --git a/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/GenericRepositoryTest.java b/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/GenericRepositoryTest.java index cbbb048..8fc7c5e 100644 --- a/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/GenericRepositoryTest.java +++ b/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/GenericRepositoryTest.java @@ -52,6 +52,7 @@ abstract class GenericRepositoryTest { +class GroupRepositoryImplTest extends GenericNodeRepositoryTest { @Override protected RepositoryService spawnRepositoryService() { var service = instantiateTestService(List.of(repositoryClass, TagRepositoryImpl.class)); @@ -29,6 +27,7 @@ class GroupRepositoryImplTest extends GenericRepositoryTest(handler.get().toList())); + entity.setTags(new TagCollectionImpl(handler.get().toList())); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/InputRepositoryImplTest.java b/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/InputRepositoryImplTest.java new file mode 100644 index 0000000..e765a69 --- /dev/null +++ b/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/InputRepositoryImplTest.java @@ -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 { + @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); + } + } +} \ No newline at end of file diff --git a/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/OutputRepositoryImplTest.java b/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/OutputRepositoryImplTest.java new file mode 100644 index 0000000..35b420d --- /dev/null +++ b/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/OutputRepositoryImplTest.java @@ -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 { + @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); + } + } +} \ No newline at end of file diff --git a/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/TagRepositoryImplTest.java b/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/TagRepositoryImplTest.java index 1d25a52..e924016 100644 --- a/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/TagRepositoryImplTest.java +++ b/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/TagRepositoryImplTest.java @@ -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 { @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(); + + 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(); + + 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());