From a79e7dacf100ec8c0b18f147bab3ecc0fc1225d3 Mon Sep 17 00:00:00 2001 From: Greg Burd Date: Mon, 6 Nov 2017 13:49:34 -0500 Subject: [PATCH] Cache data from MaterializedViews under their parent name. Add some relationship constraints that can decorate getters in model classes and be used in some cases to better cache data. --- .../net/helenus/core/cache/CacheUtil.java | 1 + .../core/operation/InsertOperation.java | 2 + .../helenus/mapping/HelenusMappingEntity.java | 10 +- .../mapping/annotation/Constraints.java | 92 +++++++++++++++++++ .../AbstractConstraintValidator.java | 34 +++++++ .../mapping/validator/DistinctValidator.java | 9 +- .../ManyToManyRelationshipValidator.java | 33 +++++++ .../ManyToOneRelationshipValidator.java | 33 +++++++ .../OneToManyRelationshipValidator.java | 33 +++++++ .../OneToOneRelationshipValidator.java | 33 +++++++ .../validator/RelationshipValidator.java | 35 +++++++ .../core/views/MaterializedViewTest.java | 31 +++++++ 12 files changed, 337 insertions(+), 9 deletions(-) create mode 100644 src/main/java/net/helenus/mapping/validator/AbstractConstraintValidator.java create mode 100644 src/main/java/net/helenus/mapping/validator/ManyToManyRelationshipValidator.java create mode 100644 src/main/java/net/helenus/mapping/validator/ManyToOneRelationshipValidator.java create mode 100644 src/main/java/net/helenus/mapping/validator/OneToManyRelationshipValidator.java create mode 100644 src/main/java/net/helenus/mapping/validator/OneToOneRelationshipValidator.java create mode 100644 src/main/java/net/helenus/mapping/validator/RelationshipValidator.java diff --git a/src/main/java/net/helenus/core/cache/CacheUtil.java b/src/main/java/net/helenus/core/cache/CacheUtil.java index a2c2e9f..a3ec916 100644 --- a/src/main/java/net/helenus/core/cache/CacheUtil.java +++ b/src/main/java/net/helenus/core/cache/CacheUtil.java @@ -45,6 +45,7 @@ public class CacheUtil { } public static Object merge(Object to, Object from) { + // TODO(gburd): do a proper merge given that materialized views are cached with their table name if (to == from) { return to; } else { diff --git a/src/main/java/net/helenus/core/operation/InsertOperation.java b/src/main/java/net/helenus/core/operation/InsertOperation.java index 3d88eb7..229ca60 100644 --- a/src/main/java/net/helenus/core/operation/InsertOperation.java +++ b/src/main/java/net/helenus/core/operation/InsertOperation.java @@ -156,6 +156,8 @@ public final class InsertOperation extends AbstractOperation primaryKeyProperties = new ArrayList<>(); ImmutableList.Builder facetsBuilder = ImmutableList.builder(); - facetsBuilder.add(new Facet("table", name.toCql()).setFixed()); + if (iface.getDeclaredAnnotation(MaterializedView.class) == null) { + facetsBuilder.add(new Facet("table", name.toCql()).setFixed()); + } else { + facetsBuilder.add( + new Facet("table", Helenus.entity(iface.getInterfaces()[0]).getName().toCql()) + .setFixed()); + } for (HelenusProperty prop : orderedProps) { switch (prop.getColumnType()) { case PARTITION_KEY: @@ -130,7 +136,7 @@ public final class HelenusMappingEntity implements HelenusEntity { MappingUtil.getValidators(prop.getGetterMethod())) { if (constraint.getClass().isAssignableFrom(DistinctValidator.class)) { DistinctValidator validator = (DistinctValidator) constraint; - String[] values = validator.value(); + String[] values = validator.constraintAnnotation.value(); UnboundFacet facet; if (values != null && values.length >= 1 && !(StringUtils.isBlank(values[0]))) { List props = new ArrayList(values.length + 1); diff --git a/src/main/java/net/helenus/mapping/annotation/Constraints.java b/src/main/java/net/helenus/mapping/annotation/Constraints.java index 22ffbdc..5c90d9d 100644 --- a/src/main/java/net/helenus/mapping/annotation/Constraints.java +++ b/src/main/java/net/helenus/mapping/annotation/Constraints.java @@ -235,4 +235,96 @@ public final class Constraints { */ String[] value() default ""; } + + /** + * Distinct annotation is used to signal, but not ensure that a value should be distinct in the + * database. + * + *

Can be used only for @java.lang.CharSequence + * + *

It does not have effect on selects and data retrieval operations + */ + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) + @Constraint(validatedBy = OneToOneRelationshipValidator.class) + public @interface OneToOne { + + /** + * User defined list of properties that combine with this one to result in a distinct + * combination in the table. + * + * @return Java + */ + String[] value() default ""; + } + + /** + * Distinct annotation is used to signal, but not ensure that a value should be distinct in the + * database. + * + *

Can be used only for @java.lang.CharSequence + * + *

It does not have effect on selects and data retrieval operations + */ + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) + @Constraint(validatedBy = OneToManyRelationshipValidator.class) + public @interface OneToMany { + + /** + * User defined list of properties that combine with this one to result in a distinct + * combination in the table. + * + * @return Java + */ + String[] value() default ""; + } + + /** + * Distinct annotation is used to signal, but not ensure that a value should be distinct in the + * database. + * + *

Can be used only for @java.lang.CharSequence + * + *

It does not have effect on selects and data retrieval operations + */ + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) + @Constraint(validatedBy = ManyToOneRelationshipValidator.class) + public @interface ManyToOne { + + /** + * User defined list of properties that combine with this one to result in a distinct + * combination in the table. + * + * @return Java + */ + String[] value() default ""; + } + + /** + * Distinct annotation is used to signal, but not ensure that a value should be distinct in the + * database. + * + *

Can be used only for @java.lang.CharSequence + * + *

It does not have effect on selects and data retrieval operations + */ + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) + @Constraint(validatedBy = ManyToManyRelationshipValidator.class) + public @interface ManyToMany { + + /** + * User defined list of properties that combine with this one to result in a distinct + * combination in the table. + * + * @return Java + */ + String[] value() default ""; + } } diff --git a/src/main/java/net/helenus/mapping/validator/AbstractConstraintValidator.java b/src/main/java/net/helenus/mapping/validator/AbstractConstraintValidator.java new file mode 100644 index 0000000..b56b05b --- /dev/null +++ b/src/main/java/net/helenus/mapping/validator/AbstractConstraintValidator.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2015 The Helenus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.helenus.mapping.validator; + +import java.lang.annotation.Annotation; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +public abstract class AbstractConstraintValidator + implements ConstraintValidator { + + public A constraintAnnotation; + + @Override + public void initialize(A constraintAnnotation) { + this.constraintAnnotation = constraintAnnotation; + } + + @Override + public abstract boolean isValid(T value, ConstraintValidatorContext context); +} diff --git a/src/main/java/net/helenus/mapping/validator/DistinctValidator.java b/src/main/java/net/helenus/mapping/validator/DistinctValidator.java index 40c30d7..459ecda 100644 --- a/src/main/java/net/helenus/mapping/validator/DistinctValidator.java +++ b/src/main/java/net/helenus/mapping/validator/DistinctValidator.java @@ -20,13 +20,12 @@ import javax.validation.ConstraintValidatorContext; import net.helenus.mapping.annotation.Constraints; public final class DistinctValidator + extends AbstractConstraintValidator implements ConstraintValidator { - private Constraints.Distinct annotation; - @Override public void initialize(Constraints.Distinct constraintAnnotation) { - annotation = constraintAnnotation; + super.initialize(constraintAnnotation); } @Override @@ -34,8 +33,4 @@ public final class DistinctValidator // TODO(gburd): check that the list contains valid property names. return true; } - - public String[] value() { - return annotation == null ? null : annotation.value(); - } } diff --git a/src/main/java/net/helenus/mapping/validator/ManyToManyRelationshipValidator.java b/src/main/java/net/helenus/mapping/validator/ManyToManyRelationshipValidator.java new file mode 100644 index 0000000..1757fda --- /dev/null +++ b/src/main/java/net/helenus/mapping/validator/ManyToManyRelationshipValidator.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 The Helenus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.helenus.mapping.validator; + +import javax.validation.ConstraintValidatorContext; +import net.helenus.mapping.annotation.Constraints; + +public class ManyToManyRelationshipValidator extends RelationshipValidator { + + @Override + public void initialize(Constraints.ManyToMany constraintAnnotation) { + super.initialize(constraintAnnotation); + } + + @Override + public boolean isValid(CharSequence value, ConstraintValidatorContext context) { + // TODO(gburd): check that the list contains valid property names. + return true; + } +} diff --git a/src/main/java/net/helenus/mapping/validator/ManyToOneRelationshipValidator.java b/src/main/java/net/helenus/mapping/validator/ManyToOneRelationshipValidator.java new file mode 100644 index 0000000..bc40ec7 --- /dev/null +++ b/src/main/java/net/helenus/mapping/validator/ManyToOneRelationshipValidator.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 The Helenus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.helenus.mapping.validator; + +import javax.validation.ConstraintValidatorContext; +import net.helenus.mapping.annotation.Constraints; + +public class ManyToOneRelationshipValidator extends RelationshipValidator { + + @Override + public void initialize(Constraints.ManyToOne constraintAnnotation) { + super.initialize(constraintAnnotation); + } + + @Override + public boolean isValid(CharSequence value, ConstraintValidatorContext context) { + // TODO(gburd): check that the list contains valid property names. + return true; + } +} diff --git a/src/main/java/net/helenus/mapping/validator/OneToManyRelationshipValidator.java b/src/main/java/net/helenus/mapping/validator/OneToManyRelationshipValidator.java new file mode 100644 index 0000000..9a76cfd --- /dev/null +++ b/src/main/java/net/helenus/mapping/validator/OneToManyRelationshipValidator.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 The Helenus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.helenus.mapping.validator; + +import javax.validation.ConstraintValidatorContext; +import net.helenus.mapping.annotation.Constraints; + +public class OneToManyRelationshipValidator extends RelationshipValidator { + + @Override + public void initialize(Constraints.OneToMany constraintAnnotation) { + super.initialize(constraintAnnotation); + } + + @Override + public boolean isValid(CharSequence value, ConstraintValidatorContext context) { + // TODO(gburd): check that the list contains valid property names. + return true; + } +} diff --git a/src/main/java/net/helenus/mapping/validator/OneToOneRelationshipValidator.java b/src/main/java/net/helenus/mapping/validator/OneToOneRelationshipValidator.java new file mode 100644 index 0000000..918b584 --- /dev/null +++ b/src/main/java/net/helenus/mapping/validator/OneToOneRelationshipValidator.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 The Helenus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.helenus.mapping.validator; + +import javax.validation.ConstraintValidatorContext; +import net.helenus.mapping.annotation.Constraints; + +public class OneToOneRelationshipValidator extends RelationshipValidator { + + @Override + public void initialize(Constraints.OneToOne constraintAnnotation) { + super.initialize(constraintAnnotation); + } + + @Override + public boolean isValid(CharSequence value, ConstraintValidatorContext context) { + // TODO(gburd): check that the list contains valid property names. + return true; + } +} diff --git a/src/main/java/net/helenus/mapping/validator/RelationshipValidator.java b/src/main/java/net/helenus/mapping/validator/RelationshipValidator.java new file mode 100644 index 0000000..36aa54e --- /dev/null +++ b/src/main/java/net/helenus/mapping/validator/RelationshipValidator.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2015 The Helenus Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.helenus.mapping.validator; + +import java.lang.annotation.Annotation; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +public abstract class RelationshipValidator + extends AbstractConstraintValidator + implements ConstraintValidator { + + @Override + public void initialize(A constraintAnnotation) { + super.initialize(constraintAnnotation); + } + + @Override + public boolean isValid(CharSequence value, ConstraintValidatorContext context) { + return false; + } +} diff --git a/src/test/java/net/helenus/test/integration/core/views/MaterializedViewTest.java b/src/test/java/net/helenus/test/integration/core/views/MaterializedViewTest.java index cfd3b7f..dd6b514 100644 --- a/src/test/java/net/helenus/test/integration/core/views/MaterializedViewTest.java +++ b/src/test/java/net/helenus/test/integration/core/views/MaterializedViewTest.java @@ -22,9 +22,12 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.UUID; import java.util.concurrent.TimeoutException; +import net.helenus.core.ConflictingUnitOfWorkException; import net.helenus.core.Helenus; import net.helenus.core.HelenusSession; +import net.helenus.core.UnitOfWork; import net.helenus.test.integration.build.AbstractEmbeddedCassandraTest; +import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -78,6 +81,34 @@ public class MaterializedViewTest extends AbstractEmbeddedCassandraTest { .from(CyclistsByAge.class) .where(cyclist::age, eq(18)) .allowFiltering() + .single() .sync(); } + + @Test + public void testMvUnitOfWork() + throws TimeoutException, ConflictingUnitOfWorkException, Exception { + Cyclist c1, c2; + + UnitOfWork uow = session.begin(); + c1 = + session + .select(Cyclist.class) + .from(CyclistsByAge.class) + .where(cyclist::age, eq(18)) + .single() + .sync(uow) + .orElse(null); + + c2 = + session + .select(Cyclist.class) + .from(CyclistsByAge.class) + .where(cyclist::age, eq(18)) + .single() + .sync(uow) + .orElse(null); + Assert.assertEquals(c1, c2); + uow.commit(); + } }