The Room 1.x FTS Recipe

Room 1.x cannot create an FTS table for us. However, Room can work with an FTS table, at least for data retrieval, using @RawQuery.

As a result, we can get partial support for FTS from Room, if we are willing to do the rest ourselves, using the support database API, such as what we use with migrations.

Manually Create the Table

First, we will need to manually create our FTS virtual table.

At minimum, we need to do this when we create the database. We can use a RoomDatabase.Callback object for that, as part of setting up our RoomDatabase.Builder:

    RoomDatabase.Builder<BookDatabase> b=
      Room.databaseBuilder(ctxt.getApplicationContext(), BookDatabase.class,
        DB_NAME);

    b.addCallback(new Callback() {
      @Override
      public void onCreate(@NonNull SupportSQLiteDatabase db) {
        super.onCreate(db);

        db.execSQL("CREATE VIRTUAL TABLE booksearch USING fts4(sequence, prose)");
      }
    });

    BookDatabase books=b.build();

RoomDatabase.Callback was covered in the chapter on the support database API.

Here, as part of setting up an instance of a BookDatabase, we request to get control when the database is created and add our own booksearch virtual table.

If you are adding the FTS table to an already-existing app, you will also need to create your FTS virtual table in the appropriate Migration object(s).

RawQuery the Table

To get data out of the virtual table, we can use a @RawQuery-annotated method on some @Dao class that references the table that we created manually. While @RawQuery can work with tables defined via Room entities, that is not a requirement. @RawQuery can work with any table, so long as Room can figure out how to map the columns that you request to the POJO that you want to return.

So, given some sort of BookSearchResult POJO that matches the booksearch table structure used above, we could have:

  @RawQuery
  protected abstract List<BookSearchResult> _searchSynchronous(SupportSQLiteQuery query);

Things get a bit tricky if we want a reactive response (e.g., Observable) or if we want to use paging, as we will see later in this chapter.

To put data into the virtual table, the official solution is to use a SupportSQLiteDatabase. You get one by calling getOpenHelper().getWritableDatabase() on your RoomDatabase. Then, just as we used one of those for a CREATE VIRTUAL TABLE statement (see above), we can use one for INSERT/UPDATE/DELETE statements or the corresponding insert(), update(), or delete() methods.

Unofficially, @RawQuery works for these as well:

  @RawQuery
  protected abstract long _insert(SupportSQLiteQuery queryish);

Prev Table of Contents Next

This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.