diff --git a/src/main/java/com/noorq/casser/mapping/annotation/ClusteringColumn.java b/src/main/java/com/noorq/casser/mapping/annotation/ClusteringColumn.java index eabd118..a433702 100644 --- a/src/main/java/com/noorq/casser/mapping/annotation/ClusteringColumn.java +++ b/src/main/java/com/noorq/casser/mapping/annotation/ClusteringColumn.java @@ -22,16 +22,94 @@ import java.lang.annotation.Target; import com.noorq.casser.mapping.OrderingDirection; +/** + * @ClusteringColumn is the family column in legacy Cassandra API + * + * The purpose of this column is have additional dimension in the table. + * Both @PartitionKey and @ClusteringColumn together are parts of the primary key of the table. + * The primary difference between them is that the first one is using for routing purposes + * in order to locate a data node in the cluster, otherwise the second one is using + * inside the node to locate peace of data in concrete machine. + * + * ClusteringColumn can be represented as a Key in SortedMap that fully stored in a single node. + * All developers must be careful for selecting fields for clustering columns, because all data + * inside this SortedMap must fit in to one node. + * + * ClusteringColumn can have more than one part and the order of parts is important. + * This order defines the way how Cassandra joins the parts and influence of data retrieval + * operations. Each part can have ordering property that defines default ascending or descending order + * of data. In case of two and more parts in select queries developer needs to have consisdent + * order of all parts as they defined in table. + * + * For example, first part is ASC ordering, second is also ASC, so Cassandra will sort entries like this: + * a-a + * a-b + * b-a + * b-b + * In this case we are able run queries: + * ORDER BY first ASC, second ASC + * ORDER BY first DESC, second DESC + * WHERE first=? ORDER BY second ASC + * WHERE first=? ORDER BY second DESC + * WHERE first=? AND second=? + * + * But, we can not run queries: + * ORDER BY first DESC, second ASC + * ORDER BY first ASC, second DESC + * WHERE second=? ORDER BY first (ASC,DESC) + * + * @author Albert Shift + * + */ + @Retention(value = RetentionPolicy.RUNTIME) @Target(value = { ElementType.METHOD, ElementType.ANNOTATION_TYPE }) public @interface ClusteringColumn { + /** + * Default value is the name of the method normalized to underscore + * + * @return name of the column + */ + String value() default ""; + /** + * ClusteringColumn parts must be ordered in the @Table. It is the requirement of Cassandra. + * Cassandra joins all parts to the final clustering key that is stored in column family name. + * Additionally all parts can have some ordering (ASC, DESC) that with sequence of parts + * determines key comparison function, so Cassandra storing column family names always in sorted order. + * + * Be default ordinal has 0 value, that's because in most cases @Table have single column for ClusteringColumn + * If you have 2 and more parts of the ClusteringColumn, then you need to use ordinal() to + * define the sequence of the parts + * + * @return number that used to sort clustering columns + */ + int ordinal() default 0; + /** + * Default order of values in the ClusteringColumn + * This ordering is using for comparison of the clustering column values when Cassandra stores it in the + * sorted order. + * + * Default value is the ascending order + * + * @return ascending order or descending order of clustering column values + */ + OrderingDirection ordering() default OrderingDirection.ASC; + /** + * For reserved words in Cassandra we need quotation in CQL queries. This property marks that + * the name of the UDT type needs to be quoted. + * + * Default value is false, we are quoting only selected names. + * + * @return true if name have to be quoted + */ + boolean forceQuote() default false; } diff --git a/src/main/java/com/noorq/casser/mapping/annotation/Column.java b/src/main/java/com/noorq/casser/mapping/annotation/Column.java index 6af508c..58e6a88 100644 --- a/src/main/java/com/noorq/casser/mapping/annotation/Column.java +++ b/src/main/java/com/noorq/casser/mapping/annotation/Column.java @@ -21,15 +21,53 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Column annotation is used to define additional properties of the column + * in entity mapping interfaces: @Table, @UDT, @Tuple + * + * Column annotation can be used to override default name of the column or to + * setup order of the columns in the mapping + * + * Usually for @Table and @UDT types it is not important to define order of the + * columns, but in @Tuple mapping it is required, because tuple itself represents the + * sequence of the types with particular order in the table's column + * + * @author Albert Shift + * + */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(value = { ElementType.METHOD, ElementType.ANNOTATION_TYPE }) public @interface Column { + /** + * Default value is the name of the method normalized to underscore + * + * @return name of the column + */ + String value() default ""; + /** + * Ordinal will be used for ascending sorting of columns + * + * Default value is 0, because not all mapping entities require all fields to have + * unique ordinals, only @Tuple mapping entity requires all of them to be unique. + * + * @return number that used to sort columns, usually for @Tuple only + */ + int ordinal() default 0; + /** + * For reserved words in Cassandra we need quotation in CQL queries. This property marks that + * the name of the UDT type needs to be quoted. + * + * Default value is false, we are quoting only selected names. + * + * @return true if name have to be quoted + */ + boolean forceQuote() default false; } diff --git a/src/main/java/com/noorq/casser/mapping/annotation/Index.java b/src/main/java/com/noorq/casser/mapping/annotation/Index.java index 367b832..21aa715 100644 --- a/src/main/java/com/noorq/casser/mapping/annotation/Index.java +++ b/src/main/java/com/noorq/casser/mapping/annotation/Index.java @@ -21,13 +21,42 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Index annotation is using under the specific column or method in entity interface with @Table annotation. + * + * The corresponding secondary index will be created in the underline @Table for the specific column. + * + * Currently Cassandra supports only single column index, so this index works only for single column. + * + * Make sure that you are using low cardinality columns for this index, that is the requirement of the Cassandra. + * Low cardinality fields examples: gender, country, age, status and etc + * High cardinality fields examples: id, email, timestamp, UUID and etc + * + * @author Albert Shift + * + */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(value = { ElementType.METHOD, ElementType.ANNOTATION_TYPE }) public @interface Index { + /** + * Defined the name of the index. By default will be used the column name. + * + * @return name of the index + */ + String value() default ""; + /** + * For reserved words in Cassandra we need quotation in CQL queries. This property marks that + * the name of the UDT type needs to be quoted. + * + * Default value is false, we are quoting only selected names. + * + * @return true if name have to be quoted + */ + boolean forceQuote() default false; } diff --git a/src/main/java/com/noorq/casser/mapping/annotation/PartitionKey.java b/src/main/java/com/noorq/casser/mapping/annotation/PartitionKey.java index 60a931e..c547ab9 100644 --- a/src/main/java/com/noorq/casser/mapping/annotation/PartitionKey.java +++ b/src/main/java/com/noorq/casser/mapping/annotation/PartitionKey.java @@ -20,14 +20,58 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * PartitionKey annotation is using to define that particular column is the part of + * partition key in the table. + * + * Partition Key is the routing key. Cassandra is using it to find the primary data node + * in the cluster that holds data. Cassandra combines all parts of the partition key to + * byte array and then calculates hash function by using good distribution algorithm (by default + * MurMur3). After that it uses hash number as a token in the ring to find a virtual + * and then a physical data server. + * + * For @Table mapping entity it is required to have as minimum one PartitionKey column. + * For @UDT and @Tuple mapping entities @PartitionKey annotation is not using. + * + * @author Albert Shift + * + */ + @Retention(value = RetentionPolicy.RUNTIME) @Target(value = { ElementType.METHOD, ElementType.ANNOTATION_TYPE }) public @interface PartitionKey { + /** + * Default value is the name of the method normalized to underscore + * + * @return name of the column + */ + String value() default ""; + /** + * PartitionKey parts must be ordered in the @Table. It is the requirement of Cassandra. + * That is how the partition key calculation works, column parts will be joined based on some order + * and final hash/token will be calculated. + * + * Be default ordinal has 0 value, that's because in most cases @Table have single column for @PartitionKey + * If you have 2 and more parts of the PartitionKey, then you need to use ordinal() to + * define the sequence of the parts + * + * @return number that used to sort columns in PartitionKey + */ + int ordinal() default 0; - + + /** + * For reserved words in Cassandra we need quotation in CQL queries. This property marks that + * the name of the UDT type needs to be quoted. + * + * Default value is false, we are quoting only selected names. + * + * @return true if name have to be quoted + */ + boolean forceQuote() default false; } diff --git a/src/main/java/com/noorq/casser/mapping/annotation/StaticColumn.java b/src/main/java/com/noorq/casser/mapping/annotation/StaticColumn.java index a800dda..ca8267b 100644 --- a/src/main/java/com/noorq/casser/mapping/annotation/StaticColumn.java +++ b/src/main/java/com/noorq/casser/mapping/annotation/StaticColumn.java @@ -20,14 +20,47 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * @StaticColumn annotation is using to define a static column in Cassandra Table + * + * It does not have effect in @UDT and @Tuple types and in @Table-s that does not have @ClusteringColumn-s + * + * In case of using @ClusteringColumn we can repeat some information that is unique for a row. + * For this purpose we can define @StaticColumn annotation, that will create static column in the table + * + * @author Albert Shift + * + */ + @Retention(value = RetentionPolicy.RUNTIME) @Target(value = { ElementType.METHOD, ElementType.ANNOTATION_TYPE }) public @interface StaticColumn { + /** + * Default value is the name of the method normalized to underscore + * + * @return name of the column + */ + String value() default ""; - + + /** + * Ordinal will be used for ascending sorting of static columns + * + * @return number that used to sort columns in PartitionKey + */ + int ordinal() default 0; + /** + * For reserved words in Cassandra we need quotation in CQL queries. This property marks that + * the name of the UDT type needs to be quoted. + * + * Default value is false, we are quoting only selected names. + * + * @return true if name have to be quoted + */ + boolean forceQuote() default false; } diff --git a/src/main/java/com/noorq/casser/mapping/annotation/Table.java b/src/main/java/com/noorq/casser/mapping/annotation/Table.java index 0f82ecb..b53e2a3 100644 --- a/src/main/java/com/noorq/casser/mapping/annotation/Table.java +++ b/src/main/java/com/noorq/casser/mapping/annotation/Table.java @@ -21,13 +21,41 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Entity annotation + * + * Table annotation is used to define Table mapping to some interface + * + * There are three types of Entity mapping annotations: @Table, @UDT, @Tuple + * + * For each @Table annotated interface Casser will create/update/verify Cassandra Table and some indexes if needed on startup. + * + * @author Albert Shift + * + */ + @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE }) public @interface Table { + /** + * Default value is the SimpleName of the interface normalized to underscore + * + * @return name of the UDT type + */ + String value() default ""; + /** + * For reserved words in Cassandra we need quotation in CQL queries. This property marks that + * the name of the UDT type needs to be quoted. + * + * Default value is false, we are quoting only selected names. + * + * @return true if name have to be quoted + */ + boolean forceQuote() default false; } diff --git a/src/main/java/com/noorq/casser/mapping/annotation/Tuple.java b/src/main/java/com/noorq/casser/mapping/annotation/Tuple.java index 93a5d04..1f12a78 100644 --- a/src/main/java/com/noorq/casser/mapping/annotation/Tuple.java +++ b/src/main/java/com/noorq/casser/mapping/annotation/Tuple.java @@ -21,6 +21,21 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Entity annotation + * + * Tuple annotation is used to define Tuple type mapping to some interface + * + * There are three types of Entity mapping annotations: @Table, @UDT, @Tuple + * + * Tuple is fully embedded type, it is the sequence of the underline types and + * the order of the sub-types is important, therefore all @Column-s must have ordinal() + * and only @Column annotation supported for underline types + * + * @author Albert Shift + * + */ + @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE }) diff --git a/src/main/java/com/noorq/casser/mapping/annotation/UDT.java b/src/main/java/com/noorq/casser/mapping/annotation/UDT.java index 89caea1..be66132 100644 --- a/src/main/java/com/noorq/casser/mapping/annotation/UDT.java +++ b/src/main/java/com/noorq/casser/mapping/annotation/UDT.java @@ -15,6 +15,18 @@ */ package com.noorq.casser.mapping.annotation; +/** + * Entity annotation + * + * UDT annotation is used to define the UDT (User Defined Type) mapping for some interface + * + * There are three types of Entity mapping annotations: @Table, @UDT, @Tuple + * + * For each annotated @UDT type Casser will create/update/verify Cassandra Type on startup + * + * @author Albert Shift + */ + import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; @@ -26,8 +38,23 @@ import java.lang.annotation.Target; @Target({ ElementType.TYPE }) public @interface UDT { + /** + * Default value is the SimpleName of the interface normalized to underscore + * + * @return name of the UDT type + */ + String value() default ""; + /** + * For reserved words in Cassandra we need quotation in CQL queries. This property marks that + * the name of the UDT type needs to be quoted. + * + * Default value is false, we are quoting only selected names. + * + * @return true if name have to be quoted + */ + boolean forceQuote() default false; }