All Projects → 1and1 → Troilus

1and1 / Troilus

Licence: Apache-2.0 license
Troilus is a Java client library for Cassandra.

Programming Languages

java
68154 projects - #9 most used programming language
PLSQL
303 projects

Projects that are alternatives of or similar to Troilus

Phantom
Schema safe, type-safe, reactive Scala driver for Cassandra/Datastax Enterprise
Stars: ✭ 1,049 (+6070.59%)
Mutual labels:  cassandra, reactive-streams
Toketi Iothubreact
Akka Stream library for Azure IoT Hub
Stars: ✭ 36 (+111.76%)
Mutual labels:  cassandra, reactive-streams
Ebook Chat App Spring Websocket Cassandra Redis Rabbitmq
Pro Java Clustering and Scalability: Building Real-Time Apps with Spring, Cassandra, Redis, WebSocket and RabbitMQ
Stars: ✭ 186 (+994.12%)
Mutual labels:  cassandra
flutter-form-with-validation-BLOC
This form and validation functions are created by using the BLOC pattern with RxDart instead of using StatefulWidget
Stars: ✭ 63 (+270.59%)
Mutual labels:  reactive-streams
Gimel
Big Data Processing Framework - Unified Data API or SQL on Any Storage
Stars: ✭ 216 (+1170.59%)
Mutual labels:  cassandra
Firecamp
Serverless Platform for the stateful services
Stars: ✭ 194 (+1041.18%)
Mutual labels:  cassandra
Cassandra Reaper
Software to run automated repairs of cassandra
Stars: ✭ 235 (+1282.35%)
Mutual labels:  cassandra
Scalardb
Universal transaction manager
Stars: ✭ 178 (+947.06%)
Mutual labels:  cassandra
pipeline
PipelineAI Kubeflow Distribution
Stars: ✭ 4,154 (+24335.29%)
Mutual labels:  cassandra
Cassandra Operator
Kubernetes operator for Apache Cassandra
Stars: ✭ 215 (+1164.71%)
Mutual labels:  cassandra
Morphl Community Edition
MorphL Community Edition uses big data and machine learning to predict user behaviors in digital products and services with the end goal of increasing KPIs (click-through rates, conversion rates, etc.) through personalization
Stars: ✭ 253 (+1388.24%)
Mutual labels:  cassandra
Cass Operator
The DataStax Kubernetes Operator for Apache Cassandra
Stars: ✭ 208 (+1123.53%)
Mutual labels:  cassandra
Cassandra
A Docker Cassandra container
Stars: ✭ 198 (+1064.71%)
Mutual labels:  cassandra
Xandra
Fast, simple, and robust Cassandra driver for Elixir.
Stars: ✭ 239 (+1305.88%)
Mutual labels:  cassandra
Cassandradump
A data exporting tool for Cassandra inspired from mysqldump, with some additional slice and dice capabilities
Stars: ✭ 186 (+994.12%)
Mutual labels:  cassandra
ecchronos
Ericsson distributed repair scheduler for Apache Cassandra
Stars: ✭ 22 (+29.41%)
Mutual labels:  cassandra
Phpfastcache
A high-performance backend cache system. It is intended for use in speeding up dynamic web applications by alleviating database load. Well implemented, it can drops the database load to almost nothing, yielding faster page load times for users, better resource utilization. It is simple yet powerful.
Stars: ✭ 2,171 (+12670.59%)
Mutual labels:  cassandra
Migrate
Database migrations. CLI and Golang library.
Stars: ✭ 2,315 (+13517.65%)
Mutual labels:  cassandra
Alia
High performance Cassandra client for clojure
Stars: ✭ 224 (+1217.65%)
Mutual labels:  cassandra
rsocket-rpc-js
Standard RSocket RPC Implementation
Stars: ✭ 29 (+70.59%)
Mutual labels:  reactive-streams

Troilus

PLEASE NOTE that the development has been stopped. This project will be removed

Build Status

Discussion group: Troilus discussion group

Troilus is a high level Cassandra Java client on the top of the DataStax Java Driver for Apache Cassandra. It supports synchronous programming and asynchronous programming.

