WIP: промежуточный коммит

This commit is contained in:
kirill.labutin 2026-01-02 23:56:25 +03:00
parent b264b38fe4
commit 2d7c7fea9c
15 changed files with 176 additions and 25 deletions

View File

@ -1,11 +1,8 @@
package ru.kirillius.XCP.Persistence; package ru.kirillius.XCP.Persistence;
import ru.kirillius.XCP.Persistence.Entities.Group; import ru.kirillius.XCP.Persistence.Entities.Group;
import ru.kirillius.XCP.Persistence.Entities.Tag;
import tools.jackson.databind.node.ObjectNode; import tools.jackson.databind.node.ObjectNode;
import java.util.Set;
public interface NodeEntity extends PersistenceEntity { public interface NodeEntity extends PersistenceEntity {
String getName(); String getName();
@ -27,7 +24,7 @@ public interface NodeEntity extends PersistenceEntity {
void setProperties(ObjectNode properties); void setProperties(ObjectNode properties);
Set<Tag> getTags(); TagCollection getTags();
void setTags(Set<Tag> tags); void setTags(TagCollection tags);
} }

View File

@ -10,6 +10,4 @@ public interface NodeRepository<E extends NodeEntity> extends Repository<E> {
StreamHandler<E> getByGroup(Group group); StreamHandler<E> getByGroup(Group group);
StreamHandler<E> getByTags(Collection<Tag> tags); StreamHandler<E> getByTags(Collection<Tag> tags);
} }

View File

@ -3,6 +3,7 @@ package ru.kirillius.XCP.Persistence.Repositories;
import ru.kirillius.XCP.Commons.ResourceHandler; import ru.kirillius.XCP.Commons.ResourceHandler;
import ru.kirillius.XCP.Persistence.Entities.Tag; import ru.kirillius.XCP.Persistence.Entities.Tag;
import ru.kirillius.XCP.Persistence.Repository; import ru.kirillius.XCP.Persistence.Repository;
import ru.kirillius.XCP.Persistence.TagCollection;
import java.util.Collection; import java.util.Collection;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -11,4 +12,6 @@ public interface TagRepository extends Repository<Tag> {
Tag getByName(String name); Tag getByName(String name);
ResourceHandler<Stream<Tag>> getByNames(Collection<String> names); ResourceHandler<Stream<Tag>> getByNames(Collection<String> names);
TagCollection createCollection();
} }

View File

@ -0,0 +1,9 @@
package ru.kirillius.XCP.Persistence;
import ru.kirillius.XCP.Persistence.Entities.Tag;
import java.util.Collection;
public interface TagCollection extends Collection<Tag> {
}

View File

