io.permazen.annotation.PermazenCompositeIndex Maven / Gradle / Ivy
Show all versions of permazen-main Show documentation
/*
* Copyright (C) 2015 Archie L. Cobbs. All rights reserved.
*/
package io.permazen.annotation;
import io.permazen.PermazenObject;
import io.permazen.UniquenessConstraints;
import jakarta.validation.groups.Default;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Java annotation that defines a composite index.
*
*
* A composite index is an index on two or more fields (to define a single-field index, see {@link PermazenField#indexed}).
* All fields participating in a composite index must be (a) simple and (b) not a sub-field of a complex field.
*
*
* The class or interface does not have to be {@link PermazenType @PermazenType}-annotated; annotations
* are "inherited" and so apply to all {@link PermazenType @PermazenType}-annotated sub-types.
*
*
* {@link PermazenCompositeIndex @PermazenCompositeIndex} is a {@linkplain Repeatable repeatable annotation}.
*
*
Uniqueness Constraints
*
* Uniqueness constraints are supported, and their enforcement is handled in the same way as for uniqueness constraints
* on simply indexed fields (see {@link PermazenField#unique @PermazenField.unique()}). A uniqueness constriant on a composite
* index means each combination of field values must be unique to a single object. Specific field value combinations may be
* excluded from the uniqueness constraint by specifying the corresponding comma-separated {@link String}-encoded tuples
* in {@link #uniqueExcludes}.
*
* @see PermazenType
* @see PermazenField#indexed
*/
@Repeatable(PermazenCompositeIndexes.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE })
@Documented
public @interface PermazenCompositeIndex {
/**
* The name of this index.
*
*
* The name must be unique among all other indexes and simple fields in a Java model type.
*
* @return the index name
*/
String name();
/**
* Storage ID for this index.
*
*
* Normally this value is left as zero, in which case a value will be automatically assigned.
*
*
* Otherwise, the value should be positive and unique within the schema.
*
* @return this index's storage ID, or zero for automatic assignment
*/
int storageId() default 0;
/**
* The names of the indexed fields, in the desired order. At least two fields must be specified.
*
* @return the names of the indexed fields
*/
String[] fields();
/**
* Require each object's field combination to be unique among all types to which this annotation applies.
*
*
* This property creates an implicit uniqueness validation constraint.
*
*
* The constraint will be checked any time normal validation is performed on an object.
* More precisely, a uniqueness constraint behaves like a JSR 303
* validation constraint with {@code groups() = }{
{@link Default}{@code .class,
* }{@link UniquenessConstraints}{@code .class} }
. Therefore, uniqueness constraints
* are included in default validation, but you can also validate only uniqueness constraints via
* {@link PermazenObject#revalidate myobj.revalidate(UniquenessConstraints.class)}.
*
* @return whether the composite index's field values should be unique
* @see #uniqueExcludes
* @see UniquenessConstraints
*/
boolean unique() default false;
/**
* Specify field value combinations to be excluded from the uniqueness constraint.
*
*
* The annotation value is a list of {@link ValuesList @ValuesList} annotations, each of which describes some
* combination of field values that should grant the containing object exclusion from the uniqueness constraint.
*
*
* Each {@link ValuesList @ValuesList} contains a list of {@link Values @Values} annotations, one for each field
* in the index. For an object to be excluded from the uniqueness constraint, the object's fields' values must all
* match their corresponding {@link Values @Values} annotation in at least one of the
* {@link ValuesList @ValuesList} annotations.
*
*
* For example, consider this class:
*
* public abstract class Person {
*
* public abstract String getName();
* public abstract void setName(String x);
*
* public abstract int getId();
* public abstract void setId(int x);
* }
*
*
*
* To require a {@code Person}'s name and ID combination to be unique, but exclude
* {@code Person}'s whose name is null and whose ID is equal to -1 or -2:
*
*
* @PermazenType(compositeIndexes =
* @PermazenCompositeIndex(name = "nameAndId", fields = { "name", "id" },
* unique = true,
* uniqueExcludes = @ValuesList({ @Values(nulls = true), @Values({ "-1", "-2" }) })
* ))))
* public abstract class Person {
* ...
* }
*
*
*
* To require a {@code Person}'s name and ID combination to be unique, but exclude
* {@code Person}'s whose name is null or whose ID is equal to -1 or -2:
*
*
* @PermazenType(compositeIndexes =
* @PermazenCompositeIndex(name = "nameAndId", fields = { "name", "id" },
* unique = true,
* uniqueExcludes = {
* @ValuesList({ @Values(nulls = true), @Values(nonNulls = true) }),
* @ValuesList({ @Values(nulls = true, nonNulls = true), @Values({ "-1", "-2" }) })
* }))))
* public abstract class Person {
* ...
* }
*
*
*
* Notes:
*
* - To match all possible values for a field, use {@link Values @Values}{@code (nulls = true, nonNulls = true)}
*
- For primitive fields, {@link Values#nulls @Values.nulls()} is not relevant.
*
*
*
* It is an error if, for any {@link ValuesList @ValuesList}, every possible field combination
* would match, as this would pointlessly exclude every object.
*
*
* This property must be left empty when {@link #unique} is false.
*
* @return field value combinations to exclude from the uniqueness constraint
* @see #unique
*/
ValuesList[] uniqueExcludes() default {};
}