Skip to content

Commit

Permalink
Meta-Annotations for @column and @CustomValueType (#50)
Browse files Browse the repository at this point in the history
  • Loading branch information
g-sg-v authored Mar 14, 2024
1 parent 6518473 commit dd9252f
Show file tree
Hide file tree
Showing 23 changed files with 293 additions and 7 deletions.
3 changes: 3 additions & 0 deletions .bazelproject
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ test_sources:
repository-ydb-v1/src/test
repository-ydb-v2/src/test
util/src/test

# Automatically includes all relevant targets under the 'directories' above
derive_targets_from_directories: true
1 change: 1 addition & 0 deletions databind/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ java_library(
visibility = ["//visibility:public"],
deps = [
"//bom:lombok",
"//util",
"@java_contribs_stable//:com_google_code_findbugs_jsr305",
"@java_contribs_stable//:com_google_guava_guava",
"@java_contribs_stable//:javax_annotation_javax_annotation_api",
Expand Down
4 changes: 4 additions & 0 deletions databind/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
</description>

<dependencies>
<dependency>
<groupId>tech.ydb.yoj</groupId>
<artifactId>yoj-util</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.RECORD_COMPONENT;
import static java.lang.annotation.ElementType.TYPE;
Expand All @@ -26,7 +27,7 @@
*/
@Inherited
@Retention(RUNTIME)
@Target({TYPE, FIELD, RECORD_COMPONENT})
@Target({TYPE, FIELD, RECORD_COMPONENT, ANNOTATION_TYPE})
@ExperimentalApi(issue = "https://github.com/ydb-platform/yoj-project/issues/24")
public @interface CustomValueType {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import tech.ydb.yoj.databind.schema.Column;
import tech.ydb.yoj.databind.schema.CustomConverterException;
import tech.ydb.yoj.databind.schema.Schema.JavaField;
import tech.ydb.yoj.util.lang.Annotations;

import javax.annotation.Nullable;
import java.lang.reflect.InvocationTargetException;
Expand Down Expand Up @@ -67,7 +68,7 @@ public static CustomValueType getCustomValueType(@NonNull Type type, @Nullable C
var cvtAnnotation = columnAnnotation == null ? null : columnAnnotation.customValueType();

var columnCvt = cvtAnnotation == null || cvtAnnotation.converter().equals(ValueConverter.NoConverter.class) ? null : cvtAnnotation;
var cvt = columnCvt == null ? rawType.getAnnotation(CustomValueType.class) : columnCvt;
var cvt = columnCvt == null ? Annotations.find(CustomValueType.class, rawType) : columnCvt;
if (cvt != null) {
var columnClass = cvt.columnClass();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package tech.ydb.yoj.databind.converter;

import tech.ydb.yoj.databind.CustomValueType;
import tech.ydb.yoj.databind.schema.Column;

import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.RECORD_COMPONENT;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
* Alias for "want-it-to-be-string" columns
* {@link StringValueConverter}
*/
@Inherited
@Retention(RUNTIME)
@Target({FIELD, RECORD_COMPONENT, ANNOTATION_TYPE})
@Column(customValueType = @CustomValueType(columnClass = String.class, converter = StringValueConverter.class))
public @interface StringColumn {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package tech.ydb.yoj.databind.converter;

import tech.ydb.yoj.databind.CustomValueType;

import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.RECORD_COMPONENT;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
* Easy to use annotation to mark type as String based
* {@link StringValueConverter}
*/
@Inherited
@Retention(RUNTIME)
@Target({TYPE, FIELD, RECORD_COMPONENT, ANNOTATION_TYPE})
@CustomValueType(columnClass = String.class, converter = StringValueConverter.class)
public @interface StringValueType {}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.RECORD_COMPONENT;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
Expand All @@ -33,7 +34,7 @@
* BigSubobject subobj2;
* </pre></blockquote>
*/
@Target({FIELD, RECORD_COMPONENT})
@Target({FIELD, RECORD_COMPONENT, ANNOTATION_TYPE})
@Retention(RUNTIME)
public @interface Column {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import tech.ydb.yoj.databind.FieldValueType;
import tech.ydb.yoj.databind.schema.Column;
import tech.ydb.yoj.databind.schema.FieldValueException;
import tech.ydb.yoj.util.lang.Annotations;

import javax.annotation.Nullable;
import java.lang.reflect.Type;
Expand Down Expand Up @@ -50,7 +51,7 @@ public KotlinDataClassComponent(Reflector reflector, String name,
Preconditions.checkArgument(field != null, "Could not get Java field for property '%s' of '%s'",
property.getName(), kPropertyType);

this.column = field.getAnnotation(Column.class);
this.column = Annotations.find(Column.class, field);
this.valueType = FieldValueType.forJavaType(genericType, column);
this.reflectType = reflector.reflectFieldType(genericType, valueType);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import tech.ydb.yoj.databind.FieldValueType;
import tech.ydb.yoj.databind.schema.Column;
import tech.ydb.yoj.databind.schema.FieldValueException;
import tech.ydb.yoj.util.lang.Annotations;

import javax.annotation.Nullable;
import java.lang.reflect.Type;
Expand Down Expand Up @@ -46,7 +47,7 @@ public PojoField(@NonNull Reflector reflector, @NonNull java.lang.reflect.Field

this.genericType = delegate.getGenericType();
this.type = delegate.getType();
this.column = delegate.getAnnotation(Column.class);
this.column = Annotations.find(Column.class, delegate);
this.valueType = FieldValueType.forJavaType(genericType, column);
this.reflectType = reflector.reflectFieldType(genericType, valueType);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import tech.ydb.yoj.databind.FieldValueType;
import tech.ydb.yoj.databind.schema.Column;
import tech.ydb.yoj.databind.schema.FieldValueException;
import tech.ydb.yoj.util.lang.Annotations;

import javax.annotation.Nullable;
import java.lang.reflect.Type;
Expand Down Expand Up @@ -40,7 +41,7 @@ public RecordField(@NonNull Reflector reflector, @NonNull java.lang.reflect.Reco
this.name = delegate.getName();
this.genericType = delegate.getGenericType();
this.type = delegate.getType();
this.column = delegate.getAnnotation(Column.class);
this.column = Annotations.find(Column.class, delegate);
this.valueType = FieldValueType.forJavaType(genericType, column);
this.reflectType = reflector.reflectFieldType(genericType, valueType);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import tech.ydb.yoj.repository.test.sample.model.Team;
import tech.ydb.yoj.repository.test.sample.model.TypeFreak;
import tech.ydb.yoj.repository.test.sample.model.UpdateFeedEntry;
import tech.ydb.yoj.repository.test.sample.model.VersionedAliasedEntity;
import tech.ydb.yoj.repository.test.sample.model.VersionedEntity;

import java.util.Set;
Expand Down Expand Up @@ -118,6 +119,10 @@ public Table<NetworkAppliance> networkAppliances() {
public Table<VersionedEntity> versionedEntities() {
return table(VersionedEntity.class);
}

public Table<VersionedAliasedEntity> versionedAliasedEntities() {
return table(VersionedAliasedEntity.class);
}
}

private static class Supabubble2InMemoryTable extends InMemoryTable<Supabubble2> implements TestEntityOperations.Supabubble2Table {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@
import tech.ydb.yoj.repository.test.sample.model.TypeFreak.Embedded;
import tech.ydb.yoj.repository.test.sample.model.UpdateFeedEntry;
import tech.ydb.yoj.repository.test.sample.model.Version;
import tech.ydb.yoj.repository.test.sample.model.VersionedAliasedEntity;
import tech.ydb.yoj.repository.test.sample.model.VersionedEntity;
import tech.ydb.yoj.repository.test.sample.model.WithUnflattenableField;
import tech.ydb.yoj.repository.test.sample.model.annotations.Sha256;

import java.time.Instant;
import java.util.ArrayList;
Expand All @@ -70,6 +72,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.Spliterator;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
Expand Down Expand Up @@ -2730,6 +2733,29 @@ public void customValueTypeInFilter() {
)).isNull();
}

@Test
public void customValueTypeInFilterByAlias() {
UUID testPrefferedUUID = UUID.randomUUID();
var ve = new VersionedAliasedEntity(new VersionedAliasedEntity.Id("heyhey", new Version(100L), testPrefferedUUID, new Sha256("100")), new Version(100_500L), testPrefferedUUID);
db.tx(() -> db.versionedAliasedEntities().insert(ve));
assertThat(db.tx(() -> db.versionedAliasedEntities().find(ve.id()))).isEqualTo(ve);
assertThat(db.tx(() -> db.versionedAliasedEntities().query()
.where("id.version").eq(ve.id().version())
.and("version2").eq(ve.version2())
.findOne()
)).isEqualTo(ve);
assertThat(db.tx(() -> db.versionedAliasedEntities().query()
.where("id.version").eq(100L)
.and("version2").eq(100_500L)
.findOne()
)).isEqualTo(ve);
assertThat(db.tx(() -> db.versionedAliasedEntities().query()
.where("id.version").eq(100L)
.and("version2").eq(null)
.findOne()
)).isNull();
}

protected void runInTx(Consumer<RepositoryTransaction> action) {
// We do not retry transactions, because we do not expect conflicts in our test scenarios.
RepositoryTransaction transaction = startTransaction();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import tech.ydb.yoj.repository.test.sample.model.Team;
import tech.ydb.yoj.repository.test.sample.model.TypeFreak;
import tech.ydb.yoj.repository.test.sample.model.UpdateFeedEntry;
import tech.ydb.yoj.repository.test.sample.model.VersionedAliasedEntity;
import tech.ydb.yoj.repository.test.sample.model.VersionedEntity;
import tech.ydb.yoj.repository.test.sample.model.WithUnflattenableField;

Expand All @@ -44,7 +45,8 @@ private TestEntities() {
WithUnflattenableField.class,
UpdateFeedEntry.class,
NetworkAppliance.class,
VersionedEntity.class
VersionedEntity.class,
VersionedAliasedEntity.class
);

@SuppressWarnings("unchecked")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import tech.ydb.yoj.repository.test.sample.model.Team;
import tech.ydb.yoj.repository.test.sample.model.TypeFreak;
import tech.ydb.yoj.repository.test.sample.model.UpdateFeedEntry;
import tech.ydb.yoj.repository.test.sample.model.VersionedAliasedEntity;
import tech.ydb.yoj.repository.test.sample.model.VersionedEntity;

import java.util.ArrayList;
Expand Down Expand Up @@ -66,6 +67,8 @@ default Table<BytePkEntity> bytePkEntities() {

Table<VersionedEntity> versionedEntities();

Table<VersionedAliasedEntity> versionedAliasedEntities();

class ProjectTable extends AbstractDelegatingTable<Project> {
public ProjectTable(Table<Project> target) {
super(target);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package tech.ydb.yoj.repository.test.sample.model;

import tech.ydb.yoj.databind.CustomValueType;
import tech.ydb.yoj.databind.schema.Column;

import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.RECORD_COMPONENT;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Inherited
@Retention(RUNTIME)
@Target({FIELD, RECORD_COMPONENT, ANNOTATION_TYPE})
@Column(customValueType = @CustomValueType(columnClass = Long.class, converter = Version.Converter.class))
public @interface VersionColumn {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package tech.ydb.yoj.repository.test.sample.model;

import tech.ydb.yoj.databind.converter.StringColumn;
import tech.ydb.yoj.repository.db.Entity;
import tech.ydb.yoj.repository.db.RecordEntity;
import tech.ydb.yoj.repository.test.sample.model.annotations.Sha256;

import java.util.UUID;

public record VersionedAliasedEntity(
Id id,
@VersionColumn
Version version2,
@StringColumn
UUID uuid
) implements RecordEntity<VersionedAliasedEntity> {
public record Id(
String value,
@VersionColumn
Version version,
@StringColumn
UUID uuidId,
Sha256 hash
) implements Entity.Id<VersionedAliasedEntity> {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package tech.ydb.yoj.repository.test.sample.model.annotations;

import java.util.Objects;


public class Digest implements YojString {
private final String algorithm;
private final String digest;

protected Digest(String algorithm, String digest) {
this.algorithm = algorithm;
this.digest = digest;
}

@Override
public String toString() {
return algorithm + ":" + digest;
}

@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (object == null || getClass() != object.getClass()) {
return false;
}
Digest digest1 = (Digest) object;
return Objects.equals(algorithm, digest1.algorithm) && Objects.equals(digest, digest1.digest);
}

@Override
public int hashCode() {
return Objects.hash(algorithm, digest);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package tech.ydb.yoj.repository.test.sample.model.annotations;

public class Sha256 extends Digest {
private static final String SHA_256 = "SHA256";

public Sha256(String digest) {
super(SHA_256, digest);
}

public static Sha256 valueOf(String value) {
String[] parsed = value.split(":");
if (parsed.length != 2 || !SHA_256.equals(parsed[0])) {
throw new IllegalArgumentException();
}
return new Sha256(parsed[1]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package tech.ydb.yoj.repository.test.sample.model.annotations;

import tech.ydb.yoj.databind.converter.StringValueType;

@StringValueType
public interface YojString {
}
Loading

0 comments on commit dd9252f

Please sign in to comment.