The main features of Troilus are

  • providing a Java8-based Interface as well as a Java7-based interface (module troilus-core-java7)
  • Supporting sync as well as async programming
  • reactive streams support
  • (Entity) Bean-Mapping support for tables and user defined data types (incl. mapping support of generic artefacts such as Java8/Guava Optional and Guava ImmutableCollections)
  • Build-in data swap check
  • Build-in prepared statement management
  • Implementation support for data-related constraint checks (mandatory fields, more complex data swap validation checks, …)

#Maven

Java8-based

<dependency>
	<groupId>net.oneandone.troilus</groupId>
	<artifactId>troilus-core</artifactId>
	<version>0.18</version>
</dependency>

Java7-based

<dependency>
	<groupId>net.oneandone.troilus</groupId>
	<artifactId>troilus-core-java7</artifactId>
	<version>0.18</version>
</dependency>

#Examples

##Create a Dao First a DataStax Java Driver Session object has to be created

Cluster cluster = Cluster.builder()
                         .addContactPoint(node)
                         .build();
Session session = cluster.connect("ks_hotel_reservation_system");

This Session object will be used to create a new instance of a Dao. In the examples below the hotels table is used

Dao hotelsDao = new DaoImpl(session, "hotels");

Pre-configured dao

Dao hotelsDao = new DaoImpl(session, "hotels")
                          .withConsistency(ConsistencyLevel.LOCAL_QUORUM);

Please consider that creating the initial DaoImpl instance is a relatively expensive operation. For instance the underlying table structure will be loaded to get some meta data. Furthermore internal caches such as the prepared statement cache will be fresh. This is not true by calling the with... methods which returns a Dao instance. In this case the meta data, caches, etc. of the initially Dao will be inherited.

For this reason avoid creating the DaoImpl instance again and again. Typically a new DaoImpl instance will be created within the initialization phase of the program (may be in a lazy manner).

##Write Write a row in a column-oriented way

hotelsDao.writeWithKey("id", "BUP932432")
         .value("name", "City Budapest")
         .value("room_ids", ImmutableSet.of("1", "2", "3", "122", "123", "124", "322", "333"))
         .value("classification", ClassifierEnum.FOUR)
         .withWritetime(microsSinceEpoch)
         .execute();

Write a row in an entity-oriented way.

hotel = new Hotel("BUP14334", 
                  "Richter Panzio",
       	          ImmutableSet.of("1", "2", "3", "4", "5"),
                  Optional.of(ClassifierEnum.TWO),
                  Optional.empty());

hotelsDao.writeEntity(hotel)
         .execute();

The columns will be mapped by using @Field annotated fields. The JEE @Column annotation is also supported for compatibility reasons. However, the name field is supported only

public class Hotel  {
   
    @Field(name = "id")
    private String id = null;
    
    @Field(name = "name")
    private String name = null;

    @Field(name = "room_ids")
    private ImmutableSet<String> roomIds = ImmutableSet.of();

    @Field(name = "classification")
    private Optional<ClassifierEnum> classification = Optional.empty();
    
    @Field(name = "description")
    private Optional<String> description = Optional.empty();

    @Field(name = "phone")
    private Optional<String> phone = Optional.empty();

    
    
    @SuppressWarnings("unused")
    private Hotel() { }
    
    public Hotel(String id, 
                 String name, 
                 ImmutableSet<String> roomIds,  
                 Optional<ClassifierEnum> classification, 
                 Optional<String> description,
                 Optional<String> phone) {
        this.id = id;
        this.name = name;
        this.roomIds = roomIds;
        this.classification = classification;
        this.description = description;
        this.phone = phone;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }
    
    public ImmutableSet<String> getRoomIds() {
        return roomIds;
    }

    public Optional<ClassifierEnum> getClassification() {
        return classification;
    }

    public Optional<String> getDescription() {
        return description;
    }

    public Optional<String> getPhone() {
        return phone;
    }
}

updating values

hotelsDao.writeWithKey("id","BUP932432")
         .value("description", "The City Budapest is in the business district on the Pest side of the river.")
         .execute();

removing values

hotelsDao.writeWithKey("id","BUP932432")
         .value("description", Optional.empty())  
         .execute();

or

hotelsDao.writeWithKey("id","BUP932432")
         .value("description", null)  
         .execute();

