In Lalafo for Android we use SQLite database, because it’s fast, flexible and it’s SQL. However, if you want to use SQLite, then you have to deal with
CursorValues and write your SQL statement in Java code.
This a lot of boilerplate code! Also, an SQL statement in Java code is difficult to read, maintain, and easy to break. Thanks to the guys from Square, we have a solution to the problems described above.
Our battle with the OutOfMemory army
In the world of startups and rapid mobile development, developers can drown in an ocean of new features and forget…
SQLBrite requires knowledge in RxJava, because it’s based on it. If you’re not familiar with RxJava, then first read about Rx.
SQLBrite is a lightweight wrapper around
ContentResolverwhich introduces reactive stream semantics to queries.
This means - that we can make our database observable. So, whenever we change a database table’s data set (insert, update or delete row) we get notified that the data set has been changed. There’s no magic, under the hood it’s implementation of Event bus pattern, which is based on RxJava.
or you can use
All queries will be executed by Scheduler that you pass in the method by default.
BriteDatabase.createQuery() is the wrap method of
SQLiteDatabase.rawQuery(). It adds an additional parameter, table name(s). In Event bus pattern, you subscribe to some event, in SQLBrite you subscribe to a particular table(s). That’s why you need to specify the table(s). When you change table’s data set, SQLBrite will recognize in what table it was changed, then check if this table has subscribers and simply rerun the SQL query for each subscriber and call
onNext() with the new query result. Note that each query Observable will remain subscribed (until unsubscribed).
Insert, Update, Delete
BriteDatabas wrap all
SQLiteDatabase methods you need to insert, update and delete data.
As you can see the first parameter is also table name (you can specify only one table name). When the data was successfully changed
BriteDatabase send a trigger to subscribers. Note if you want that your subscribers get the notification about data changed, you need to change your data through
SQLBrite also provides a wrapper for the transaction. It does all that do
SQLiteDatabase transaction API. However, the main idea of this wrapper is to prevent sending triggers to subscribers when you change data in a transaction. The trigger will be sent only after the transaction has ended.
Under the hood
How do trigger works?
As I said above, everything based on the Event bus pattern. The core of SQLBrite is
PublishSubject<Set<String>> triggers. It only emits table name(s). When you call a method to change a data set in the table, the table name (that you passed as a parameter) posts to the
How do query and subscriptions work?
All stuff happens in the code below.
tableFilter —the set of tables that we pass when creating query observable and when the trigger happens we filter only those tables that we have subscribed;
.map(query) — map observable to query type. Every time, when we get notified, the observable returns the same query object;
.startWith(query) — emit query when we subscribe to observable;
.observeOn(scheduler) — this is a scheduler that you pass when setup SQLBrite;
.compose(queryTransformer) — this transformer you also can set when doing a setup in SQLBrite. It’s useful when you need custom logging;
.doOnSubscribe(this.ensureNotInTransaction); — we cannot subscribe to an observable in a transaction;
Also SQLBrite provide operators to map
mapToList() — for a list of rows (if your query result is empty use
switchIfEmpty() operators to emit default value if need);
mapToOne() — for single row;
mapToOneOrDefault() — if the result is empty (0 rows) emit default value;
mapToOptional() — like
mapToOne(), but return
Thanks for reading. Stay tuned! Next time we’ll talk about type safety, compiler errors for SQL statement and other cool features of SQLDelight.