@ -6,16 +6,16 @@ import tools.jackson.databind.SerializationContext;
import tools.jackson.databind.ser.std.StdSerializer; import tools.jackson.databind.ser.std.StdSerializer;
public class EntityReferenceSerializer extends StdSerializer<EntityReference> { public class EntityReferenceSerializer extends StdSerializer<EntityReference> {
private RepositoryServiceImpl repositoryService; private final RepositoryServiceImpl repositoryService;
public EntityReferenceSerializer(RepositoryServiceImpl repositoryService) { public EntityReferenceSerializer(RepositoryServiceImpl repositoryService) {
super(EntityReference.class); super(EntityReference.class);
this.repositoryService = repositoryService; this.repositoryService = repositoryService;
} }
protected EntityReferenceSerializer(Class<PersistenceEntity> t) { // protected EntityReferenceSerializer(Class<PersistenceEntity> t) {
super(t); // super(t);
} // }
@Override @Override
public void serialize(EntityReference reference, JsonGenerator gen, SerializationContext provider) throws JacksonException { public void serialize(EntityReference reference, JsonGenerator gen, SerializationContext provider) throws JacksonException {

View File

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

View File

@ -68,6 +68,8 @@ public class GroupRepositoryImpl extends AbstractNodeRepository<Group> implement
super.store(entity); super.store(entity);
} }
@Entity @Entity
@Table(name = "Groups") @Table(name = "Groups")
@Builder @Builder
@ -76,6 +78,8 @@ public class GroupRepositoryImpl extends AbstractNodeRepository<Group> implement
@Getter @Getter
@Setter @Setter
public static class GroupEntity implements Group { public static class GroupEntity implements Group {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
@JsonProperty @JsonProperty
@ -120,13 +124,13 @@ public class GroupRepositoryImpl extends AbstractNodeRepository<Group> implement
private GroupEntity parent; private GroupEntity parent;
@JsonProperty("parent") @JsonProperty("parent")
public EntityReference getParentReference() { EntityReference getParentReference() {
return new EntityReference(getParent()); return new EntityReference(getParent());
} }
@JsonProperty("parent") @JsonProperty("parent")
public void setParentReference(EntityReference entityReference) { void setParentReference(EntityReference entityReference) {
parent = (GroupEntity) entityReference.get(); parent = entityReference == null ? null : (GroupEntity) entityReference.get();
} }
public Group getParent() { public Group getParent() {
@ -137,6 +141,9 @@ public class GroupRepositoryImpl extends AbstractNodeRepository<Group> implement
this.parent = (GroupEntity) parent; this.parent = (GroupEntity) parent;
} }
@Override @Override
public void setTags(Set<Tag> tags) { public void setTags(Set<Tag> tags) {
this.tags = tags.stream().map(t -> (TagRepositoryImpl.TagEntity) t).collect(Collectors.toSet()); this.tags = tags.stream().map(t -> (TagRepositoryImpl.TagEntity) t).collect(Collectors.toSet());
@ -153,7 +160,7 @@ public class GroupRepositoryImpl extends AbstractNodeRepository<Group> implement
@Setter @Setter
private ObjectNode properties = SerializationUtils.EmptyObject(); private ObjectNode properties = SerializationUtils.EmptyObject();
@JsonProperty @JsonIgnore
@ManyToMany(fetch = FetchType.EAGER) @ManyToMany(fetch = FetchType.EAGER)
private Set<TagRepositoryImpl.TagEntity> tags = new HashSet<>(); private Set<TagRepositoryImpl.TagEntity> tags = new HashSet<>();

View File

@ -24,12 +24,19 @@ public class TagRepositoryImpl extends AbstractRepository<Tag> implements TagRep
} }
@Override @Override
public Tag getByName(String name) { public Tag getByName(String name) {
try (var handler = buildQueryParametrized("WHERE name = ?1", name)) { try (var handler = buildQueryParametrized("WHERE name = ?1", name)) {
var result = handler.get().findFirst(); var result = handler.get().findFirst();
return result.orElse(null); if (result.isPresent()) {
return result.get();
} else {
var tag = create();
tag.setName(name);
store(tag);
return tag;
}
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -40,6 +47,11 @@ public class TagRepositoryImpl extends AbstractRepository<Tag> implements TagRep
return search("where name IN (?1)", List.of(names)); return search("where name IN (?1)", List.of(names));
} }
@Override
public TagCollection createCollection() {
return new TagCollectionImpl();
}
@Entity @Entity
@Table(name = "Tags") @Table(name = "Tags")
@Builder @Builder
@ -58,6 +70,11 @@ public class TagRepositoryImpl extends AbstractRepository<Tag> implements TagRep
@UuidGenerator @UuidGenerator
private UUID uuid; private UUID uuid;
@Override
public String toString() {
return name;
}
@Column(nullable = false, unique = true) @Column(nullable = false, unique = true)
@JsonProperty @JsonProperty
private String name = ""; private String name = "";

View File

@ -0,0 +1,8 @@
package ru.kirillius.XCP.Persistence;
import ru.kirillius.XCP.Persistence.Entities.Tag;
import java.util.HashSet;
public class TagCollectionImpl extends HashSet<Tag> implements TagCollection {
}

View File

@ -0,0 +1,39 @@
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>> {
private final RepositoryServiceImpl repositoryService;
public TagSetDeserializer(RepositoryServiceImpl repositoryService) {
super(Set.class);
this.repositoryService = repositoryService;
}
@Override
public Set<Tag> deserialize(JsonParser p, DeserializationContext ctxt) throws JacksonException {
var result = new HashSet<Tag>();
var tagNames = p.readValueAs(String[].class);
var repository = repositoryService.getRepository(TagRepository.class);
for (var name : tagNames) {
var tag = repository.getByName(name);
result.add(tag);
}
return result;
}
}

View File

@ -0,0 +1,30 @@
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

@ -77,7 +77,7 @@ abstract class GenericRepositoryTest<E extends PersistenceEntity, R extends Abst
var repository = service.getRepositoryForEntity(entityClass); var repository = service.getRepositoryForEntity(entityClass);
var entity = repository.create(); var entity = repository.create();
repository.store(entity); repository.store(entity);
modify(entity); modify(entity,service);
repository.store(entity); repository.store(entity);
var loaded = repository.load(entity.getId()); var loaded = repository.load(entity.getId());
assertThat(loaded).isNotNull().isEqualTo(entity); assertThat(loaded).isNotNull().isEqualTo(entity);
@ -107,8 +107,18 @@ abstract class GenericRepositoryTest<E extends PersistenceEntity, R extends Abst
var deserialized = repository.deserialize(serialized); var deserialized = repository.deserialize(serialized);
assertThat(deserialized).isNotNull().isEqualTo(entity); assertThat(deserialized).isNotNull().isEqualTo(entity);
var anotherEntity = repository.create();
modify(anotherEntity,service);
repository.store(anotherEntity);
var anotherSerialized = repository.serialize(anotherEntity);
assertThat(anotherSerialized.toString()).isNotEqualTo(serialized.toString());
var anotherDeserialized = repository.deserialize(anotherSerialized);
assertThat(anotherDeserialized).isNotNull().isEqualTo(anotherEntity).isNotEqualTo(entity);
} }
} }
protected abstract void modify(E entity); protected abstract void modify(E entity, RepositoryService service);
} }