value update based on where conditions

hotelsDao.writeWhere(QueryBuilder.in("id", "BUP932432", "BUP233544", "BUP2433"))
         .value("classification", ClassifierEnum.FOUR)
         .execute();

Collections support

add an entry to a set

usersDao.writeWithKey(UsersTable.USER_ID, "3f9ac8c0-d3aa-11e5-ab30-625662870761")
        .addSetValue("emails", "[email protected]")           
        .execute();

remove an entry from a set

usersDao.writeWithKey(UsersTable.USER_ID, "3f9ac8c0-d3aa-11e5-ab30-625662870761")
        .removeSetValue("emails", "[email protected]")           
        .execute();

append an entry to the end of the list

usersDao.writeWithKey(UsersTable.USER_ID, "3f9ac8c0-d3aa-11e5-ab30-625662870761")
        .appendListValue("top_places", "london")           
        .execute();

prepend an entry to the top of the list

usersDao.writeWithKey(UsersTable.USER_ID, "3f9ac8c0-d3aa-11e5-ab30-625662870761")
        .prependListValue("top_places", "paris")           
        .execute();

delete an entry from a list

usersDao.writeWithKey(UsersTable.USER_ID, "3f9ac8c0-d3aa-11e5-ab30-625662870761")
        .removeListValue("top_places", "london")           
        .execute();

put an entry to a map

usersDao.writeWithKey(UsersTable.USER_ID, "3f9ac8c0-d3aa-11e5-ab30-625662870761")
        .putMapValue("todo", "2015-9-24" : "fix bug")           
        .execute();

remove an entry from a set (delete has to be used instead of write)

usersDao.deleteWithKey(UsersTable.USER_ID, "3f9ac8c0-d3aa-11e5-ab30-625662870761")
        .removeMapValue("todo", "2015-9-24")           
        .execute();

##Delete

hotelsDao.deleteWithKey("id", "BUP932432")
         .execute();

lightweight transactions

transaction-safe, unique insert with ifNotExists()(will perform the insertion only, if the row does not already exist)

try {
   hotelsDao.writeWithKey("id", "BUP932432")
            .value("name", "City Budapest")
            .value("room_ids", ImmutableSet.of("1", "2", "3", "122", "123", "124", "322", "333"))
            .value("classification", ClassifierEnum.FOUR)
            .withWritetime(microsSinceEpoch)
            .ifNotExists()
            .withSerialConsistency(ConsistencyLevel.SERIAL)
            .execute();
         
} catch (IfConditionException ice) {
   // ...
}

transaction-safe, conditional update with onlyIf(..conditions..) (uses IF followed by a condition to be met for the update to succeed)

try {
   hotelsDao.writeWithKey("id", "BUP932432")
            .value("name" "Budapest City")
            .onlyIf(QueryBuilder.eq("name", "City Budapest"))
            .withSerialConsistency(ConsistencyLevel.SERIAL)
            .execute();
                                 
} catch (IfConditionException ice) {
   // ...
}

transaction-safe, conditional delete with onlyIf(..conditions..) (uses IF followed by a condition to be met for the update to succeed)

try {
   hotelsDao.deleteWithKey("id","BUP932432")
            .onlyIf(QueryBuilder.eq("name", "Budapest City"))
            .withSerialConsistency(ConsistencyLevel.SERIAL)
            .execute();
                                
} catch (IfConditionException ice) {
   // ...
}         

transaction-safe delete with ifExists

try {
   hotelsDao.deleteWithKey("id","BUP932432")
            .ifExists()
            .withSerialConsistency(ConsistencyLevel.SERIAL)
            .execute();
                                
} catch (IfConditionException ice) {
   // ...
}         

##Batching
Non if-conditional mutate operations (insert, update, delete) can be executed in a batched manner by combining it with another mutate operation. This is provided by the combinedWith(...) method.

Deletion deletion = hotelsDao.deleteWithKey("id", "BUP932432");

hotelsDao.deleteWithKey("id", "BUP14334")
         .combinedWith(deletion)
         .withWriteAheadLog()
         .execute();

##Read ###Read a single row

Read a row in an entity-oriented way.

