Spring Data for Apache CassandraのRepositoryでTTLを読み書きする

Spring DataのCrudRepository, ReactiveCrudRepositoryは汎用的な作りになっていて、CassandraのTTL機能を使うインターフェースがありません。

検索してみて日本語の情報が見当たらなかったので、Cassandraに書き込む時にTTLを指定する方法を書き残しておきます。

以下のバージョンで確認しています。
新しいバージョンでは事情が変わっているかもしれません。

例として、ユーザー情報を扱う UserRepository を作成していきます。

具体的には、以下のような構成でインターフェース、クラスを作成します。
(グレーのインターフェース, クラスはSpring Dataのクラスです)

CREATE TABLE users (
    id text,
    first_name text,
    last_name text,
    PRIMARY KEY (id)
);

書き込み時にTTLを設定するカスタムインターフェース UserTtlRepository を追加します。
動作確認のため、TTLの値を見るメソッドも追加しています。

public interface UserTtlRepository {

  /**
   * UserエンティティをTTL付きで保存する
   *
   * @param user ユーザー
   * @param ttl TTL
   * @return ユーザーのMono
   */
  Mono<User> save(User user, Duration ttl);

  /**
   * firstNameカラムのTTLを取得する
   *
   * @param id ユーザーID
   * @return TTLのMono
   */
  Mono<Duration> findFirstNameTtlById(String id);

  /**
   * lastNameカラムのTTLを取得する
   *
   * @param id ユーザーID
   * @return TTLのMono
   */
  Mono<Duration> findLastNameTtlById(String id);
}

UserRepositoy インターフェースを ReactiveCrudRepository だけでなく UserTtlRepository も継承させます。

@Repository
public interface UserRepository extends ReactiveCrudRepository<User, String>, UserTtlRepository {

}

カスタムインターフェースの実装クラス UserTtlRepositoryImpl を作成します。
実装クラスの名前は (カスタムインターフェース名) + Impl でないといけません。(repository-impl-postfixの設定で変えられるそうです)

public class UserTtlRepositoryImpl implements UserTtlRepository {

  private final ReactiveCassandraOperations reactiveCassandraOperations;

  public UserTtlRepositoryImpl(final ReactiveCassandraOperations reactiveCassandraOperations) {
    this.reactiveCassandraOperations = reactiveCassandraOperations;
  }

  @Override
  public Mono<User> save(final User user, final Duration ttl) {
    InsertOptions insertOptions = InsertOptions.builder().ttl(ttl).build();
    return reactiveCassandraOperations.insert(user, insertOptions)
        .map(EntityWriteResult::getEntity);
  }

  @Override
  public Mono<Duration> findFirstNameTtlById(final String id) {
    return findColumnTtlByIdAndColumnName(id, User.FIRST_NAME_COLUMN_NAME);
  }

  @Override
  public Mono<Duration> findLastNameTtlById(final String id) {
    return findColumnTtlByIdAndColumnName(id, User.LAST_NAME_COLUMN_NAME);
  }

  private Mono<Duration> findColumnTtlByIdAndColumnName(final String id, final String columnName) {
    SimpleStatement statement = QueryBuilder.selectFrom(User.TABLE_NAME)
        .ttl(columnName)
        .whereColumn(User.ID_COLUMN_NAME)
        .isEqualTo(literal(id))
        .build();

    return reactiveCassandraOperations.selectOne(statement, Integer.class)
        .map(Duration::ofSeconds);
  }
}

以上で UserRepository に TTL を操作するインターフェースを追加できました。
Springが UserRepository の実装を生成する時に UserTtlRepositoryImpl も組み込んでくれます。

このページで作ったコードは以下に置いてあります。
(動作確認のため結合テストもしてます)

https://github.com/massakai/spring-data-cassandra-example

参考

コメントする