View File

@ -1,11 +1,15 @@
package ru.kirillius.XCP.Persistence.Repositories; package ru.kirillius.XCP.Persistence.Repositories;
import org.junit.jupiter.api.Test; 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.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.RepositoryService;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -15,7 +19,14 @@ import static ru.kirillius.XCP.Persistence.TestEnvironment.instantiateTestServic
class GroupRepositoryImplTest extends GenericRepositoryTest<Group, GroupRepositoryImpl> { class GroupRepositoryImplTest extends GenericRepositoryTest<Group, GroupRepositoryImpl> {
@Override @Override
protected RepositoryService spawnRepositoryService() { protected RepositoryService spawnRepositoryService() {
return instantiateTestService(List.of(repositoryClass, TagRepositoryImpl.class)); var service = instantiateTestService(List.of(repositoryClass, TagRepositoryImpl.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;
} }
@Test @Test
@ -117,7 +128,20 @@ class GroupRepositoryImplTest extends GenericRepositoryTest<Group, GroupReposito
} }
@Override @Override
protected void modify(Group entity) { protected void modify(Group entity, RepositoryService service) {
entity.setName(UUID.randomUUID().toString()); entity.setName(UUID.randomUUID().toString());
var groupRepository = service.getRepository(GroupRepository.class);
var root = groupRepository.getRoot();
if (root != null && !root.equals(entity)) {
entity.setParent(root);
}
try (var handler = service.getRepositoryForEntity(Tag.class).loadAll()) {
entity.setTags(new HashSet<>(handler.get().toList()));
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
} }

View File

@ -2,6 +2,7 @@ package ru.kirillius.XCP.Persistence.Repositories;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import ru.kirillius.XCP.Persistence.Entities.Tag; import ru.kirillius.XCP.Persistence.Entities.Tag;
import ru.kirillius.XCP.Persistence.RepositoryService;
import java.io.IOException; import java.io.IOException;
@ -21,7 +22,7 @@ class TagRepositoryImplTest extends GenericRepositoryTest<Tag, TagRepositoryImpl
} }
@Override @Override
protected void modify(Tag entity) { protected void modify(Tag entity, RepositoryService service) {
entity.setName("test" + Math.random()); entity.setName("test" + Math.random());
} }
} }

View File

@ -2,6 +2,7 @@ package ru.kirillius.XCP.Persistence.Repositories;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import ru.kirillius.XCP.Persistence.Entities.User; import ru.kirillius.XCP.Persistence.Entities.User;
import ru.kirillius.XCP.Persistence.RepositoryService;
import java.io.IOException; import java.io.IOException;
import java.util.UUID; import java.util.UUID;
@ -48,7 +49,7 @@ class UserRepositoryImplTest extends GenericRepositoryTest<User, UserRepositoryI
} }
@Override @Override
protected void modify(User entity) { protected void modify(User entity, RepositoryService service) {
entity.setName("test" + UUID.randomUUID()); entity.setName("test" + UUID.randomUUID());
} }
} }