Optional<Hotel> optionalHotel = hotelsDao.readWithKey("id", "BUP45544")
                                         .asEntity(Hotel.class)
                                         .execute();
optionalHotel.ifPresent(hotel -> System.out.println(hotel.getName()));

Read a row in a column-oriented way

Optional<Record> optionalRecord = hotelsDao.readWithKey("id", "BUP14334")
                                           .column("id")
                                           .column("name")
                                           .withConsistency(ConsistencyLevel.LOCAL_ONE)
                                           .execute();
optionalRecord.ifPresent(record -> System.out.println(record.getString("name")));

Read a row in a column-oriented way with Name definitions.

import static ....HotelTableColumns.*;

Optional<Record> optionalRecord = hotelsDao.readWithKey(ID, "BUP3443")
                                           .column(NAME)
                                           .column(CLASSIFICATION)
                                           .execute();
optionalRecord.ifPresent(record -> System.out.println(record.getValue(NAME)));
optionalRecord.ifPresent(record -> System.out.println(record.getValue(CLASSIFICATION)));

with definitions

public final class HotelTableColumns  {
    public static final ColumnName<String> ID = ColumnName.defineString("id");
    public static final ColumnName<String> NAME = ColumnName.defineString("name");
    public static final ColumnName<Set<String>> ROOM_IDS = ColumnName.defineSet("room_ids", String.class);
    public static final ColumnName<Address> ADDRESS = ColumnName.define("address", Address.class);
    public static final ColumnName<String> DESCRIPTION = ColumnName.defineString("description");
    public static final ColumnName<ClassifierEnum> CLASSIFICATION = ColumnName.define("classification", ClassifierEnum.class);
}

Read with meta data (ttl, writetime)

Record record = hotelsDao.readWithKey("id", "BUP14334")
                         .column("id")
         	             .column("name")
            	         .columnWithMetadata("description")
                         .withConsistency(ConsistencyLevel.LOCAL_ONE)
                         .execute()
                         .get();
                                           
System.out.println("ttl=" + record.getTtl("description")));

###Read a list of rows

Read all of the table

Iterable<Hotel> hotelIterator = hotelsDao.readSequence()
                                         .asEntity(Hotel.class)
                                         .withLimit(5000)
                                         .execute();
hotelIterator.forEach(hotel -> System.out.println(hotel));

Read specific ones by using conditions

Iterable<Hotel> hotelIterator = hotelsDao.readSequenceWhere(QueryBuilder.in("ID", "BUP45544", "BUP14334"))
                                         .asEntity(Hotel.class)
                                         .withAllowFiltering()
                                         .execute();
hotelIterator.forEach(hotel -> System.out.println(hotel));                

#User-defined types support

to use the user-defined types support a Java class which represents the user-defined type has to be implemented. The fields to be mapped have to be annotated with @Field

public class Hotel  {
   
    @Field(name = "id")
    private String id = null;
    
    @Field(name = "name")
    private String name = null;

    @Field(name = "room_ids")
    private ImmutableSet<String> roomIds = ImmutableSet.of();

    @Field(name = "classification")
    private Optional<ClassifierEnum> classification = Optional.empty();
    
    @Field(name = "description")
    private Optional<String> description = Optional.empty();

    @Field(name = "address")
    private Address address = null;

    @Field(name = "phone")
    private Optional<String> phone = Optional.empty();

    
    
    @SuppressWarnings("unused")
    private Hotel() { }
    
    public Hotel(String id, 
                 String name, 
                 ImmutableSet<String> roomIds,  
                 Optional<ClassifierEnum> classification, 
                 Optional<String> description,
                 Address address,
                 Optional<String> phone) {
        this.id = id;
        this.name = name;
        this.roomIds = roomIds;
        this.classification = classification;
        this.description = description;
        this.address = address;
        this.phone = phone;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }
    
    public ImmutableSet<String> getRoomIds() {
        return roomIds;
    }

    public Optional<ClassifierEnum> getClassification() {
        return classification;
    }

    public Optional<String> getDescription() {
        return description;
    }
    
    public Address getAddress() {
        return address;
    }
    
    public Optional<String> getPhone() {
        return phone;
    }
}

##Write

Write a row in a column-oriented way

