Convert Figma logo to code with AI

square logosqlbrite

A lightweight wrapper around SQLiteOpenHelper which introduces reactive stream semantics to SQL operations.

4,570
420
4,570
5

Top Related Projects

47,834

RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.

24,672

Event bus for Android and Java that simplifies communication between Activities, Fragments, Threads, Services, etc. Less code, better quality.

Realm is a mobile database: a replacement for SQLite & ORMs

3,139

requery - modern SQL based query & persistence for Java / Kotlin / Android

4,872

A blazing fast, powerful, and very simple ORM android database library that writes database code for you.

Quick Overview

SQLBrite is a lightweight wrapper around SQLiteDatabase and ContentResolver that makes it easy to work with reactive queries. It provides a simple API for executing SQL queries and observing the results as a stream of data.

Pros

  • Reactive Approach: SQLBrite uses RxJava to provide a reactive API for working with SQL data, making it easier to handle asynchronous operations and data changes.
  • Lightweight: SQLBrite is a lightweight library that adds minimal overhead to your application, making it a good choice for performance-sensitive projects.
  • Abstraction over SQLiteDatabase: SQLBrite provides a higher-level abstraction over the SQLiteDatabase class, simplifying common database operations and reducing boilerplate code.
  • ContentResolver Support: SQLBrite can also be used to observe changes in ContentProvider data, making it a versatile tool for working with both local and remote data sources.

Cons

  • Dependency on RxJava: SQLBrite requires the use of RxJava, which may not be suitable for all projects or developers who are not familiar with reactive programming.
  • Limited Documentation: The project's documentation could be more comprehensive, which may make it more difficult for new users to get started.
  • Potential Learning Curve: Developers who are not familiar with reactive programming may need to invest time in learning the concepts and patterns used in SQLBrite.
  • Potential Performance Overhead: While SQLBrite is lightweight, the use of RxJava and the additional abstraction layer may introduce some performance overhead in certain scenarios.

Code Examples

Executing a Query

val query = "SELECT * FROM users WHERE name LIKE ?"
val args = arrayOf("%John%")

db.createQuery("users", query, *args)
    .map { it.getString(it.getColumnIndex("name")) }
    .subscribe { name -> println("User name: $name") }

This code demonstrates how to execute a SQL query using SQLBrite and observe the results as a stream of data.

Observing Changes in a Table

db.createQuery("users", "SELECT * FROM users")
    .subscribe { result ->
        // Process the result set
        while (result.moveToNext()) {
            val name = result.getString(result.getColumnIndex("name"))
            println("User name: $name")
        }
    }

This code shows how to observe changes in a database table using SQLBrite. Whenever the "users" table is updated, the subscriber will be notified and can process the new data.

Observing Changes in a ContentProvider

val uri = Uri.parse("content://com.example.provider/users")
contentResolver.createQuery(uri, null, null, null, null)
    .subscribe { cursor ->
        // Process the cursor
        while (cursor.moveToNext()) {
            val name = cursor.getString(cursor.getColumnIndex("name"))
            println("User name: $name")
        }
    }

This code demonstrates how to use SQLBrite to observe changes in a ContentProvider. The createQuery method is used to create an observable that emits the results of a ContentProvider query.

Getting Started

To get started with SQLBrite, you can follow these steps:

  1. Add the SQLBrite dependency to your project's build.gradle file:
dependencies {
    implementation 'com.squareup.sqlbrite3:sqlbrite:3.2.0'
}
  1. Create a SqlBrite.Builder instance and configure it with your database or ContentResolver:
val sqlBrite = SqlBrite.Builder()
    .logger { message -> Log.d("SQLBrite", message) }
    .build()

val db = sqlBrite.wrapDatabaseHelper(MyDatabaseHelper(context), Schedulers.io())
  1. Use the createQuery method to execute SQL queries and observe the results:
db.createQuery("users", "SELECT * FROM users")
    .map { it.getString(it.getColumnIndex("name")) }
    .subscribe { name -> println("User name: $name") }
  1. Observe changes in a ContentProvider:
