GithubHelp home page GithubHelp logo

pankajmalhotra / cassandra-driver-mapping Goto Github PK

View Code? Open in Web Editor NEW

This project forked from valchkou/cassandra-driver-mapping

0.0 2.0 0.0 326 KB

JPA addon for DataStax Java Driver for Cassandra

Java 100.00%

cassandra-driver-mapping's Introduction

cassandra-driver-mapping

Entity mapping Add-on for the DataStax Java Driver (Driver) for Cassandra (C*).
This Add-on allows you to generate schema and persist JPA annotated entities in C*.
Add-on is not replacement for the Driver but lightweight utility for it.
You still can utilize full power of the Driver API and Datastax documentation.
Mapping Add-on relies on Driver version 2.0 and JPA 2.1.

Read more about Datastax Java Driver, Cassandra and CQL3.

[More Usage Samples in Unit Tests] (https://github.com/pankajmalhotra/cassandra-driver-mapping/blob/master/src/test/java/com/datastax/driver/mapping/)

Table of Contents

### Features

The features provided by the module include:

  • Manipulate Entity

    • Get entity from Cassandra.
    • Save entity to Cassandra.
    • Delete entity from Cassandra.
    • Run and map custom Queries.
    • Convert ResultSet into List of Entities
  • Generate Schema

    • Create table and indexes from Entity.
    • Alter table and indexes if entity definition has changed.
    • Drop table and indexes.

No mapping files, no scripts, no configuration files.
You don't have to worry about creating the Table and Indexes for your Entity manually.
All is built-in and taken care of. Entity definition will be automatically synchronized with C*.

### Jump Start - Maven Dependency. Install in your application from Maven Central using the following dependency: ```xml org.ul.cassandra.driver cassandra-driver-mapping 1.0.0 ``` - Init Mapping Session. MappingSession is cheap to instantiate and it is not replacement for the Datastax Session. You can instantiate as many mapping sessions as you want. It's theradsafe. ```java import com.datastax.driver.core.Session; import com.datastax.driver.mapping.MappingSession; ...
Session session; // initialize datastax session.
MappingSession mappingSession = new MappingSession("keyspace_name", session);
Underlying Datastax Session does all the heavylifting and is expansive.   
Prior using MappingSession you need to open the Datastax Session and create the Keyspace using the standard Datastax Driver API. If you are not familiar with procedure please refer to [Datastax Dcumentation](http://www.datastax.com/documentation/developer/java-driver/2.0/java-driver/quick_start/qsQuickstart_c.html).  
Or look at the [Spring Framework Example](#spring).

<a name="jump_save"/>
- Save.
```java
	Entity entity = new Entity();
	mappingSession.save(entity);

OR

	import com.datastax.driver.mapping.option.WriteOptions;
	import com.datastax.driver.core.policies.DefaultRetryPolicy;
	import com.datastax.driver.core.ConsistencyLevel;
	...
	// using options
	WriteOptions options = new WriteOptions()
		.setTtl(300)
		.setTimestamp(42)
		.setConsistencyLevel(ConsistencyLevel.ANY)
		.setRetryPolicy(DefaultRetryPolicy.INSTANCE);
		
	Entity entity = new Entity();
	mappingSession.save(entity, options);
- Get. ```java Entity entity = mappingSession.get(Entity.class, id); ``` OR ```java import com.datastax.driver.mapping.option.ReadOptions; import com.datastax.driver.core.policies.DefaultRetryPolicy; import com.datastax.driver.core.ConsistencyLevel; ... // using options ReadOptions options = new ReadOptions() .setConsistencyLevel(ConsistencyLevel.ANY) .setRetryPolicy(DefaultRetryPolicy.INSTANCE);
Entity entity = mappingSession.get(Entity.class, id, options);

<a name="jump_delete"/>
- Delete.
```java
	mappingSession.delete(entity);	
### Various Mappings
IMPORTANT!!!  
- If entity or field is not annotated it will provide its name as default.    
- Id field is required and must be annotated with @Id or @EmbeddedId.
- Index name must be unique within the keyspace.  
- C* supports only single-column-index.
- Basic Mapping ```java import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.Column
@Table (name="mytable")
public class Entity {
	
	@Id
	private long Id;
	
	@Column(name = "myname")
	private String name;
	
	// @Column is not required
	private int age;
	
	@Transient
	private BigDecimal calculable;
	
	// public getters/setters ...
}
```
CQL3 Statement
```
CREATE TABLE IF NOT EXISTS ks.mytable (id bigint, myname text, age int, PRIMARY KEY(id))
```     
- Mapping Indexes ```java import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.Column import javax.persistence.Index import java.util.UUID
@Table (name="mytable", 
indexes = {
	@Index(name="entity_email_idx", columnList="email" ), 
	@Index(name="entity_name_idx", columnList="myname" ) 
})
public class Entity {
	
	@Id
	private java.util.UUID code;
	
	@Column(name = "myname")
	private String name;
	private String email;
	// public getters/setters ...
}
```
CQL3 Statement
```
	CREATE TABLE IF NOT EXISTS ks.mytable (code uuid, myname text, email text,  PRIMARY KEY(code)); 
	CREATE INDEX IF NOT EXISTS entity_email_idx ON ks.mytable(email);  
	CREATE INDEX IF NOT EXISTS entity_name_idx ON ks.mytable(myname);
```   
- Compound Primary Key
```java
import javax.persistence.Embeddable;	

@Embeddable
public class CompositeKey {
	private String name;
	private int rank;
	// public getters/setters ...
}
```
```java

import javax.persistence.Table;
import javax.persistence.EmbeddedId;	

@Table(name="entity")
public class Entity {
	@EmbeddedId
	private CompositeKey key;
	private String email;
	// public getters/setters ...
}
```
CQL3 Statement
```
CREATE TABLE IF NOT EXISTS ks.entity (name text,  rank int, email text,  PRIMARY KEY(name, rank))
```     
- Composite Partition Key
```java
import javax.persistence.Embeddable;	

@Embeddable
public class PartitionKey {
	private String firstName;
	private String lastName;
	// public getters/setters ...
}
```
```java
import javax.persistence.Embeddable;	

@Embeddable
public class CompositeKey {
	@EmbeddedId
	private PartitionKey key;
	private int age;
	// public getters/setters ...
}
```
```java
import javax.persistence.Table;
import javax.persistence.EmbeddedId;	

@Table(name="entity")
public class Entity {
	@EmbeddedId
	private CompositeKey key;
	private String email;
	// public getters/setters ...
}
```
CQL3 Statement
```
CREATE TABLE IF NOT EXISTS ks.entity (firstname text, lastname text, age int, email text,  PRIMARY KEY((firstname, lastname), age))
```     
- Table Properties This feature is not JPA standard! [ Read more about C* Table properties ] (http://www.datastax.com/documentation/cql/3.1/cql/cql_reference/cql_storage_options_c.html) ```java import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.Column
import com.datastax.driver.mapping.annotation.TableProperties;
import com.datastax.driver.mapping.annotation.TableProperty;

@Table (name="mytable")
@TableProperties(values = {
	@TableProperty(value="comment='Important records'"),
	@TableProperty(value="read_repair_chance = 1.0"),
	@TableProperty(value="compression ={ 'sstable_compression' : 'DeflateCompressor', 'chunk_length_kb' : 64 }")
})
public class Entity {
	
	@Id
	private long Id;
	private String name;
	// public getters/setters ...
}
```
CQL3 Statement
```
CREATE TABLE IF NOT EXISTS ks.mytable (id bigint, name text, PRIMARY KEY(id)) WITH comment='Important records' AND read_repair_chance = 1.0 AND compression ={ 'sstable_compression' : 'DeflateCompressor', 'chunk_length_kb' : 64 }
```     
- Override Column Data Type. Datastax defines [data type mapping from Java to C*] (http://www.datastax.com/documentation/developer/java-driver/2.0/java-driver/reference/javaClass2Cql3Datatypes_r.html). This addon defines opposite way mapping. [You can explore daults here](#metadata). But in case you don't like defaults you are able to override the type on the column level. For example you want to leverage "time UUID" for timeseries data instead of "random UUID". ```java import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.Column
@Table (name="mytable")
public class Entity {
	
	@Id
	@Column(name="uid", columnDefinition="timeuuid") // case insensitive
	private UUID uid;		
	
	@Column(name="name", columnDefinition="VarChaR") // case insensitive
	private String name;
	// public getters/setters ...
}
```
CQL3 Statement
```
CREATE TABLE IF NOT EXISTS ks.mytable (uid timeuuid, name varchar, PRIMARY KEY(uid))
```     
- Mixed Case for Column Names [C* converts all names to lowercase](http://www.datastax.com/documentation/cql/3.1/cql/cql_reference/ucase-lcase_r.html). This is default and recommended approach. But in case you need enforce the case you will need to wrap you names in double quotes. ```java import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.Column
@Table (name="mytable")
public class Entity {
	
	@Id
	@Column(name = "\"KEY\"")
	private int id;
	private String firstName;

	@Column(name = "\"last_NAME\"")
	private String lastName;

	@Column(name = "AGE")
	private int age;
	// public getters/setters ...
}
```
CQL3 Statement
```
CREATE TABLE IF NOT EXISTS ks.mytable ("KEY" int, firstName text, "last_NAME" text, AGE int, PRIMARY KEY("KEY"))
```     
### Collections - Mapping ```java import java.math.BigInteger; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set;
import javax.persistence.Id;
import javax.persistence.Table;

@Table(name="entity")
public class Entity {
	@Id
	private java.util.UUID id;
	private List<String> cats;
	private Set<Date> dogs;
	private Map<String, BigInteger> pets;
	
	// public getters/setters ...
}
```

Collections must have generic type defined. Only java.util.List, Map and Set are allowed.
By default implementation of HashMap, HashSet and ArrayList are used. If you are unhappy with that fact and would like your data to be baked with specific collection implementation you can apply an annotation as shown below. ```java import com.datastax.driver.mapping.annotation.CollectionType; ... @CollectionType(LinkedList.class) private List cats;

	@CollectionType(TreeSet.class)
	private Set<Date> dogs;

	@CollectionType(TreeMap.class)
	private Map<String, BigInteger> pets;
}
```

NOTE: this is strictly java side feature and does not effect how your data stored in C*.

CQL3 Statement
```
CREATE TABLE IF NOT EXISTS ks.entity (id uuid, cats list<text>, dogs set<timestamp>, pets map<text, varint>,  PRIMARY KEY(id))
```     

For more info on collections please refer [Datastax Using Collection] (http://www.datastax.com/documentation/cql/3.1/cql/cql_using/use_collections_c.html)

- Optimized operations You can work with your collection properties as you would normally work with other entity properties. In addition C* provides optimized operations on collections. Those operations do not require to load and save the whole entity. C* allows us directly manipulate collections. - List operations ```java // append item to list mappingSession.append(id, Entity.class, "cats", "Black Cat");

// append item to be expired in 5 sec mappingSession.append(id, Entity.class, "cats", "Expired Cat", new WriteOptions().setTtl(5));

// prepend item mappingSession.prepend(id, Entity.class, "cats", "First Cat");

// replace item at specified index mappingSession.replaceAt(id, Entity.class, "cats", "Grey Cat", 1);

// append List of items List addCats = new ArrayList(); addCats.add("Red Cat"); addCats.add("Green Cat"); mappingSession.append(id, Entity.class, "cats", addCats);

// remove item mappingSession.remove(id, Entity.class, "cats", "Grey Cat");

// remove List of items List removeCats = new ArrayList(); removeCats.add("Red Cat"); removeCats.add("Green Cat"); mappingSession.remove(id, Entity.class, "cats", removeCats);

// remove all items mappingSession.deleteValue(id, Entity.class, "cats");


<a name="collections_set"/>
- Set operations
```java
// append item
mappingSession.append(id, Entity.class, "dogs", "Black Dog");

// append item to be expired in 5 sec
mappingSession.append(id, Entity.class, "dogs", "Expired Dog", new WriteOptions().setTtl(5));

// append Set of items
Set<String> addDogs = new HashSet<String>();
addDogs.add("Red Dog");
addDogs.add("Green Dog");
mappingSession.append(id, Entity.class, "dogs", addDogs);

// remove item
mappingSession.remove(id, Entity.class, "dogs", "Black Dog");

// remove Set of items
Set<String> removeDogs = new HashSet<String>();
removeDogs.add("Red Dog");
removeDogs.add("Green Dog");
mappingSession.remove(id, Entity.class, "dogs", removeDogs);

// remove all items
mappingSession.deleteValue(id, Entity.class, "dogs");
- Map operations ```java /** append item */ Map pets = new HashMap(); pets.put("Red Dogs", 25); pets.put("Black Cats", 50); mappingSession.append(id, Entity.class, "pets", pets);

/** append items to be expired in 5 sec */ Map<String, BigInteger> pets = new HashMap<String, BigInteger>(); pets.put("Green Dogs", 25); pets.put("Brown Cats", 50); mappingSession.append(id, Entity.class, "pets", pets, new WriteOptions().setTtl(5));

/** remove all items */ mappingSession.deleteValue(id, Entity.class, "pets");


<a name="lock"/>
### Optimistic Lock
C* does not support locking. But it provides ability for [Optimistic Concurrency Control] (http://en.wikipedia.org/wiki/Optimistic_concurrency_control).  
While running, transactions use data resources without acquiring locks on those resources. Before committing, each transaction verifies that no other transaction has modified the data it has read. If the check reveals conflicting modifications, the committing transaction rolls back and can be restarted.  
This section explains how you can achieve this with C* and Mapping Add-on


<a name="lock_transactions"/>
- Lightweight Transactions  
I don't know why they call it Lightweight Transactions. Those transactions are much heavier than normal C* transactions. Read more about [Datastax Lightweight Transactions.] (http://www.datastax.com/documentation/cassandra/2.0/cassandra/dml/dml_ltwt_transaction_c.html)  
C* supports conditional UPDATE/INSERT using IF/IF NOT EXISTS keywords. When "IF" condition is not met write doesn't happen. The boolean flag "[applied]" is returned.

<a name="lock_version"/>
- @Version  
Mapping Add-on enables optimistic locking using annotation @Version.  
The property must be of "long" data type. Whenever you save entity the version get incremented and as result of operation updated entity is retirned. If you try to save not-the-latest one then "null" will be returned instead and no error will be thrown.
```java
	
	import javax.persistence.Id;
	import javax.persistence.Table;
	import javax.persistence.Version;	
	
	@Table(name="entity")
	public class EntityWithVersion {
		@Id
		private java.util.UUID id;
	
		@Version
		private long version;	
		// public getters/setters ...
	}
	
	@Test
	public void entityWithVersionTest() throws Exception {
		UUID id = UUID.randomUUID();
		EntityWithVersion obj = new EntityWithVersion();
		obj.setId(id);
		obj.setName("ver1"); 
		
		EntityWithVersion loaded = mappingSession.get(EntityWithVersion.class, id);
		assertNull(loaded);
		
		// save object ver1 
		EntityWithVersion saved = mappingSession.save(obj);
		
		// get object ver1
		EntityWithVersion obj1 = mappingSession.get(EntityWithVersion.class, id);
		assertEquals(obj1, saved);
		assertEquals(1, saved.getVersion());
		
		// save object ver2
		saved = mappingSession.save(saved);
		EntityWithVersion obj2 = mappingSession.get(EntityWithVersion.class, id);
		assertEquals(obj2, saved);
		assertEquals(2, saved.getVersion());		
		
		saved = mappingSession.save(obj1);
		assertNull(saved);
	}		
### Batch ```java
mappingSession.withBatch()
	.save(entityA)
	.save(entityB)
	.delete(entityC)
	.delete(entityD)
	.execute();


<a name="nested"/>
### Nested Entities
This section shows how you can support nested entities with C* and Mapping Add-on.
```java
	
	@Table(name="entity_a")
	public class EntityA {
		@Id
		private UUID id;
	
		// public getters/setters ...
	}
	
	@Table(name="entity_b")
	public class EntityB {
		@Id
		private UUID id;
		
		// reference on EntityA 
		private UUID refA;
		// public getters/setters ...
	}	
	
	public class TestNested() {
		
		@Test
		public void saveNested() throws Exception {
			EntityA a = new EntityA();
			mappingSession.save(a);
			
			EntityB b = new EntityB();
			b.setRefA(a.getId());
			mappingSession.save(b);
		}

		@Test
		public void loadNested() throws Exception {
			UUID bId = some_id;
			EntityB b = mappingSession.load(bId);
			EntityA a = mappingSession.load(b.getRefA());
		}
		
	}
### Mapping Custom Queries - How To Run There are two ways to run and map the query: 1) run using mapping session ```java import com.datastax.driver.mapping.MappingSession; ... List result = mappingSession.getByQuery(Entity.class, query); ```
2) run using DataStax session and map the ResultSet
```java
import com.datastax.driver.core.Session;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.mapping.MappingSession;
...
ResultSet rs = session.execute(query);	
List<Entity> result = mappingSession.getFromResultSet(Entity.class, rs);
```
- Any-to-Any and Magic Gnomes This is the coolest feature of the module. Your Entity doesn't have to match the table. You can populate any entity from any query (Any-to-Any). Consider example: ```java public class AnyObject { private String name; private int age; // public getters/setters ... } ``` You can populate this object from any ResultSet which contains 'name' and 'age' columns. ```java ResultSet rs = session.execute("SELECT name, age, birth_date, salary FROM person"); List result = mappingSession.getFromResultSet(AnyObject.class, rs); ``` In this particular case 'name' and 'age' will be populated on 'AnyObject'. 'birth_date' and 'salary' will be ignored and no errors will be thrown. The biggest advantage that we can reuse the same entity to query different results from even different tables. Entity doesn't have to map, match or relate to the table at all. Many thank to magic gnomes under the hood making all these work. ### Building Custom Queries - CQL String ```java import com.datastax.driver.mapping.MappingSession; ...
// build query
String query = "SELECT name, age, birth_date, salary FROM person");	

// run query						
List<Entity> result = mappingSession.getByQuery(Entity.class, query);	

<a name="queries_builder"/>
- QueryBuilder (Better)  
Datastax Driver shipped with a tool to build CQL statement.  
You can build your query with Datastax QueryBuilder and map ResultSet on Entity.  
QueryBuilder ensures you build correct CQL.
```java
				
	import com.datastax.driver.core.Statement;
	import com.datastax.driver.core.querybuilder.QueryBuilder;
	import com.datastax.driver.mapping.MappingSession;
	...

	// build query
	Statement query = QueryBuilder.select().all()
		.from("your_keyspace", "your_table").where(eq("column", value));
	
	// run query						
	List<Entity> result = mappingSession.getByQuery(Entity.class, query);
- QueryBuilder with EntityMetadata (Even Better) In early stages you may often change table and column names. To avoid changing queries each time you rename something you can employ entity metadata. ```java import com.datastax.driver.core.Statement; import com.datastax.driver.core.querybuilder.QueryBuilder; import com.datastax.driver.mapping.MappingSession; import com.datastax.driver.mapping.EntityFieldMetaData; import com.datastax.driver.mapping.EntityTypeMetadata; ...
// get Entity Metadata
EntityTypeMetadata emeta = EntityTypeParser.getEntityMetadata(Entity.class);

// get field metadata by property/field name
EntityFieldMetaData fmeta = emeta.getFieldMetadata(field_name); 

// build query.
Statement query = QueryBuilder.select().all()
	.from("your_keyspace", emeta.getTableName()).where(eq(fmeta.getColumnName(), value));
						
// run query
List<Entity> result = mappingSession.getByQuery(Entity.class, query);



	   
<a name="sync"/>	   
### How Entity get synchronized
The table structure is automatically synchronized with the entity definition on the first use of the entity.  
Any SessionMapping call internally will check if the entity has already been synchronized and if not   
it will run SchemaSync.sync. You can use sync API directly as:  

```java
	// create or alter
	import com.datastax.driver.mapping.schemasync.SchemaSync;
	...
	SchemaSync.sync(keyspace, session, Entity.class);
	// drop table
	import com.datastax.driver.mapping.schemasync.SchemaSync;
	...
	SchemaSync.drop(keyspace, session, Entity.class);

You don't need to use this API unless you have reasons.
Such as unittests or if you want to gain few milliseconds on the first use
you may want to invoke the synchronization on the application start up instead.

As the project is evolving sometimes there is need to refactor entity, add or delete properties and indexes. Again this all taken care automatically but with certain restrictions.
Please read to understand what will and will not be altered and synchronized.

Not Alterable

  • add/delete/rename primary key columns. (C* restriction)
  • change column data type to incompatible one, such as string to number. (C* restriction)
  • change property name which is not annotated as @Column. This will be understood as a new property.

Alterable

  • add new property.
  • delete property.
  • add index on column.
  • change datatype to compatible one. Compatibility is enforced by C*.
### Entity Metadata and Data Types

You may want to access Entity metadata if you are building custom Statements.
Entity Metadata contains corresponding table and column names.
Entity Metadata can be easily accessed anywhere in your code as:

	EntityTypeMetadata emeta = EntityTypeParser.getEntityMetadata(Entity.class)
	emeta.getTableName(); // corresponding table name in C*
	
	// get field meta info by property name
	EntityFieldMetaData fdata = emeta.getFieldMetadata("email");
	 
	// corresponding column name in C*
	String columnName = fdata.getColumnName(); 
	
	 // all the persistent fields on entity
	List<EntityFieldMetaData> fields = emeta.getFields();

Datastax driver has mapping of datastax types to java. But not all types are mapped as 1-to-1.
CQL3 data types to Java types
In order the mapping to work the module defines backward mapping for the types.

Java type CQL3 data type
int int
long bigint
float float
double double
boolean boolean
java.lang.Double double
java.nio.ByteBuffer blob
java.math.BigDecimal decimal
java.lang.String text
java.util.Date timestamp
java.lang.Boolean boolean
java.lang.Integer int
java.lang.Long bigint
java.util.Map map
java.lang.Float float
java.util.Set set
java.math.BigInteger varint
java.util.UUID uuid
java.util.List list

You can override defaults as:

	import com.datastax.driver.core.DataType;
	...
	Map<Class<?>, DataType.Name> mapping = new HashMap<Class<?>, DataType.Name>();
	.... populate the map
	EntityTypeParser.setDataTypeMapping(mapping);

Or override individual type:

	import com.datastax.driver.core.DataType;
	...
	EntityTypeParser.overrideDataTypeMapping(javaClass, DataType.Name)
### Spring Framework Example
  • Configure properties.
    Let's imagine we have a property file /META-INF/cassandra.properties:

     	cassandra.keyspace=your_keyspace
      cassandra.node=127.0.0.1
    
  • Include properties in spring config:

     <?xml version="1.0" encoding="UTF-8"?>
     <beans:beans xmlns="http://www.springframework.org/schema/mvc"
     	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     	xmlns:beans="http://www.springframework.org/schema/beans"
     	xmlns:context="http://www.springframework.org/schema/context"
     	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
     	http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
     	
     	<!-- Enables the Spring MVC @Controller programming model -->
     	<annotation-driven />
    
     	<context:property-placeholder location="classpath*:/META-INF/cassandra.properties"/>  
     
     	<context:component-scan base-package="your.package.path" />
      </beans:beans> 
  • Define Entity

     	import java.util.UUID;
     	
     	import javax.persistence.Entity;
     	import javax.persistence.Column;
     	import javax.persistence.Id;
     	import javax.persistence.Table;
     	
     	@Entity
     	@Table(name="account", indexes = {@Index(name="account_email_idx", columnList="email" )})
     	public class Account {
     		@Id
     		private String id = UUID.randomUUID().toString();
     		
     		@Column(name="email") 
     		private String email;			
     		
     		public String getId() {
     			return id;
     		}
     		public void setId(String id) {
     			this.id = id;
     		}			
     		public String getEmail() {
     			return email;
     		}
     		public void setEmail(String email) {
     			this.email = email;
     		}
     	}
  • Create session factory for C*:

     	import org.springframework.beans.factory.annotation.Value;
     	import org.springframework.stereotype.Repository;
     	import com.datastax.driver.core.Cluster;
     	import com.datastax.driver.core.Session;
     	import com.datastax.driver.mapping.MappingSession;
     	import com.datastax.driver.mapping.schemasync.SchemaSync;
     	
     	@Repository
     	public class CassandraSessionFactory {
     		
     		@Value("${cassandra.keyspace}")
     		private String keyspace;
     		
     		@Value("${cassandra.node}")
     		private String node;
     		
     		private Cluster cluster;
     		private Session session;
     		private MappingSession mappingSession;
     			
     		public Session getSession() {
     			if (session == null) {
     				connect();
     			}
     			return session;
     		}
     	
     		public MappingSession getMappingSession() {
     			if (session == null) {
     				connect();
     			}
     			return mappingSession;
     		}
     	
     		public String getKeyspace() {
     			return keyspace;
     		}
     		
     		/** only 1 thread is permitted to open connection */
     		protected synchronized void connect() {
     			if (session == null) {
     				cluster = Cluster.builder().addContactPoint(node).build();
     				session = cluster.connect();
     				session.execute("CREATE KEYSPACE IF NOT EXISTS "+ getKeyspace() +
     					" WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 3 }");
     					
     				mappingSession = new MappingSession(getKeyspace(), getSession());
     			}	
     		}
     	}
  • Create DAO and inject factory into it:

     	import java.util.List;
     	
     	import org.springframework.beans.factory.annotation.Autowired;
     	import org.springframework.stereotype.Repository;
     	
     	import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
     	import com.datastax.driver.core.Statement;
     	import com.datastax.driver.core.querybuilder.QueryBuilder;
     	import com.datastax.driver.mapping.EntityFieldMetaData;
     	import com.datastax.driver.mapping.EntityTypeMetadata;
     	import com.datastax.driver.mapping.EntityTypeParser;
     	import com.datastax.driver.mapping.MappingSession;	
     	
     	@Repository
     	public class AccountDAO {
     		
     		@Autowired
     		CassandraSessionFactory sf;
     		
     		public void save(Account account) {
     			sf.getMappingSession().save(account);	
     		}
     		
     		public void delete(Account account) {
     			sf.getMappingSession().delete(account);	
     		}
     		
     		public Account getById(Object id) {
     			return sf.getMappingSession().get(ChatAccount.class, id);	
     		}
     		
     		public Account getByEmail(String email) throws Exception {
     			
     			Statement stmt = buildQueryForColumn("email", email);
     			if (stmt==null) return null;
     			
     			List<Account> result = sf.getMappingSession().getByQuery(Account.class, stmt);
     			if (result == null || result.size()==0) return null;
     	
     			return result.get(0);
     		}
     	
     		
     		/** Sample Building Select Statement for a single column with Datastax QueryBuilder */
     		protected Statement buildQueryForColumn(String propName, Object propVal) {
     			EntityTypeMetadata emeta = EntityTypeParser.getEntityMetadata(Account.class);
     			EntityFieldMetaData fmeta = emeta.getFieldMetadata(propName);
     			if (fmeta != null) {
     				return QueryBuilder
     						.select().all()
     						.from(sf.getKeyspace(), emeta.getTableName())
     						.where(eq(fmeta.getColumnName(), propVal));
     			}
     			return null;
     		}
     	}

cassandra-driver-mapping's People

Contributors

valchkou avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.