hotelsDao.writeWithKey("id", "BUP932432")
         .value("name", "City Budapest")
         .value("room_ids", ImmutableSet.of("1", "2", "3", "122", "123", "124", "322", "333"))
         .value("classification", ClassifierEnum.FOUR)
         .value("address", new Address("Thököly Ut 111", "Budapest", "1145"))
         .withWritetime(microsSinceEpoch)
         .execute();

Write a row in a entity-oriented way

hotel = new Hotel("BUP14334", 
                  "Richter Panzio",
                  ImmutableSet.of("1", "2", "3", "4", "5"),
                  Optional.of(ClassifierEnum.TWO),
                  Optional.empty(),
                  new Address("Thököly Ut 111", "Budapest", "1145"));

hotelsDao.writeEntity(hotel)
         .execute();
public class Hotel  {
   
    @Field(name = "id")
    private String id = null;
    
    @Field(name = "name")
    private String name = null;

    @Field(name = "room_ids")
    private ImmutableSet<String> roomIds = ImmutableSet.of();

    @Field(name = "classification")
    private Optional<ClassifierEnum> classification = Optional.empty();
    
    @Field(name = "description")
    private Optional<String> description = Optional.empty();

    @Field(name = "address")
    private Address address = null;

        
    
    @SuppressWarnings("unused")
    private Hotel() { }
    
    public Hotel(String id, 
                 String name, 
                 ImmutableSet<String> roomIds,  
                 Optional<ClassifierEnum> classification, 
                 Optional<String> description,
                 Address address) {
        this.id = id;
        this.name = name;
        this.roomIds = roomIds;
        this.classification = classification;
        this.description = description;
        this.address = address;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }
    
    public ImmutableSet<String> getRoomIds() {
        return roomIds;
    }

    public Optional<ClassifierEnum> getClassification() {
        return classification;
    }

    public Optional<String> getDescription() {
        return description;
    }
    
    public Address getAddress() {
        return address;
    }
}

##Read

Read a row in a entity-oriented way

hotel = hotelsDao.readWithKey("id", "BUP14334")
                 .asEntity(Hotel.class)
                 .execute()
                 .get();
        
System.out.println(hotel.getAddress());

Read a row in a column-oriented way

record = hotelsDao.readWithKey("id", "BUP14334")
                  .column("id")
                  .column("name")
                  .column("classification")
                  .column("address")
                  .withConsistency(ConsistencyLevel.LOCAL_ONE)
                  .execute()
                  .get();
        
System.out.println(record.getString("classification"));
System.out.println(record.getObject("address", Address.class));

#Asynchronous Examples

##Async Write By calling executeAsync() instead execute() the method returns immediately without waiting for the database response. Further more the executeAsync() returns a Java8 CompletableFuture object which can be used for async processing

hotel = new Hotel("BUP14334", 
                  "Richter Panzio", 
                  Optional.of(ClassifierEnum.TWO), 
                  Optional.empty());
                  
CompletableFuture<Result> future = hotelsDao.writeEntity(hotel)
                                            .withConsistency(ConsistencyLevel.ANY)
                                            .executeAsync();

##Async Read

As already mentioned above the methods returns immediately without waiting for the database response. The consumer code within the thenAccept(...) method will be called as soon as the database response is received.

read single row