val uri = Uri.parse("content://

Competitor Comparisons

47,834

RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.

Pros of RxJava

  • More comprehensive and versatile, offering a wide range of operators for complex reactive programming scenarios
  • Supports multiple programming paradigms beyond just database operations
  • Large community and extensive documentation

Cons of RxJava

  • Steeper learning curve due to its extensive API and concepts
  • Can be overkill for simple database operations
  • Potential performance overhead for basic tasks

Code Comparison

SQLBrite:

briteDatabase.createQuery(TABLE_NAME, QUERY)
    .mapToList(cursor -> {
        // Map cursor to object
    })
    .subscribe(items -> {
        // Handle items
    });

RxJava:

Observable.fromCallable(() -> {
    // Perform database query
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
    // Handle result
});

Key Differences

  • SQLBrite is specifically designed for reactive database operations in Android, while RxJava is a general-purpose reactive programming library
  • SQLBrite provides a simpler API for database queries, whereas RxJava offers more flexibility but requires more setup
  • RxJava can be used for a wider range of reactive programming scenarios beyond just database operations
24,672

Event bus for Android and Java that simplifies communication between Activities, Fragments, Threads, Services, etc. Less code, better quality.

Pros of EventBus

  • Simpler API and easier to implement for basic event-driven communication
  • Supports sticky events, allowing subscribers to receive the most recent event even if they weren't registered at the time of posting
  • Lightweight and has minimal impact on app size

Cons of EventBus

  • Can lead to less structured code and make it harder to track event flow
  • Lacks built-in RxJava integration, which SQLBrite offers out of the box
  • May require more manual memory management to avoid potential memory leaks

Code Comparison

EventBus:

EventBus.getDefault().post(new MessageEvent("Hello!"));

@Subscribe
public void onMessageEvent(MessageEvent event) {
    Log.d("EventBus", event.message);
}

SQLBrite:

Observable<Query> users = db.createQuery("users", "SELECT * FROM users");
users.subscribe(query -> {
    Cursor cursor = query.run();
    // Process cursor
});

While EventBus focuses on event-driven communication between components, SQLBrite is specifically designed for reactive database operations. EventBus offers a simpler API for general-purpose event handling, while SQLBrite provides a more specialized solution for database interactions with RxJava integration.

Realm is a mobile database: a replacement for SQLite & ORMs

Pros of Realm Java

  • Object-oriented database with a simple, intuitive API
  • Faster performance for complex queries and large datasets
  • Built-in support for reactive programming and real-time updates

Cons of Realm Java

  • Steeper learning curve for developers familiar with SQLite
  • Limited flexibility in database schema changes
  • Larger app size due to included Realm core library

Code Comparison

SQLBrite:

SqlBrite sqlBrite = SqlBrite.create();
BriteDatabase db = sqlBrite.wrapDatabaseHelper(dbHelper);

db.createQuery("users", "SELECT * FROM users")
    .mapToList(User::new)
    .subscribe(users -> {
        // Handle user list
    });

Realm Java:

Realm realm = Realm.getDefaultInstance();
RealmResults<User> users = realm.where(User.class).findAllAsync();
users.addChangeListener((results, changeSet) -> {
    // Handle user list updates
});

Both libraries offer reactive programming support, but Realm Java provides a more straightforward API for working with objects directly. SQLBrite requires more manual mapping between SQL results and objects, while Realm Java allows for direct object manipulation. Realm Java also offers built-in asynchronous queries and change listeners, making it easier to implement real-time updates in your app.

3,139

requery - modern SQL based query & persistence for Java / Kotlin / Android

Pros of requery

  • Supports multiple database types (SQLite, MySQL, PostgreSQL, etc.)
  • Provides an object-oriented query interface
  • Offers automatic schema generation and migration

Cons of requery

  • Steeper learning curve due to more complex API
  • Potentially higher overhead for simple database operations
  • Less focus on reactive programming compared to SQLBrite

Code Comparison

SQLBrite:

val query = SqlBrite.Query(
    "SELECT * FROM users WHERE age > ?",
    arrayOf("18")
)
query.run()
    .mapToList { cursor ->
        User(cursor.getString(cursor.getColumnIndex("name")))
    }
    .subscribe { users -> /* Handle result */ }

requery:

val result = data
    .select(User::class)
    .where(User::age.gt(18))
    .get()
    .toList()

Summary

SQLBrite is a lightweight SQLite wrapper with reactive extensions, while requery is a more comprehensive ORM solution. SQLBrite offers simplicity and reactive programming support, making it suitable for Android development. requery provides a broader set of features, including support for multiple databases and an object-oriented query interface, but may have a steeper learning curve. The choice between the two depends on project requirements and complexity.

4,872

A blazing fast, powerful, and very simple ORM android database library that writes database code for you.

Pros of DBFlow

  • More comprehensive ORM solution with advanced features like migrations and model caching
  • Supports multiple databases and custom database wrappers
  • Provides a fluent query API for complex queries

Cons of DBFlow

  • Steeper learning curve due to more complex API and features
  • Potentially higher overhead for simple database operations
  • Less flexibility for raw SQL queries compared to SQLBrite

Code Comparison

SQLBrite:

val query = SqlBrite.Query(rawQuery, tables)
query.run()
    .mapToList { cursor ->
        // Map cursor to object
    }
    .subscribe { results ->
        // Handle results
    }

DBFlow:

SQLite.select()
    .from(MyTable::class.java)
    .where(MyTable_Table.column.eq(value))
    .async()
    .queryListResultCallback { _, results ->
        // Handle results
    }
    .execute()

Both libraries offer reactive database operations, but DBFlow provides a more abstracted, ORM-style API, while SQLBrite focuses on enhancing raw SQL queries with reactive streams. DBFlow's approach may be more suitable for complex data models, while SQLBrite offers more direct control over SQL operations.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

SQL Brite

A lightweight wrapper around SupportSQLiteOpenHelper and ContentResolver which introduces reactive stream semantics to queries.

Deprecated

This library is no longer actively developed and is considered complete.

Its database features (and far, far more) are now offered by SQLDelight and its upgrading guide offers some migration help.

For content provider monitoring please use Copper instead.

Usage

Create a SqlBrite instance which is an adapter for the library functionality.

SqlBrite sqlBrite = new SqlBrite.Builder().build();

Pass a SupportSQLiteOpenHelper instance and a Scheduler to create a BriteDatabase.

BriteDatabase db = sqlBrite.wrapDatabaseHelper(openHelper, Schedulers.io());

A Scheduler is required for a few reasons, but the most important is that query notifications can trigger on the thread of your choice. The query can then be run without blocking the main thread or the thread which caused the trigger.

The BriteDatabase.createQuery method is similar to SupportSQLiteDatabase.query except it takes an additional parameter of table(s) on which to listen for changes. Subscribe to the returned Observable<Query> which will immediately notify with a Query to run.

Observable<Query> users = db.createQuery("users", "SELECT * FROM users");
users.subscribe(new Consumer<Query>() {
  @Override public void accept(Query query) {
    Cursor cursor = query.run();
    // TODO parse data...
  }
});

Unlike a traditional query, updates to the specified table(s) will trigger additional notifications for as long as you remain subscribed to the observable. This means that when you insert, update, or delete data, any subscribed queries will update with the new data instantly.

final AtomicInteger queries = new AtomicInteger();
users.subscribe(new Consumer<Query>() {
  @Override public void accept(Query query) {
    queries.getAndIncrement();
  }
});
System.out.println("Queries: " + queries.get()); // Prints 1

db.insert("users", SQLiteDatabase.CONFLICT_ABORT, createUser("jw", "Jake Wharton"));
db.insert("users", SQLiteDatabase.CONFLICT_ABORT, createUser("mattp", "Matt Precious"));
db.insert("users", SQLiteDatabase.CONFLICT_ABORT, createUser("strong", "Alec Strong"));

System.out.println("Queries: " + queries.get()); // Prints 4

In the previous example we re-used the BriteDatabase object "db" for inserts. All insert, update, or delete operations must go through this object in order to correctly notify subscribers.

Unsubscribe from the returned Subscription to stop getting updates.

final AtomicInteger queries = new AtomicInteger();
Subscription s = users.subscribe(new Consumer<Query>() {
  @Override public void accept(Query query) {
    queries.getAndIncrement();
  }
});
System.out.println("Queries: " + queries.get()); // Prints 1

db.insert("users", SQLiteDatabase.CONFLICT_ABORT, createUser("jw", "Jake Wharton"));
db.insert("users", SQLiteDatabase.CONFLICT_ABORT, createUser("mattp", "Matt Precious"));
s.unsubscribe();

db.insert("users", SQLiteDatabase.CONFLICT_ABORT, createUser("strong", "Alec Strong"));

System.out.println("Queries: " + queries.get()); // Prints 3

Use transactions to prevent large changes to the data from spamming your subscribers.

final AtomicInteger queries = new AtomicInteger();
users.subscribe(new Consumer<Query>() {
  @Override public void accept(Query query) {
    queries.getAndIncrement();
  }
});
System.out.println("Queries: " + queries.get()); // Prints 1

Transaction transaction = db.newTransaction();
try {
  db.insert("users", SQLiteDatabase.CONFLICT_ABORT, createUser("jw", "Jake Wharton"));
  db.insert("users", SQLiteDatabase.CONFLICT_ABORT, createUser("mattp", "Matt Precious"));
  db.insert("users", SQLiteDatabase.CONFLICT_ABORT, createUser("strong", "Alec Strong"));
  transaction.markSuccessful();
} finally {
  transaction.end();
}

System.out.println("Queries: " + queries.get()); // Prints 2

Note: You can also use try-with-resources with a Transaction instance.

Since queries are just regular RxJava Observable objects, operators can also be used to control the frequency of notifications to subscribers.

users.debounce(500, MILLISECONDS).subscribe(new Consumer<Query>() {
  @Override public void accept(Query query) {
    // TODO...
  }
});

The SqlBrite object can also wrap a ContentResolver for observing a query on another app's content provider.

BriteContentResolver resolver = sqlBrite.wrapContentProvider(contentResolver, Schedulers.io());
Observable<Query> query = resolver.createQuery(/*...*/);

The full power of RxJava's operators are available for combining, filtering, and triggering any number of queries and data changes.

Philosophy

SQL Brite's only responsibility is to be a mechanism for coordinating and composing the notification of updates to tables such that you can update queries as soon as data changes.

This library is not an ORM. It is not a type-safe query mechanism. It won't serialize the same POJOs you use for Gson. It's not going to perform database migrations for you.

Some of these features are offered by SQL Delight which can be used with SQL Brite.

Download

implementation 'com.squareup.sqlbrite3:sqlbrite:3.2.0'

For the 'kotlin' module that adds extension functions to Observable<Query>:

implementation 'com.squareup.sqlbrite3:sqlbrite-kotlin:3.2.0'

Snapshots of the development version are available in Sonatype's snapshots repository.

License

Copyright 2015 Square, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.