AutoValueGson + SQLDelight

Fabio Lee
FabioHub
Published in
2 min readApr 2, 2017

Extends from my previous post Retrofit 2 + AutoValueGson, I’m trying to add a database for the project. I choose to use ContentProvider due to the benefit of ContentObserver, with the help of SQLDelight to generate all the necessary fields in Java model.

I first create an User.sq file under src/main/sqldelight/{package}/User.sq, it will generated as UserModel.java interface file under {package} package.

CREATE TABLE IF NOT EXISTS user (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
login TEXT NOT NULL,
id INTEGER NOT NULL,
avatarUrl TEXT,
UNIQUE (login) ON CONFLICT REPLACE
);

drop_table:
DROP TABLE IF EXISTS user;

selectAll:
SELECT *
FROM user;

insertRow:
INSERT INTO user(login, id, avatarUrl)
VALUES (?, ?, ?);

Then I rename UserBean.

@AutoValue
public abstract class UserBean {
public abstract String login();

public abstract int id();

@Nullable
public abstract String avatarUrl();

public static UserModel create(String login, int id, @Nullable String avatarUrl) {
return new AutoValue_UserModel(login, id, avatarUrl);
}


public static TypeAdapter<UserModel> typeAdapter(Gson gson) {
return new AutoValue_UserModel.GsonTypeAdapter(gson);
}
}

Change it to User implements UserModel.

@AutoValue
public abstract class User implements UserModel {
public static final Factory<User> FACTORY = new Factory<>(
(_id, login, id, avatarUrl) -> new AutoValue_User(null, login, id, avatarUrl));
public static final RowMapper<User> SELECT_ALL_MAPPER = FACTORY.selectAllMapper();


public static TypeAdapter<User> typeAdapter(Gson gson) {
return new AutoValue_User.GsonTypeAdapter(gson);
}

public ContentValues asContentValues() {
return new Marshal(this).asContentValues();
}

}

In order to create or drop a table, it can simply call to User.CREATE_TABLE or User.DROP_TABLE.

public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "app.db";
private static final int DATABASE_VERSION = 1;

private static DatabaseHelper instance;

public static DatabaseHelper getInstance(Context context) {
if (instance == null) {
instance = new DatabaseHelper(context.getApplicationContext());
}
return instance;
}

private DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(User.CREATE_TABLE);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(User.DROP_TABLE);
onCreate(db);
}
}

For select record from a table, it can use UserModel.Mapper#map(Cursor) to convert an Cursor to User.

For insert record into a table, it can use UserModel.Marshal#asContentValues() to convert an User to ContentValues.

public class SqlBriteHelper {
private final ContentResolver contentResolver;
private final BriteContentResolver briteResolver;

@Inject
public SqlBriteHelper(ContentResolver contentResolver) {
this.contentResolver = contentResolver;
this.briteResolver = new SqlBrite.Builder()
.build()
.wrapContentProvider(contentResolver, Schedulers.io());
}

public Observable<List<User>> getUserList() {
return briteResolver.createQuery(User.CONTENT_URI, null, null, null, null, false)
.mapToList(User.SELECT_ALL_MAPPER::map);
}

public Observable<List<User>> setUserList(List<User> userList) {
return Observable.defer(() -> {
for (User user : userList) {
contentResolver.insert(User.CONTENT_URI, user.asContentValues());
}
return Observable.just(userList);
});
}
}

The full project can be found at GitHub.

--

--