Skip to content

Achilles Custom Types

DuyHai DOAN edited this page Sep 30, 2016 · 31 revisions

AnalyzerClass

Analyzer class to be used for SASI support. Possible values are:

  • NO_OP_ANALYSER (DEFAULT): do not analyze the input
  • NON_TOKENIZING_ANALYZER: only valid for text/ascii data types. Do not tokenize the input. Normalization by lowercase/uppercase is allowed
  • STANDARD_ANALYZER: only valid for text/ascii data types. Split the input text into tokens, using the locale defined by attribute 'locale' Normalization by lowercase/uppercase is allowed

#### CassandraShutdownHook

Shutdown hook to control when to shutdown the embedded Cassandra process.

    CassandraShutDownHook shutdownHook = new CassandraShutDownHook();

    Session session = CassandraEmbeddedServerBuilder.builder()
        .withShutdownHook(shutdownHook)
        ...
        .buildNativeSession();

    ...

    shutdownHook.shutdownNow();

Please note that upon call on shutdownNow(), Achilles will trigger the shutdown of:

  • the embedded Cassandra server
  • the associated Cluster object
  • the associated Session object

#### CassandraVersion

This is an enum used to declare the Cassandra version you're using for compile to configure Achilles at compile time.

    @CompileTimeConfig(cassandraVersion = CassandraVersion.CASSANDRA_3_0_X)
    public interface AchillesConfig {
    
    }

Depending on the chosen version, Achilles will generate appropriate DSL code.


#### Codec

Define a codec to transform a source type into a target type.
The source type can be any Java type. The target type should be a Java type supported by Cassandra

    public interface Codec<FROM, TO> {
    
        Class<FROM> sourceType();
    
        Class<TO> targetType();
    
        TO encode(FROM fromJava) throws AchillesTranscodingException;
    
        FROM decode(TO fromCassandra) throws AchillesTranscodingException;
    }
    


Example of LongToString codec:
    public class LongToString implements Codec<Long,String> {
        @Override
        public Class<Long> sourceType() {
            return Long.class;
        }
    
        @Override
        public Class<String> targetType() {
            return String.class;
        }
    
        @Override
        public String encode(Long fromJava) throws AchillesTranscodingException {
            return fromJava.toString();
        }
        
        @Override
        public Long decode(String fromCassandra) throws AchillesTranscodingException {
            return Long.parseLong(fromCassandra);
        }
    }

#### CodecSignature

Utility class to identify uniquely a codec. A codec signature is composed of:

  • sourceType
  • targetType
  • optionally, codecName if provided

See Runtime Codec for more details


#### Column Mapping Strategy

You can specify the column mapping strategy at compile time using the @CompileTimeConfig annotation:

    @CompileTimeConfig(cassandraVersion = CassandraVersion.CASSANDRA_3_0_X, columnMappingStrategy = ColumnMappingStrategy.IMPLICIT)
    public interface AchillesConfig {
    
    }

The default behavior is ColumnMappingStrategy.EXPLICIT

See Column Mapping Strategy for more details


#### Encoding

Define the encoding type for enum values. 2 choices are available:

  1. info.archinnov.achilles.annotations.Enumerated.Encoding.NAME encode enum using their name()
  2. info.archinnov.achilles.annotations.Enumerated.Encoding.ORDINAL encode enum using their ordinal()

More details on Enum type


#### Empty

It is just a marker enum for asynchronous operations. Sometimes an operation does not return any meaningful result (like deleteById(...) or insert(...)). Still we need to be able to ensure that the asynchronous operation has been executed correctly by calling get(). If the execution has been successful, the singleton Empty is returned, otherwise an exception is raised

For more details, please check Asynchronous Operations


#### IndexMode

Indexing mode for SASI. Possible values are:

  • PREFIX (DEFAULT): allows search on prefix for text/ascii data types. Default and only valid index mode for non-text data types
  • CONTAINS: allows search on prefix, suffix and substring for text/ascii data types. Invalid for non-text data types
  • SPARSE: only valid for non-text data types. SPARSE mode is optimized for low-cardinality e.g. for indexed values having 5 or less corresponding rows. If there are more than 5 CQL rows having this index value, SASI will complain by throwing an exception

#### InsertStrategy

Define the insert strategy on an entity. Right now only 2 values are possible:

  1. info.archinnov.achilles.type.InsertStrategy.NOT_NULL_FIELDS
  2. info.archinnov.achilles.type.InsertStrategy.ALL_FIELDS

Upon call to insert(), depending on the chosen strategy Achilles will

  1. insert all fields on the entity, even if they are null
  2. insert only non null fields of the entity