hotelsDao.readWithKey("id", "BUP45544")
         .asEntity(Hotel.class)
	     .executeAsync()
         .thenAccept(optionalHotel.ifPresent(hotel -> System.out.println(hotel));

read a list of rows. Please consider that the Iterator has a blocking behavior which means the streaming of the result could block

hotelsDao.readSequence()
         .asEntity(Hotel.class)
         .withLimit(5000)
         .executeAsync()
         .thenAccept(hotelIt -> hotelIt.forEach(hotel -> System.out.println(hotel)));

##Reactive streams Read For true asynchronous streaming executeRx() can be called which returns a reactive streams Publisher

Publisher<Hotel> hotelPublisher = hotelsDao.readSequence()
                                           .asEntity(Hotel.class)
                                           .executeRx();
hotelPublisher.subscribe(new ConsoleSubscriber());

The Subscriber implements call back methods such as onNext(...) or onError(...) to process the result stream in a reactive way. By calling the hotels.subscribe(subscriber) above the onSubscribe(...) method of the subscriber below will be called.

import java.util.concurrent.atomic.AtomicReference;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;

public class ConsoleSubscriber implements Subscriber<Hotel> {
    private final AtomicReference<Subscription> subscriptionRef = new AtomicReference<>();
    //...
    
    @Override
    public void onSubscribe(Subscription subscription) {
        this.subscriptionRef.set(subscription);
        subscription.request(1);  // here, requesting elements starts the streaming implicitly
    }
    
    @Override
    public void onNext(Hotel hotel) {
        System.out.println(obj);
        subscription.request(1);   // request one more element
    }
    
    @Override
    public void onComplete() {
        //..
    }
    
    @Override
    public void onError(Throwable t) {
        //..
    }
}

#Interceptor Examples The interceptor support can be used to implement (more complex) constraint checks on the client-side (Cassandra also supports server-side trigger which can also be used to implement contraints). To register interceptors the Dao supports the withInterceptor(...) method.

Dao phoneNumbersDao = new DaoImpl(getSession(), "phone_numbers");
       
Dao phoneNumbersDaoWithConstraints = phoneNumbersDao.withInterceptor(new PhonenumbersConstraints(deviceDao))
												    .withInterceptor(ConstraintsInterceptor.newConstraints()
                                                                                           .withNotNullColumn("device_id")
                                                                                           .withImmutableColumn("device_id"));

##ConstraintsInterceptor Examples To implement simple constraints the ConstraintsInterceptor can be used

Dao phoneNumbersDaoWithConstraints = phoneNumbersDao.withInterceptor(ConstraintsInterceptor.newConstraints()
                                                                                           .withNotNullColumn("device_id"));

##More Complexe Interceptor Examples The interceptor below implements a back relation check regarding the phone_numbers table.

class PhonenumbersConstraints implements ReadQueryRequestInterceptor,
                                         ReadQueryResponseInterceptor {
    
    private final Dao deviceDao;
    
    public PhonenumbersConstraints(Dao deviceDao) {
        this.deviceDao = deviceDao.withConsistency(ConsistencyLevel.QUORUM);
    }
        
    
    @Override
    public CompletableFuture<ReadQueryData> onReadRequestAsync(ReadQueryData queryData) {
        // force that device_id will be fetched 
        if (!queryData.getColumnsToFetch().containsKey("device_id")) {
            queryData = queryData.columnsToFetch(Immutables.merge(queryData.getColumnsToFetch(), "device_id", false));
        }
        return CompletableFuture.completedFuture(queryData);
    }
    

    @Override
    public CompletableFuture<ResultList<Record>> onReadResponseAsync(ReadQueryData queryData, ResultList<Record> recordList) {
        return CompletableFuture.completedFuture(new VaildatingRecordList(recordList, deviceDao));
    }
    
    
    private static final class VaildatingRecordList extends RecordListAdapter {
     
        private final Dao deviceDao;

        
        public VaildatingRecordList(RecordList recordList, Dao deviceDao) {
            super(recordList);
            this.deviceDao = deviceDao;
        }
        
        @Override
        public Iterator<Record> iterator() {
            return new ValidatingIterator(super.iterator());
        }

        
        private final class ValidatingIterator implements Iterator<Record> {
            private Iterator<Record> it;
            
            public ValidatingIterator(Iterator<Record> it) {
                this.it = it;
            }
            
            @Override
            public boolean hasNext() {
                return it.hasNext();
            }
            
            
            @Override
            public Record next() {
                
                Record record = it.next();
                
                Optional<Record> deviceRecord = deviceDao.readWithKey("device_id", record.getString("device_id"))
                                                         .column("phone_numbers")
                                                         .withConsistency(ConsistencyLevel.ONE)
                                                         .execute();
                
                deviceRecord.ifPresent(rec -> {
                                                ImmutableSet<String> set = rec.getSet("phone_numbers", String.class);
                                                if (!set.isEmpty() && !set.contains(record.getString("number"))) {
                                                    throw new ConstraintException("reverse reference devices table -> phone_numbers table does not exit");
                                                }
                                              });
                
                return record;
            }
        }
    }
}

##OnCascade Interceptor Examples To add cascading queries to the current queries the CascadeOnWriteInterceptor and CascadeOnDeleteInterceptor can be used. Please consider that in this case the current queries becomes a write ahead logged batch query. For this reason the CascadeOn interceptors works for non if-conditional mutate operations (insert, update, delete) only

Dao keyByAccountDao = new DaoImpl(session, KeyByAccountColumns.TABLE);
Dao keyByEmailDao = new DaoImpl(session, KeyByEmailColumns.TABLE);
        
keyByAccountDao = keyByAccountDao.withInterceptor(new KeyByAccountColumns.CascadeToByEmailDao(keyByAccountDao, keyByEmailDao));
//...



public interface KeyByAccountColumns  {
   
    public static final String TABLE = "key_by_accountid";
    
    public static final ColumnName<String> ACCOUNT_ID = ColumnName.defineString("account_id");
    public static final ColumnName<byte[]> KEY = ColumnName.defineBytes("key");
    public static final ColumnName<Set<TupleValue>> EMAIL_IDX = ColumnName.defineSet("email_idx", TupleValue.class);
    
    
    
    public static final class CascadeToByEmailDao implements CascadeOnWriteInterceptor, CascadeOnDeleteInterceptor {
        private final Dao keyByAccountDao;
        private final Dao keyByEmailDao;
        
        public CascadeToByEmailDao(Dao keyByAccountDao, Dao keyByEmailDao) {
            this.keyByAccountDao = keyByAccountDao;
            this.keyByEmailDao = keyByEmailDao;
        }

        @Override
        public CompletableFuture<ImmutableSet<? extends Batchable<?>>> onWrite(WriteQueryData queryData) {
            
            // this interceptor does not support where condition based queries
            if (!queryData.getWhereConditions().isEmpty()) {
                throw new InvalidQueryException("where condition based queries are not supported");
            }
            
            if (queryData.hasKey(ACCOUNT_ID) && queryData.hasValueToMutate(KEY) && queryData.hasSetValuesToAddOrSet(EMAIL_IDX)) {
                List<Write> writes = Lists.newArrayList();
                for (TupleValue tupleValue : queryData.getSetValuesToAddOrSet(EMAIL_IDX)) {
                    writes.add(keyByEmailDao.writeWithKey(KeyByEmailColumns.EMAIL, tupleValue.getString(0), KeyByEmailColumns.CREATED, tupleValue.getLong(1))
                                            .value(KeyByEmailColumns.KEY, queryData.getValueToMutate(KEY))
                                            .value(KeyByEmailColumns.ACCOUNT_ID, queryData.getKey(ACCOUNT_ID))
                                            .withConsistency(ConsistencyLevel.QUORUM));
                }
                return CompletableFuture.completedFuture(ImmutableSet.copyOf(writes));
                
            } else {
                return CompletableFuture.completedFuture(ImmutableSet.of());
            }
        }
        
        
        @Override
        public CompletableFuture<ImmutableSet<? extends Batchable<?>>> onDelete(DeleteQueryData queryData) {

            // this interceptor does not support where condition based queries
            if (!queryData.getWhereConditions().isEmpty()) {
                throw new InvalidQueryException("where condition based queries are not supported");
            }
                
            // resolve dependent records
            return keyByAccountDao.readWithKey(queryData.getKey())
                                  .withConsistency(ConsistencyLevel.QUORUM)
                                  .executeAsync()
                                  .thenApply(optionalRecord -> optionalRecord.map(record -> getDeletions(record)).orElse(ImmutableSet.of()));
        }
        
        
        private ImmutableSet<Deletion> getDeletions(Record record) {
            List<Deletion> deletions = Lists.newArrayList();
            for (TupleValue tupleValue : record.getValue(KeyByAccountColumns.EMAIL_IDX)) {
                deletions.add(keyByEmailDao.deleteWithKey(KeyByEmailColumns.EMAIL, tupleValue.getString(0), KeyByEmailColumns.CREATED, tupleValue.getLong(1))
                                           .withConsistency(ConsistencyLevel.QUORUM));
            }
            
            return ImmutableSet.copyOf(deletions);
        }
    }
}
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].