-
Notifications
You must be signed in to change notification settings - Fork 16
@BindDataSource
This annotation decorate an interface to define a datasource associated to a database schema. Between its attributes there is a DAO collection. Every DAO is defined by an interface annotated with @BindDao. Every DAO and is associated to a specific Java class which is associated to a specific table.
A data source class name have to finish with DataSource
suffix.
List of attributes is:
-
asyncTask: if true, generate async task name
Bind<data source name without DataSource prefix>AsyncTask
-
cursorWrapper: if true, generate a wrapped cursor for every Java class managed by data-source. Cursor's name is
Bind<data source name without DataSource prefix>Cursor
. - daoSet: the collection of DAO associated to data-source.
- fileName: filename used to store database
- rx: enable reactive programming support. It's necessary to include in project RX dependencies.
- log: controls generation of the log of SQL on logcat.
- typeAdapters: Global sql-type-adapters. These adapters are applied to every property that adapter supports. See Global-SQL-Type-adapter for more information.
- version: database version. The default version is 1.
Consider this interface to define a data source:
@BindDataSource(daoSet = {PersonDao.class}, fileName = "feature01.db")
public interface SampleDataSource {
}
With this interface, it is defined a data source name SampleDataSource
and is referred a DAO named PersonDao
.
When Kripton annotation processor process interface SampleDataSource
, it generate a class name BindSampleDataSource
similar to:
/**
* <p>
* Represents implementation of datasource SampleDataSource.
* This class expose database interface through Dao attribute.
* </p>
*
* <p><strong>This class is generated by Kripton Annotation Processor (3.0.2)</strong></p>
*
* @since Thu Nov 30 22:40:47 CET 2017
* @see SampleDataSource
* @see BindSampleDaoFactory
* @see PersonDao
* @see PersonDaoImpl
* @see Person
*/
public class BindSampleDataSource extends AbstractDataSource implements BindSampleDaoFactory, SampleDataSource {
/**
* <p>datasource singleton</p>
*/
static BindSampleDataSource instance;
/**
* <p>dao instance</p>
*/
protected PersonDaoImpl personDao = new PersonDaoImpl(this);
/**
* Used only in transactions (that can be executed one for time */
private final DataSourceSingleThread _daoFactorySingleThread = new DataSourceSingleThread();
protected BindSampleDataSource(DataSourceOptions options) {
super("feature01.db", 1, options);
}
@Override
public PersonDaoImpl getPersonDao() {
return personDao;
}
/**
* <p>Executes a transaction. This method <strong>is thread safe</strong> to avoid concurrent problems. Thedrawback is only one transaction at time can be executed. The database will be open in write mode. This method uses default error listener to intercept errors.</p>
*
* @param transaction
* transaction to execute
*/
public void execute(Transaction transaction) {
execute(transaction, onErrorListener);
}
/**
* <p>Executes a transaction. This method <strong>is thread safe</strong> to avoid concurrent problems. Thedrawback is only one transaction at time can be executed. The database will be open in write mode.</p>
*
* @param transaction
* transaction to execute
* @param onErrorListener
* error listener
*/
public void execute(Transaction transaction, AbstractDataSource.OnErrorListener onErrorListener) {
boolean needToOpened=!this.isOpenInWriteMode();
@SuppressWarnings("resource")
SQLiteDatabase connection=needToOpened ? openWritableDatabase() : database();
try {
connection.beginTransaction();
if (transaction!=null && TransactionResult.COMMIT == transaction.onExecute(_daoFactorySingleThread.bindToThread())) {
connection.setTransactionSuccessful();
}
} catch(Throwable e) {
Logger.error(e.getMessage());
e.printStackTrace();
if (onErrorListener!=null) onErrorListener.onError(e);
} finally {
try {
connection.endTransaction();
} catch (Throwable e) {
Logger.warn("error closing transaction %s", e.getMessage());
}
if (needToOpened) { close(); }
}
}
/**
* <p>Executes a batch opening a read only connection. This method <strong>is thread safe</strong> to avoid concurrent problems.</p>
*
* @param commands
* batch to execute
*/
public <T> T executeBatch(Batch<T> commands) {
return executeBatch(commands, false);
}
/**
* <p>Executes a batch. This method <strong>is thread safe</strong> to avoid concurrent problems. Thedrawback is only one transaction at time can be executed. if <code>writeMode</code> is set to false, multiple batch operations is allowed.</p>
*
* @param commands
* batch to execute
* @param writeMode
* true to open connection in write mode, false to open connection in read only mode
*/
public <T> T executeBatch(Batch<T> commands, boolean writeMode) {
boolean needToOpened=writeMode?!this.isOpenInWriteMode(): !this.isOpen();
if (needToOpened) { if (writeMode) { openWritableDatabase(); } else { openReadOnlyDatabase(); }}
try {
if (commands!=null) {
return commands.onExecute(new DataSourceSingleThread());
}
} catch(Throwable e) {
Logger.error(e.getMessage());
e.printStackTrace();
throw(e);
} finally {
if (needToOpened) { close(); }
}
return null;
}
/**
* instance
*/
public static synchronized BindSampleDataSource instance() {
if (instance==null) {
instance=new BindSampleDataSource(null);
}
return instance;
}
/**
* Retrieve data source instance and open it.
* @return opened dataSource instance.
*/
public static BindSampleDataSource open() {
BindSampleDataSource instance=instance();
instance.openWritableDatabase();
return instance;
}
/**
* Retrieve data source instance and open it in read only mode.
* @return opened dataSource instance.
*/
public static BindSampleDataSource openReadOnly() {
BindSampleDataSource instance=instance();
instance.openReadOnlyDatabase();
return instance;
}
/**
* onCreate
*/
@Override
public void onCreate(SQLiteDatabase database) {
// generate tables
// log section BEGIN
if (this.logEnabled) {
Logger.info("Create database '%s' version %s",this.name, this.getVersion());
}
// log section END
// log section BEGIN
if (this.logEnabled) {
Logger.info("DDL: %s",PersonTable.CREATE_TABLE_SQL);
}
// log section END
database.execSQL(PersonTable.CREATE_TABLE_SQL);
// if we have a populate task (previous and current are same), try to execute it
if (options.updateTasks != null) {
SQLiteUpdateTask task = findPopulateTaskList(database.getVersion());
if (task != null) {
// log section BEGIN
if (this.logEnabled) {
Logger.info("Begin update database from version %s to %s", task.previousVersion, task.currentVersion);
}
// log section END
task.execute(database);
// log section BEGIN
if (this.logEnabled) {
Logger.info("End update database from version %s to %s", task.previousVersion, task.currentVersion);
}
// log section END
}
}
if (options.databaseLifecycleHandler != null) {
options.databaseLifecycleHandler.onCreate(database);
}
}
/**
* onUpgrade
*/
@Override
public void onUpgrade(SQLiteDatabase database, int previousVersion, int currentVersion) {
// log section BEGIN
if (this.logEnabled) {
Logger.info("Update database '%s' from version %s to version %s",this.name, previousVersion, currentVersion);
}
// log section END
// if we have a list of update task, try to execute them
if (options.updateTasks != null) {
List<SQLiteUpdateTask> tasks = buildTaskList(previousVersion, currentVersion);
for (SQLiteUpdateTask task : tasks) {
// log section BEGIN
if (this.logEnabled) {
Logger.info("Begin update database from version %s to %s", task.previousVersion, task.currentVersion);
}
// log section END
task.execute(database);
// log section BEGIN
if (this.logEnabled) {
Logger.info("End update database from version %s to %s", task.previousVersion, task.currentVersion);
}
// log section END
}
} else {
// drop all tables
SQLiteUpdateTaskHelper.dropTablesAndIndices(database);
// generate tables
// log section BEGIN
if (this.logEnabled) {
Logger.info("DDL: %s",PersonTable.CREATE_TABLE_SQL);
}
// log section END
database.execSQL(PersonTable.CREATE_TABLE_SQL);
}
if (options.databaseLifecycleHandler != null) {
options.databaseLifecycleHandler.onUpdate(database, previousVersion, currentVersion, true);
}
}
/**
* onConfigure
*/
@Override
public void onConfigure(SQLiteDatabase database) {
// configure database
if (options.databaseLifecycleHandler != null) {
options.databaseLifecycleHandler.onConfigure(database);
}
}
public void clearCompiledStatements() {
PersonDaoImpl.clearCompiledStatements();
}
/**
* Build instance.
* @return dataSource instance.
*/
public static synchronized BindSampleDataSource build(DataSourceOptions options) {
if (instance==null) {
instance=new BindSampleDataSource(options);
}
instance.openWritableDatabase();
instance.close();
return instance;
}
/**
* Build instance with default config.
*/
public static synchronized BindSampleDataSource build() {
return build(DataSourceOptions.builder().build());
}
/**
* Rapresents transational operation.
*/
public interface Transaction extends AbstractDataSource.AbstractExecutable<BindSampleDaoFactory> {
/**
* Execute transation. Method need to return {@link TransactionResult#COMMIT} to commit results
* or {@link TransactionResult#ROLLBACK} to rollback.
* If exception is thrown, a rollback will be done.
*
* @param daoFactory
* @return
* @throws Throwable
*/
TransactionResult onExecute(BindSampleDaoFactory daoFactory);
}
/**
* Rapresents batch operation.
*/
public interface Batch<T> {
/**
* Execute batch operations.
*
* @param daoFactory
* @throws Throwable
*/
T onExecute(BindSampleDaoFactory daoFactory);
}
class DataSourceSingleThread implements BindSampleDaoFactory {
private SQLContextSingleThreadImpl _context;
private PersonDaoImpl _personDao;
DataSourceSingleThread() {
_context=new SQLContextSingleThreadImpl(BindSampleDataSource.this);
}
/**
*
* retrieve dao PersonDao
*/
public PersonDaoImpl getPersonDao() {
if (_personDao==null) {
_personDao=new PersonDaoImpl(_context);
}
return _personDao;
}
public DataSourceSingleThread bindToThread() {
_context.bindToThread();
return this;
}
}
}
Generated data source class derived from AbstractDataSource that derive from SQLiteOpenHelper.
To use a data source in a client application, just retrieve a reference to singleton instance of data source
BindSampleDataSource dataSource = BindSampleDataSource .instance();
To execute a transaction, just invoke the following code
dataSource.execute(new Transaction() {
@Override
public TransationResultonExecute(BindSampleDaoFactory daoFactory) {
DaoPersonImpl dao = daoFactory.getPersonDao();
long result = dao.insertRaw1("test", 52);
dao.insertRaw2("test2", 23)
// commit transaction
return TransationResult.COMMIT;
}
});
If you want to use directly DAO without a transaction just retrieve DAO implementation from data-source
PersonDaoImpl dao=dataSource.getPersonDao();
dao.insertRaw1("test", 52);
- Introduction
- Goals & Features
- Kotlin
- Immutable or Mutable Pojo
- Annotation Processor Args
- Credits
- Articles
- Benchmarks
- Setup
- Tutorial
- Usage
- Dependencies and inspirations
- Stackoverflow
- Documentation
- SQL logging
- Data source options
- Indices
- SQL Type adapter
- Global SQL Type adapter
- Constraints
- Live data: welcome Architectural components!!
- Paged Live data
- Dynamic parts
- Transactional and batch operations
- Async Transactional and batch operations
- Global transaction
- Support for immutable POJO
- Generate Content provider
- Generate Database schema generation
- Database migration
- BindSqlColumn
- BindContentProvider
- BindContentProviderEntry
- BindContentProviderPath
- BindDao
- BindDaoMany2Many
- BindDataSource
- BindDataSourceOptions
- BindDataSourceUpdateTask
- BindIndex
- BindSqlRelation
- BindSqlAdapter
- BindSqlChildSelect
- BindSqlDelete
- BindSqlDynamicOrderBy
- BindSqlDynamicWhere
- BindSqlDynamicWhereParams
- BindSqlInsert
- BindSqlPageSize
- BindSqlParam
- BindSqlSelect
- BindSqlUpdate
- BindSqlType
- BindSqlTransaction