Check here for more details on the Insert strategy


#### Interceptor

This is an interface defining the contract for a lifecycle interceptor. For more details, please check Interceptors

    public interface Interceptor<T> 
    {
        boolean acceptEntity(Class<?> entityClass);
        
        public void onEvent(T entity);
    
        public List<Event> events();
    }

#### LWTResultListener

For all LWT operations, Cassandra returns an [applied] boolean column telling whether the operation has been successful or not. If a LWT update operation failed, Cassandra also returns the current values that differ from the ones used by the LWT update.

To intercepts the LWT operation result and current values, you can register a LWTResultListener using the Options API (see above)

The signature of the LWTResultListener is:

    public interface LWTResultListener {

        default void onSuccess() {
            // Do nothing
        }

        void onError(LWTResult lwtResult);
    }
    

The LWTResult type is defined as:

    public class LWTResult {
            private final Operation operation;
            private final TypedMap currentValues;
    
            public LWTResult(Operation operation, TypedMap currentValues) {
                this.operation = operation;
                this.currentValues = currentValues;
            }
    
            ...
    
            public static enum Operation {INSERT, UPDATE}
        }
        

For more details on LWT operations, please refer to Lightweight Transaction


#### NamingStrategy

Define the naming strategy for the keyspace, table and column name. There are 3 possible strategies:

  1. SNAKE_CASE: transform all schema name using snake case
  2. CASE_SENSITIVE: enclose the name between double quotes (") for escaping the case
  3. LOWER_CASE: transform the name to lower case

Check here for more details on the Naming strategy


#### Normalization

Text normalization mode for SASI. Possible values are:

  • NONE (DEFAULT): no normalization
  • LOWERCASE: normalize input text and search term to lower case
  • UPPERCASE: normalize input text and search term to upper case

#### SchemaNameProvider

This is an interface to be implemented to provide dynamic binding of keyspace/table name at runtime. The interface is

	public interface SchemaNameProvider {
	
		/**
		 * Provide keyspace name for entity class
		 */
		<T> String keyspaceFor(Class<T> entityClass);
	
		/**
		 * Provide table name for entity class
		 */
		<T> String tableNameFor(Class<T> entityClass);
	}

The provider can be used with CRUD API and DSL API


#### Tuples

Since Cassandra supports tuple type and the Java driver only exposes a com.datastax.driver.core.TupleValue, Achilles introduces Tuple1, Tuple2, ..., Tuple10 types. They all extends the Tuple interface and exposes the following methods:

    
    //Get all tuple values, in the correct order
    public List<Object> values();
    
    //Return the 1st component of the tuple
    public A _1();
    
    //Return the 2nd component of the tuple
    public B _2();
    
    ...
    
    //Return the 10th component of the tuple
    public J _10();    

Internally, Achilles will perform automatic conversion between those tuple types to/from com.datastax.driver.core.TupleValue so that you can use them directly in your entities

    @Table
    public class Entity {
    
        @Column
        private Tuple3<String, List<String>, Long> tuple3;
        
         ...
    }
    

Note: in the above example, there is no need to add @Frozen on the List<String> because all tuples are frozen by default.


#### TypedMap

The native query API used to return a Map<String,Object> as result. It is not very user-friendly because it forces you do manual type casting. Example:

	
	Map<String,Object> columns = manager.nativeQuery("SELECT * FROM users WHERE userId = 10").getFirst();
	
	String name = (String)columns.get("name");  // BAD !
	Long age = (Long)columns.get("age"); // BAD !

TypedMap is just an extension of Map<String,Object> offering two extras methods for convenience:

	
	@SuppressWarnings("unchecked")
	public <T> T getTyped(String key) {
		T value = null;
		if (super.containsKey(key) && super.get(key) != null) {
			value = (T) super.get(key);
			return value;
		}
		return value;
	}

	public <T> T getTypedOr(String key, T defaultValue) {
		if (super.containsKey(key)) {
			return getTyped(key);
		} else {
			return defaultValue;
		}
	}

Of course there is no magic, the dirty casting you no longer do, getTyped() will do it for you. The target type is passed at runtime while calling the method. getTypedOr() lets you provide a fall-back value.

Example of usage:

	
	TypedMap columns = manager.nativeQuery("SELECT * FROM users WHERE userId = 10").first();
	
	// Explicit type (String) is passed to method invocation
	String name = columns.<String>getTyped("name");
	
	// No need to provide explicit type. The compiler will infer type in this case
	Long age = columns.get("age");

Home

Clone this wiki locally