Skip to content

Achilles Custom Types

DuyHai DOAN edited this page Oct 29, 2015 · 31 revisions

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

    @Entity
    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");

#### 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


#### 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


#### 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


#### 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


#### 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);
        }
    }

#### 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


#### 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

Home

Clone this wiki locally