Skip to content

Commit

Permalink
feat: implement ModelToSchemeCollectionConverter
Browse files Browse the repository at this point in the history
Signed-off-by: sepgh <13250403+sepgh@users.noreply.github.com>
  • Loading branch information
sepgh committed Nov 12, 2024
1 parent 5af2cb1 commit 8f7033c
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package com.github.sepgh.testudo.scheme;

import com.github.sepgh.testudo.scheme.annotation.AutoIncrement;
import com.github.sepgh.testudo.scheme.annotation.Collection;
import com.github.sepgh.testudo.scheme.annotation.Field;
import com.github.sepgh.testudo.scheme.annotation.Index;
import com.github.sepgh.testudo.serialization.SerializerRegistry;

import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Stream;

public class ModelToSchemeCollectionConverter {

private final Class<?> modelClass;

public ModelToSchemeCollectionConverter(Class<?> modelClass) {
this.modelClass = modelClass;
}

public Scheme.Collection toCollection() {
Scheme.Collection collection = this.extractCollection();
List<Scheme.Field> fields = this.extractFields();
fields.sort(Comparator.comparingInt(Scheme.Field::getId));
collection.setFields(fields);
return collection;
}

private List<Scheme.Field> extractFields() {
Stream<java.lang.reflect.Field> stream = Arrays.stream(this.modelClass.getDeclaredFields())
.filter(field -> Modifier.isPrivate(field.getModifiers()))
.filter(f -> f.isAnnotationPresent(Field.class));

List<Scheme.Field> fields = new ArrayList<>();
stream.forEach(field -> {
Optional<Scheme.Field> optional = this.getSchemeField(field);
optional.ifPresent(fields::add);
});

return fields;
}

private Scheme.Collection extractCollection() {
Optional<Annotation> collectionOptional = Arrays.stream(modelClass.getAnnotations())
.filter(annotation -> annotation.annotationType().equals(Collection.class))
.findFirst();

if (collectionOptional.isEmpty()) {
// Todo: err
}

Collection collection = (Collection) collectionOptional.get();
return Scheme.Collection.builder()
.id(collection.id())
.name(collection.name())
.build();
}

private Optional<Scheme.Field> getSchemeField(final java.lang.reflect.Field field) {
Field fieldAnnotation = field.getAnnotation(Field.class);
Scheme.Field schemeField = Scheme.Field.builder()
.id(fieldAnnotation.id())
.type(getFieldType(field, fieldAnnotation))
.name(fieldAnnotation.name())
.nullable(fieldAnnotation.nullable())
.defaultValue(fieldAnnotation.defaultValue())
.meta(Scheme.Meta.builder()
.charset(fieldAnnotation.charset())
.comment(fieldAnnotation.comment())
.maxLength(fieldAnnotation.maxLength())
.build())
.build();

List<Annotation> objFieldAnnotations = Arrays.asList(field.getAnnotations());

Optional<Annotation> indexAnnotationOptional = objFieldAnnotations.stream().filter(annotation -> annotation.annotationType().equals(Index.class)).findFirst();
if (indexAnnotationOptional.isEmpty())
return Optional.of(schemeField);

Index index = (Index) indexAnnotationOptional.get();

schemeField.setIndex(index.enable());
schemeField.setIndexUnique(index.unique());
schemeField.setPrimary(index.primary());
schemeField.setLowCardinality(index.lowCardinality());
schemeField.setAutoIncrement(objFieldAnnotations.stream().anyMatch(annotation -> annotation.annotationType().equals(AutoIncrement.class)));

return Optional.of(schemeField);
}

private String getFieldType(final java.lang.reflect.Field field, Field fieldAnnotation) {
if (fieldAnnotation.type().isEmpty()) {
Optional<String> optional = SerializerRegistry.getInstance().getTypeOfClass(field.getType());
if (optional.isPresent()) {
return optional.get();
}
throw new RuntimeException("Can't find a default field type for class " + field.getType().getTypeName()); // todo
}

final String annotatedType = fieldAnnotation.type();
Class<?> type = SerializerRegistry.getInstance().getSerializer(annotatedType).getType();

if (type.equals(field.getType())) {
return annotatedType;
} else {
throw new RuntimeException("Annotated type '%s' is not compatible with field type '%s'".formatted(annotatedType, field.getType().getTypeName())); // Todo
}
}


}
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
package com.github.sepgh.testudo.scheme.annotation;

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.FIELD)
public @interface AutoIncrement {
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
package com.github.sepgh.testudo.scheme.annotation;

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 Collection {
int id();
String name() default "";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
package com.github.sepgh.testudo.scheme.annotation;

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.FIELD)
public @interface Field {
int id();
String name() default "";
String type() default "";
boolean nullable() default false;
String defaultValue() default "";

// Meta
String comment() default "";
String defaultValue() default "";
int maxLength() default -1;
String charset() default "UTF-8";
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
package com.github.sepgh.testudo.scheme.annotation;

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.FIELD)
public @interface Index {
boolean enable() default true;
boolean unique() default false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,19 @@ public static int getSizeOfCollection(Scheme.Collection collection) {
return size;
}

public static void setValueOfField(Scheme.Collection after, Scheme.Field field, byte[] obj, @Nullable byte[] bytes) throws SerializationException {
int offset = getByteArrOffsetTillFieldIndex(after.getFields(), after.getFields().indexOf(field));
public static void setValueOfField(Scheme.Collection collection, Scheme.Field field, byte[] obj, @Nullable byte[] value) throws SerializationException {
int offset = getByteArrOffsetTillFieldIndex(collection.getFields(), collection.getFields().indexOf(field));
int size = getByteArrSizeOfField(field);
if (bytes != null) {
if (bytes.length > size) {
System.arraycopy(bytes, 0, bytes, 0, size);
if (value != null) {
if (value.length > size) {
System.arraycopy(value, 0, value, 0, size);
}
} else {
Serializer<?> serializer = SerializerRegistry.getInstance().getSerializer(field.getType());
assert serializer != null;
bytes = serializer.serializeDefault(field.getDefaultValue(), field.getMeta());
value = serializer.serializeDefault(field.getDefaultValue(), field.getMeta());
}

System.arraycopy(bytes, 0, obj, offset, bytes.length);
System.arraycopy(value, 0, obj, offset, value.length);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class SerializerRegistry {
private static final SerializerRegistry INSTANCE = new SerializerRegistry();
Expand Down Expand Up @@ -41,4 +42,9 @@ public Serializer<?> getSerializer(String type){
return serializers.stream().filter(serializer -> serializer.typeName().equals(type)).findFirst().orElse(null);
}

public Optional<String> getTypeOfClass(Class<?> clazz){
Optional<Serializer<?>> optional = serializers.stream().filter(serializer -> serializer.getType().equals(clazz)).findFirst();
return optional.map(Serializer::typeName);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.github.sepgh.test.scheme;

import com.github.sepgh.testudo.scheme.ModelToSchemeCollectionConverter;
import com.github.sepgh.testudo.scheme.Scheme;
import com.github.sepgh.testudo.scheme.annotation.AutoIncrement;
import com.github.sepgh.testudo.scheme.annotation.Collection;
import com.github.sepgh.testudo.scheme.annotation.Field;
import com.github.sepgh.testudo.scheme.annotation.Index;
import lombok.Getter;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.List;

public class ModelToSchemeCollectionConverterTestCase {

@Getter
@Collection(id = 1, name = "test")
public static class TestModel {
@Field(id = 1)
@AutoIncrement
@Index(primary = true)
private int id;

@Field(id = 2)
private String name;

@Field(id = 3)
@Index()
private long age;

@Field(id = 4)
@Index(lowCardinality = true)
private String country;
}


@Test
public void convert() {
ModelToSchemeCollectionConverter converter = new ModelToSchemeCollectionConverter(TestModel.class);
Scheme.Collection collection = converter.toCollection();

Assertions.assertEquals(1, collection.getId());
Assertions.assertEquals("test", collection.getName());

List<Scheme.Field> fields = collection.getFields();
Assertions.assertEquals(4, fields.size());

Scheme.Field field = fields.getFirst();
Assertions.assertEquals(1, field.getId());
Assertions.assertEquals("int", field.getType());

field = fields.get(1);
Assertions.assertEquals(2, field.getId());
Assertions.assertEquals("char", field.getType());

field = fields.get(2);
Assertions.assertEquals(3, field.getId());
Assertions.assertEquals("long", field.getType());

field = fields.get(3);
Assertions.assertEquals(4, field.getId());
Assertions.assertEquals("char", field.getType());


}

}

0 comments on commit 8f7033c

Please sign in to comment.