{"id":26002763,"url":"https://github.com/1and1/troilus","last_synced_at":"2025-03-05T19:30:17.741Z","repository":{"id":24670766,"uuid":"28081244","full_name":"1and1/Troilus","owner":"1and1","description":"Troilus is a Java client library for Cassandra.","archived":false,"fork":false,"pushed_at":"2022-05-30T09:03:47.000Z","size":2250,"stargazers_count":17,"open_issues_count":3,"forks_count":4,"subscribers_count":13,"default_branch":"master","last_synced_at":"2023-04-06T16:10:54.928Z","etag":null,"topics":["cassandra","datastax-java-driver","java","reactive-streams"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/1and1.png","metadata":{"files":{"readme":"README.md","changelog":"changes.txt","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-12-16T10:07:45.000Z","updated_at":"2023-02-16T19:22:59.000Z","dependencies_parsed_at":"2022-08-23T04:40:49.408Z","dependency_job_id":null,"html_url":"https://github.com/1and1/Troilus","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1and1%2FTroilus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1and1%2FTroilus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1and1%2FTroilus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/1and1%2FTroilus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/1and1","download_url":"https://codeload.github.com/1and1/Troilus/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242091100,"owners_count":20070279,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cassandra","datastax-java-driver","java","reactive-streams"],"created_at":"2025-03-05T19:30:16.910Z","updated_at":"2025-03-05T19:30:17.696Z","avatar_url":"https://github.com/1and1.png","language":"Java","readme":"\nTroilus\n======\n\nPLEASE NOTE that the development has been stopped. This project will be removed\n\n[![Build Status](https://travis-ci.org/1and1/Troilus.svg)](https://travis-ci.org/1and1/Troilus)\n\n**Discussion group**: [Troilus discussion group](https://groups.google.com/forum/#!forum/troilus)\n\n**Troilus** is a high level Cassandra Java client on the top of the [DataStax Java Driver for Apache Cassandra](https://github.com/datastax/java-driver). \nIt supports synchronous programming and asynchronous programming.\n\nThe main features of Troilus are \n* providing a Java8-based Interface as well as a Java7-based interface (module troilus-core-java7)\n* Supporting sync as well as async programming\n* [reactive streams](http://www.reactive-streams.org) support\n* (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)\n* Build-in data swap check \n* Build-in prepared statement management \n* Implementation support for data-related constraint checks (mandatory fields, more complex data swap validation checks, …)          \n\n#Maven\n-------\nJava8-based\n``` java\n\u003cdependency\u003e\n\t\u003cgroupId\u003enet.oneandone.troilus\u003c/groupId\u003e\n\t\u003cartifactId\u003etroilus-core\u003c/artifactId\u003e\n\t\u003cversion\u003e0.18\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n\nJava7-based\n``` java\n\u003cdependency\u003e\n\t\u003cgroupId\u003enet.oneandone.troilus\u003c/groupId\u003e\n\t\u003cartifactId\u003etroilus-core-java7\u003c/artifactId\u003e\n\t\u003cversion\u003e0.18\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n\n#Examples\n-------\n\n##Create a Dao\nFirst a DataStax Java Driver [Session](https://github.com/datastax/java-driver) object has to be created\n``` java\nCluster cluster = Cluster.builder()\n                         .addContactPoint(node)\n                         .build();\nSession session = cluster.connect(\"ks_hotel_reservation_system\");\n```\n\n\n\nThis Session object will be used to create a new instance of a `Dao`. In the examples below the [hotels table](troilus-core/src/test/resources/com/unitedinternet/troilus/example/hotels.ddl) is used\n``` java\nDao hotelsDao = new DaoImpl(session, \"hotels\");\n```\n\nPre-configured dao\n``` java\nDao hotelsDao = new DaoImpl(session, \"hotels\")\n                          .withConsistency(ConsistencyLevel.LOCAL_QUORUM);\n```\n\nPlease 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. \n \nFor 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). \n     \n\n\n##Write\nWrite a row in a column-oriented way\n``` java\nhotelsDao.writeWithKey(\"id\", \"BUP932432\")\n         .value(\"name\", \"City Budapest\")\n         .value(\"room_ids\", ImmutableSet.of(\"1\", \"2\", \"3\", \"122\", \"123\", \"124\", \"322\", \"333\"))\n         .value(\"classification\", ClassifierEnum.FOUR)\n         .withWritetime(microsSinceEpoch)\n         .execute();\n```\n\n\nWrite a row in an entity-oriented way.  \n``` java\nhotel = new Hotel(\"BUP14334\", \n                  \"Richter Panzio\",\n       \t          ImmutableSet.of(\"1\", \"2\", \"3\", \"4\", \"5\"),\n                  Optional.of(ClassifierEnum.TWO),\n                  Optional.empty());\n\nhotelsDao.writeEntity(hotel)\n         .execute();\n```\n\nThe columns will be mapped by using `@Field` annotated fields. The JEE [`@Column`](http://docs.oracle.com/javaee/7/api/javax/persistence/Column.html) annotation is also supported for compatibility reasons. However, the name field is supported only  \n``` java\npublic class Hotel  {\n   \n    @Field(name = \"id\")\n    private String id = null;\n    \n    @Field(name = \"name\")\n    private String name = null;\n\n    @Field(name = \"room_ids\")\n    private ImmutableSet\u003cString\u003e roomIds = ImmutableSet.of();\n\n    @Field(name = \"classification\")\n    private Optional\u003cClassifierEnum\u003e classification = Optional.empty();\n    \n    @Field(name = \"description\")\n    private Optional\u003cString\u003e description = Optional.empty();\n\n    @Field(name = \"phone\")\n    private Optional\u003cString\u003e phone = Optional.empty();\n\n    \n    \n    @SuppressWarnings(\"unused\")\n    private Hotel() { }\n    \n    public Hotel(String id, \n                 String name, \n                 ImmutableSet\u003cString\u003e roomIds,  \n                 Optional\u003cClassifierEnum\u003e classification, \n                 Optional\u003cString\u003e description,\n                 Optional\u003cString\u003e phone) {\n        this.id = id;\n        this.name = name;\n        this.roomIds = roomIds;\n        this.classification = classification;\n        this.description = description;\n        this.phone = phone;\n    }\n\n    public String getId() {\n        return id;\n    }\n\n    public String getName() {\n        return name;\n    }\n    \n    public ImmutableSet\u003cString\u003e getRoomIds() {\n        return roomIds;\n    }\n\n    public Optional\u003cClassifierEnum\u003e getClassification() {\n        return classification;\n    }\n\n    public Optional\u003cString\u003e getDescription() {\n        return description;\n    }\n\n    public Optional\u003cString\u003e getPhone() {\n        return phone;\n    }\n}\n```\n\n\n### updating values\n``` java\nhotelsDao.writeWithKey(\"id\",\"BUP932432\")\n         .value(\"description\", \"The City Budapest is in the business district on the Pest side of the river.\")\n         .execute();\n  ```               \n\n### removing values\n``` java\nhotelsDao.writeWithKey(\"id\",\"BUP932432\")\n         .value(\"description\", Optional.empty())  \n         .execute();\n```             \n\nor\n``` java\nhotelsDao.writeWithKey(\"id\",\"BUP932432\")\n         .value(\"description\", null)  \n         .execute();\n```  \n\n\n### value update based on where conditions\n``` java\nhotelsDao.writeWhere(QueryBuilder.in(\"id\", \"BUP932432\", \"BUP233544\", \"BUP2433\"))\n         .value(\"classification\", ClassifierEnum.FOUR)\n         .execute();\n```               \n\n## Collections support\nadd an entry to a set\n``` java\nusersDao.writeWithKey(UsersTable.USER_ID, \"3f9ac8c0-d3aa-11e5-ab30-625662870761\")\n        .addSetValue(\"emails\", \"me@example.org\")           \n        .execute();\n```               \n\nremove an entry from a set\n``` java\nusersDao.writeWithKey(UsersTable.USER_ID, \"3f9ac8c0-d3aa-11e5-ab30-625662870761\")\n        .removeSetValue(\"emails\", \"you@example.org\")           \n        .execute();\n```         \n\nappend an entry to the end of the list\n``` java\nusersDao.writeWithKey(UsersTable.USER_ID, \"3f9ac8c0-d3aa-11e5-ab30-625662870761\")\n        .appendListValue(\"top_places\", \"london\")           \n        .execute();\n```               \n\nprepend an entry to the top of the list\n``` java\nusersDao.writeWithKey(UsersTable.USER_ID, \"3f9ac8c0-d3aa-11e5-ab30-625662870761\")\n        .prependListValue(\"top_places\", \"paris\")           \n        .execute();\n```               \n\ndelete an entry from a list\n``` java\nusersDao.writeWithKey(UsersTable.USER_ID, \"3f9ac8c0-d3aa-11e5-ab30-625662870761\")\n        .removeListValue(\"top_places\", \"london\")           \n        .execute();\n```               \n\nput an entry to a map\n``` java\nusersDao.writeWithKey(UsersTable.USER_ID, \"3f9ac8c0-d3aa-11e5-ab30-625662870761\")\n        .putMapValue(\"todo\", \"2015-9-24\" : \"fix bug\")           \n        .execute();\n```               \n\nremove an entry from a set (delete has to be used instead of write)\n``` java\nusersDao.deleteWithKey(UsersTable.USER_ID, \"3f9ac8c0-d3aa-11e5-ab30-625662870761\")\n        .removeMapValue(\"todo\", \"2015-9-24\")           \n        .execute();\n```                         \n        \n##Delete\n\n``` java\nhotelsDao.deleteWithKey(\"id\", \"BUP932432\")\n         .execute();\n```\n\n        \n\n### lightweight transactions \ntransaction-safe, ***unique insert*** with `ifNotExists()`(will perform the insertion only, if the row does not already exist)        \n``` java\ntry {\n   hotelsDao.writeWithKey(\"id\", \"BUP932432\")\n            .value(\"name\", \"City Budapest\")\n            .value(\"room_ids\", ImmutableSet.of(\"1\", \"2\", \"3\", \"122\", \"123\", \"124\", \"322\", \"333\"))\n            .value(\"classification\", ClassifierEnum.FOUR)\n            .withWritetime(microsSinceEpoch)\n            .ifNotExists()\n            .withSerialConsistency(ConsistencyLevel.SERIAL)\n            .execute();\n         \n} catch (IfConditionException ice) {\n   // ...\n}\n```  \n        \ntransaction-safe, ***conditional update*** with `onlyIf(..conditions..)` (uses IF followed by a condition to be met for the update to succeed)        \n``` java\ntry {\n   hotelsDao.writeWithKey(\"id\", \"BUP932432\")\n            .value(\"name\" \"Budapest City\")\n            .onlyIf(QueryBuilder.eq(\"name\", \"City Budapest\"))\n            .withSerialConsistency(ConsistencyLevel.SERIAL)\n            .execute();\n                                 \n} catch (IfConditionException ice) {\n   // ...\n}\n```  \n       \n\ntransaction-safe, ***conditional delete*** with `onlyIf(..conditions..)` (uses IF followed by a condition to be met for the update to succeed)        \n``` java\ntry {\n   hotelsDao.deleteWithKey(\"id\",\"BUP932432\")\n            .onlyIf(QueryBuilder.eq(\"name\", \"Budapest City\"))\n            .withSerialConsistency(ConsistencyLevel.SERIAL)\n            .execute();\n                                \n} catch (IfConditionException ice) {\n   // ...\n}         \n```  \n  \n  \ntransaction-safe ***delete*** with `ifExists` \n``` java\ntry {\n   hotelsDao.deleteWithKey(\"id\",\"BUP932432\")\n            .ifExists()\n            .withSerialConsistency(ConsistencyLevel.SERIAL)\n            .execute();\n                                \n} catch (IfConditionException ice) {\n   // ...\n}         \n```  \n\n\n\n##Batching        \nNon 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. \n``` java\nDeletion deletion = hotelsDao.deleteWithKey(\"id\", \"BUP932432\");\n\nhotelsDao.deleteWithKey(\"id\", \"BUP14334\")\n         .combinedWith(deletion)\n         .withWriteAheadLog()\n         .execute();\n```\n\n\n##Read\n###Read a single row\n\nRead a row in an entity-oriented way.  \n``` java        \nOptional\u003cHotel\u003e optionalHotel = hotelsDao.readWithKey(\"id\", \"BUP45544\")\n                                         .asEntity(Hotel.class)\n                                         .execute();\noptionalHotel.ifPresent(hotel -\u003e System.out.println(hotel.getName()));\n```        \n\nRead a row in a column-oriented way\n``` java        \nOptional\u003cRecord\u003e optionalRecord = hotelsDao.readWithKey(\"id\", \"BUP14334\")\n                                           .column(\"id\")\n                                           .column(\"name\")\n                                           .withConsistency(ConsistencyLevel.LOCAL_ONE)\n                                           .execute();\noptionalRecord.ifPresent(record -\u003e System.out.println(record.getString(\"name\")));\n```        \n\nRead a row in a column-oriented way with `Name` definitions. \n``` java        \nimport static ....HotelTableColumns.*;\n\nOptional\u003cRecord\u003e optionalRecord = hotelsDao.readWithKey(ID, \"BUP3443\")\n                                           .column(NAME)\n                                           .column(CLASSIFICATION)\n                                           .execute();\noptionalRecord.ifPresent(record -\u003e System.out.println(record.getValue(NAME)));\noptionalRecord.ifPresent(record -\u003e System.out.println(record.getValue(CLASSIFICATION)));\n```        \n\n\nwith definitions\n``` java        \npublic final class HotelTableColumns  {\n    public static final ColumnName\u003cString\u003e ID = ColumnName.defineString(\"id\");\n    public static final ColumnName\u003cString\u003e NAME = ColumnName.defineString(\"name\");\n    public static final ColumnName\u003cSet\u003cString\u003e\u003e ROOM_IDS = ColumnName.defineSet(\"room_ids\", String.class);\n    public static final ColumnName\u003cAddress\u003e ADDRESS = ColumnName.define(\"address\", Address.class);\n    public static final ColumnName\u003cString\u003e DESCRIPTION = ColumnName.defineString(\"description\");\n    public static final ColumnName\u003cClassifierEnum\u003e CLASSIFICATION = ColumnName.define(\"classification\", ClassifierEnum.class);\n}\n```        \n\n\n\nRead with meta data (ttl, writetime)\n``` java        \nRecord record = hotelsDao.readWithKey(\"id\", \"BUP14334\")\n                         .column(\"id\")\n         \t             .column(\"name\")\n            \t         .columnWithMetadata(\"description\")\n                         .withConsistency(ConsistencyLevel.LOCAL_ONE)\n                         .execute()\n                         .get();\n                                           \nSystem.out.println(\"ttl=\" + record.getTtl(\"description\")));\n```        \n\n  \n\n###Read a list of rows\n\nRead all of the table\n``` java  \nIterable\u003cHotel\u003e hotelIterator = hotelsDao.readSequence()\n                                         .asEntity(Hotel.class)\n                                         .withLimit(5000)\n                                         .execute();\nhotelIterator.forEach(hotel -\u003e System.out.println(hotel));\n```        \n        \n\nRead specific ones by using conditions\n``` java  \nIterable\u003cHotel\u003e hotelIterator = hotelsDao.readSequenceWhere(QueryBuilder.in(\"ID\", \"BUP45544\", \"BUP14334\"))\n                                         .asEntity(Hotel.class)\n                                         .withAllowFiltering()\n                                         .execute();\nhotelIterator.forEach(hotel -\u003e System.out.println(hotel));                \n```        \n        \n\n      \n#User-defined types support\n-------\n\nto 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`\n\n\n``` java\npublic class Hotel  {\n   \n    @Field(name = \"id\")\n    private String id = null;\n    \n    @Field(name = \"name\")\n    private String name = null;\n\n    @Field(name = \"room_ids\")\n    private ImmutableSet\u003cString\u003e roomIds = ImmutableSet.of();\n\n    @Field(name = \"classification\")\n    private Optional\u003cClassifierEnum\u003e classification = Optional.empty();\n    \n    @Field(name = \"description\")\n    private Optional\u003cString\u003e description = Optional.empty();\n\n    @Field(name = \"address\")\n    private Address address = null;\n\n    @Field(name = \"phone\")\n    private Optional\u003cString\u003e phone = Optional.empty();\n\n    \n    \n    @SuppressWarnings(\"unused\")\n    private Hotel() { }\n    \n    public Hotel(String id, \n                 String name, \n                 ImmutableSet\u003cString\u003e roomIds,  \n                 Optional\u003cClassifierEnum\u003e classification, \n                 Optional\u003cString\u003e description,\n                 Address address,\n                 Optional\u003cString\u003e phone) {\n        this.id = id;\n        this.name = name;\n        this.roomIds = roomIds;\n        this.classification = classification;\n        this.description = description;\n        this.address = address;\n        this.phone = phone;\n    }\n\n    public String getId() {\n        return id;\n    }\n\n    public String getName() {\n        return name;\n    }\n    \n    public ImmutableSet\u003cString\u003e getRoomIds() {\n        return roomIds;\n    }\n\n    public Optional\u003cClassifierEnum\u003e getClassification() {\n        return classification;\n    }\n\n    public Optional\u003cString\u003e getDescription() {\n        return description;\n    }\n    \n    public Address getAddress() {\n        return address;\n    }\n    \n    public Optional\u003cString\u003e getPhone() {\n        return phone;\n    }\n}\n```\n\n\n\n##Write\n\nWrite a row in a column-oriented way\n``` java\nhotelsDao.writeWithKey(\"id\", \"BUP932432\")\n         .value(\"name\", \"City Budapest\")\n         .value(\"room_ids\", ImmutableSet.of(\"1\", \"2\", \"3\", \"122\", \"123\", \"124\", \"322\", \"333\"))\n         .value(\"classification\", ClassifierEnum.FOUR)\n         .value(\"address\", new Address(\"Thököly Ut 111\", \"Budapest\", \"1145\"))\n         .withWritetime(microsSinceEpoch)\n         .execute();\n```\n\n\nWrite a row in a entity-oriented way\n``` java\nhotel = new Hotel(\"BUP14334\", \n                  \"Richter Panzio\",\n                  ImmutableSet.of(\"1\", \"2\", \"3\", \"4\", \"5\"),\n                  Optional.of(ClassifierEnum.TWO),\n                  Optional.empty(),\n                  new Address(\"Thököly Ut 111\", \"Budapest\", \"1145\"));\n\nhotelsDao.writeEntity(hotel)\n         .execute();\n```\n\n``` java\npublic class Hotel  {\n   \n    @Field(name = \"id\")\n    private String id = null;\n    \n    @Field(name = \"name\")\n    private String name = null;\n\n    @Field(name = \"room_ids\")\n    private ImmutableSet\u003cString\u003e roomIds = ImmutableSet.of();\n\n    @Field(name = \"classification\")\n    private Optional\u003cClassifierEnum\u003e classification = Optional.empty();\n    \n    @Field(name = \"description\")\n    private Optional\u003cString\u003e description = Optional.empty();\n\n    @Field(name = \"address\")\n    private Address address = null;\n\n        \n    \n    @SuppressWarnings(\"unused\")\n    private Hotel() { }\n    \n    public Hotel(String id, \n                 String name, \n                 ImmutableSet\u003cString\u003e roomIds,  \n                 Optional\u003cClassifierEnum\u003e classification, \n                 Optional\u003cString\u003e description,\n                 Address address) {\n        this.id = id;\n        this.name = name;\n        this.roomIds = roomIds;\n        this.classification = classification;\n        this.description = description;\n        this.address = address;\n    }\n\n    public String getId() {\n        return id;\n    }\n\n    public String getName() {\n        return name;\n    }\n    \n    public ImmutableSet\u003cString\u003e getRoomIds() {\n        return roomIds;\n    }\n\n    public Optional\u003cClassifierEnum\u003e getClassification() {\n        return classification;\n    }\n\n    public Optional\u003cString\u003e getDescription() {\n        return description;\n    }\n    \n    public Address getAddress() {\n        return address;\n    }\n}\n```\n\n\n\n##Read\n\nRead a row in a entity-oriented way\n``` java\nhotel = hotelsDao.readWithKey(\"id\", \"BUP14334\")\n                 .asEntity(Hotel.class)\n                 .execute()\n                 .get();\n        \nSystem.out.println(hotel.getAddress());\n```\n\n\nRead a row in a column-oriented way\n``` java\nrecord = hotelsDao.readWithKey(\"id\", \"BUP14334\")\n                  .column(\"id\")\n                  .column(\"name\")\n                  .column(\"classification\")\n                  .column(\"address\")\n                  .withConsistency(ConsistencyLevel.LOCAL_ONE)\n                  .execute()\n                  .get();\n        \nSystem.out.println(record.getString(\"classification\"));\nSystem.out.println(record.getObject(\"address\", Address.class));\n```\n\n\n        \n#Asynchronous Examples\n-------\n\n##Async Write\nBy calling `executeAsync()` instead `execute()` the method returns immediately without waiting for the database response. Further more the `executeAsync()` returns a Java8 [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) object which can be used for async processing\n``` java\nhotel = new Hotel(\"BUP14334\", \n                  \"Richter Panzio\", \n                  Optional.of(ClassifierEnum.TWO), \n                  Optional.empty());\n                  \nCompletableFuture\u003cResult\u003e future = hotelsDao.writeEntity(hotel)\n                                            .withConsistency(ConsistencyLevel.ANY)\n                                            .executeAsync();\n```\n\n\n##Async Read\n\nAs 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. \n\nread single row\n``` java\nhotelsDao.readWithKey(\"id\", \"BUP45544\")\n         .asEntity(Hotel.class)\n\t     .executeAsync()\n         .thenAccept(optionalHotel.ifPresent(hotel -\u003e System.out.println(hotel));\n```\n\n\nread a list of rows. Please consider that the Iterator has a blocking behavior which means the streaming of the result could block\n``` java\nhotelsDao.readSequence()\n         .asEntity(Hotel.class)\n         .withLimit(5000)\n         .executeAsync()\n         .thenAccept(hotelIt -\u003e hotelIt.forEach(hotel -\u003e System.out.println(hotel)));\n```\n\n\n##Reactive streams Read\nFor true asynchronous streaming `executeRx()` can be called which returns a reactive streams [Publisher](http://www.reactive-streams.org)   \n``` java\nPublisher\u003cHotel\u003e hotelPublisher = hotelsDao.readSequence()\n                                           .asEntity(Hotel.class)\n                                           .executeRx();\nhotelPublisher.subscribe(new ConsoleSubscriber());\n```\n\nThe 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.\n``` java\nimport java.util.concurrent.atomic.AtomicReference;\nimport org.reactivestreams.Subscriber;\nimport org.reactivestreams.Subscription;\n\npublic class ConsoleSubscriber implements Subscriber\u003cHotel\u003e {\n    private final AtomicReference\u003cSubscription\u003e subscriptionRef = new AtomicReference\u003c\u003e();\n    //...\n    \n    @Override\n    public void onSubscribe(Subscription subscription) {\n        this.subscriptionRef.set(subscription);\n        subscription.request(1);  // here, requesting elements starts the streaming implicitly\n    }\n    \n    @Override\n    public void onNext(Hotel hotel) {\n        System.out.println(obj);\n        subscription.request(1);   // request one more element\n    }\n    \n    @Override\n    public void onComplete() {\n        //..\n    }\n    \n    @Override\n    public void onError(Throwable t) {\n        //..\n    }\n}\n```\n\n\n\n\n#Interceptor Examples\nThe interceptor support can be used to implement (more complex) constraint checks on the client-side  (Cassandra also supports server-side [trigger](http://www.datastax.com/documentation/cql/3.1/cql/cql_reference/trigger_r.html) which can also be used to implement contraints). To register interceptors the `Dao` supports the `withInterceptor(...)` method.\n\n``` java\nDao phoneNumbersDao = new DaoImpl(getSession(), \"phone_numbers\");\n       \nDao phoneNumbersDaoWithConstraints = phoneNumbersDao.withInterceptor(new PhonenumbersConstraints(deviceDao))\n\t\t\t\t\t\t\t\t\t\t\t\t    .withInterceptor(ConstraintsInterceptor.newConstraints()\n                                                                                           .withNotNullColumn(\"device_id\")\n                                                                                           .withImmutableColumn(\"device_id\"));\n```\n\n##ConstraintsInterceptor Examples\nTo implement simple constraints the  `ConstraintsInterceptor` can be used \n``` java\nDao phoneNumbersDaoWithConstraints = phoneNumbersDao.withInterceptor(ConstraintsInterceptor.newConstraints()\n                                                                                           .withNotNullColumn(\"device_id\"));\n```\n\n##More Complexe Interceptor Examples\nThe interceptor below implements a back relation check regarding the [phone_numbers](troilus-core/src/test/resources/com/unitedinternet/troilus/example/phone_numbers.ddl) table. \n``` java\nclass PhonenumbersConstraints implements ReadQueryRequestInterceptor,\n                                         ReadQueryResponseInterceptor {\n    \n    private final Dao deviceDao;\n    \n    public PhonenumbersConstraints(Dao deviceDao) {\n        this.deviceDao = deviceDao.withConsistency(ConsistencyLevel.QUORUM);\n    }\n        \n    \n    @Override\n    public CompletableFuture\u003cReadQueryData\u003e onReadRequestAsync(ReadQueryData queryData) {\n        // force that device_id will be fetched \n        if (!queryData.getColumnsToFetch().containsKey(\"device_id\")) {\n            queryData = queryData.columnsToFetch(Immutables.merge(queryData.getColumnsToFetch(), \"device_id\", false));\n        }\n        return CompletableFuture.completedFuture(queryData);\n    }\n    \n\n    @Override\n    public CompletableFuture\u003cResultList\u003cRecord\u003e\u003e onReadResponseAsync(ReadQueryData queryData, ResultList\u003cRecord\u003e recordList) {\n        return CompletableFuture.completedFuture(new VaildatingRecordList(recordList, deviceDao));\n    }\n    \n    \n    private static final class VaildatingRecordList extends RecordListAdapter {\n     \n        private final Dao deviceDao;\n\n        \n        public VaildatingRecordList(RecordList recordList, Dao deviceDao) {\n            super(recordList);\n            this.deviceDao = deviceDao;\n        }\n        \n        @Override\n        public Iterator\u003cRecord\u003e iterator() {\n            return new ValidatingIterator(super.iterator());\n        }\n\n        \n        private final class ValidatingIterator implements Iterator\u003cRecord\u003e {\n            private Iterator\u003cRecord\u003e it;\n            \n            public ValidatingIterator(Iterator\u003cRecord\u003e it) {\n                this.it = it;\n            }\n            \n            @Override\n            public boolean hasNext() {\n                return it.hasNext();\n            }\n            \n            \n            @Override\n            public Record next() {\n                \n                Record record = it.next();\n                \n                Optional\u003cRecord\u003e deviceRecord = deviceDao.readWithKey(\"device_id\", record.getString(\"device_id\"))\n                                                         .column(\"phone_numbers\")\n                                                         .withConsistency(ConsistencyLevel.ONE)\n                                                         .execute();\n                \n                deviceRecord.ifPresent(rec -\u003e {\n                                                ImmutableSet\u003cString\u003e set = rec.getSet(\"phone_numbers\", String.class);\n                                                if (!set.isEmpty() \u0026\u0026 !set.contains(record.getString(\"number\"))) {\n                                                    throw new ConstraintException(\"reverse reference devices table -\u003e phone_numbers table does not exit\");\n                                                }\n                                              });\n                \n                return record;\n            }\n        }\n    }\n}\n```\n\n\n##OnCascade Interceptor Examples\nTo 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   \n \n``` java\nDao keyByAccountDao = new DaoImpl(session, KeyByAccountColumns.TABLE);\nDao keyByEmailDao = new DaoImpl(session, KeyByEmailColumns.TABLE);\n        \nkeyByAccountDao = keyByAccountDao.withInterceptor(new KeyByAccountColumns.CascadeToByEmailDao(keyByAccountDao, keyByEmailDao));\n//...\n\n\n\npublic interface KeyByAccountColumns  {\n   \n    public static final String TABLE = \"key_by_accountid\";\n    \n    public static final ColumnName\u003cString\u003e ACCOUNT_ID = ColumnName.defineString(\"account_id\");\n    public static final ColumnName\u003cbyte[]\u003e KEY = ColumnName.defineBytes(\"key\");\n    public static final ColumnName\u003cSet\u003cTupleValue\u003e\u003e EMAIL_IDX = ColumnName.defineSet(\"email_idx\", TupleValue.class);\n    \n    \n    \n    public static final class CascadeToByEmailDao implements CascadeOnWriteInterceptor, CascadeOnDeleteInterceptor {\n        private final Dao keyByAccountDao;\n        private final Dao keyByEmailDao;\n        \n        public CascadeToByEmailDao(Dao keyByAccountDao, Dao keyByEmailDao) {\n            this.keyByAccountDao = keyByAccountDao;\n            this.keyByEmailDao = keyByEmailDao;\n        }\n\n        @Override\n        public CompletableFuture\u003cImmutableSet\u003c? extends Batchable\u003c?\u003e\u003e\u003e onWrite(WriteQueryData queryData) {\n            \n            // this interceptor does not support where condition based queries\n            if (!queryData.getWhereConditions().isEmpty()) {\n                throw new InvalidQueryException(\"where condition based queries are not supported\");\n            }\n            \n            if (queryData.hasKey(ACCOUNT_ID) \u0026\u0026 queryData.hasValueToMutate(KEY) \u0026\u0026 queryData.hasSetValuesToAddOrSet(EMAIL_IDX)) {\n                List\u003cWrite\u003e writes = Lists.newArrayList();\n                for (TupleValue tupleValue : queryData.getSetValuesToAddOrSet(EMAIL_IDX)) {\n                    writes.add(keyByEmailDao.writeWithKey(KeyByEmailColumns.EMAIL, tupleValue.getString(0), KeyByEmailColumns.CREATED, tupleValue.getLong(1))\n                                            .value(KeyByEmailColumns.KEY, queryData.getValueToMutate(KEY))\n                                            .value(KeyByEmailColumns.ACCOUNT_ID, queryData.getKey(ACCOUNT_ID))\n                                            .withConsistency(ConsistencyLevel.QUORUM));\n                }\n                return CompletableFuture.completedFuture(ImmutableSet.copyOf(writes));\n                \n            } else {\n                return CompletableFuture.completedFuture(ImmutableSet.of());\n            }\n        }\n        \n        \n        @Override\n        public CompletableFuture\u003cImmutableSet\u003c? extends Batchable\u003c?\u003e\u003e\u003e onDelete(DeleteQueryData queryData) {\n\n            // this interceptor does not support where condition based queries\n            if (!queryData.getWhereConditions().isEmpty()) {\n                throw new InvalidQueryException(\"where condition based queries are not supported\");\n            }\n                \n            // resolve dependent records\n            return keyByAccountDao.readWithKey(queryData.getKey())\n                                  .withConsistency(ConsistencyLevel.QUORUM)\n                                  .executeAsync()\n                                  .thenApply(optionalRecord -\u003e optionalRecord.map(record -\u003e getDeletions(record)).orElse(ImmutableSet.of()));\n        }\n        \n        \n        private ImmutableSet\u003cDeletion\u003e getDeletions(Record record) {\n            List\u003cDeletion\u003e deletions = Lists.newArrayList();\n            for (TupleValue tupleValue : record.getValue(KeyByAccountColumns.EMAIL_IDX)) {\n                deletions.add(keyByEmailDao.deleteWithKey(KeyByEmailColumns.EMAIL, tupleValue.getString(0), KeyByEmailColumns.CREATED, tupleValue.getLong(1))\n                                           .withConsistency(ConsistencyLevel.QUORUM));\n            }\n            \n            return ImmutableSet.copyOf(deletions);\n        }\n    }\n}\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F1and1%2Ftroilus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F1and1%2Ftroilus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F1and1%2Ftroilus/lists"}