DSC
- A descendant class. When creating a descendant class, it should
extend SQLiteHouse
templatized for itself. This will ensure that all
methods inherited from SQLiteHouse
return instances of the
descendant class, rather than the parent class.public class SQLiteHouse<DSC extends SQLiteHouse> extends SQLitePortal
This class is based on SQLitePortal
and provides all of the same
methods for accessing the database.
Define your SQLite database by creating an empty descendant of
SQLiteHouse
, decorated with an SQLiteDatabaseSpec
annotation
which describes the basic parameters of the database itself. In the example
below, we create a database to hold information about people, places, and
things.
@SQLiteDatabaseSpec( database_name = "my_database", schema_version = 1, classes = { Person.class, Place.class, Thing.class } ) public class MyDatabaseClass extends SQLiteHouse<MyDatabaseClass> {}
Note that the descendant class extends SQLiteHouse
with a generic
parameter pointing back to itself. This template parameter is used in
SQLiteHouse
's method definitions to ensure that all methods that are
"fluid" (i.e., which return the same object) will return instances of
that descendant class, rather than being typecast up the hierarchy to
SQLiteHouse
itself. This pattern allows for more effective method
chaining in case the descendant has custom methods that are also fluid.
In the example above, the classes
element of the annotation names
three other classes. These are the data objects that you would use in your
app to contain the data elements that are stored in the database. By
decorating these classes with annotations, the SQLiteHouse
can
recognize those classes as data schema definitions, and use the annotations
to construct and manage the database automatically.
To continue the previous example, the Person
class is shown below;
Place
and Thing
would be similarly defined.
@SQLiteTable( "people" ) public class Person implements SQLightable { @SQLiteColumn( name = "person_id", index = 0 ) @SQLitePrimaryKey protected String m_sID ; @SQLiteColumn( name = "first_name", index = 1 ) protected String m_sFirstName ; @SQLiteColumn( name = "last_name", index = 2 ) protected String m_sLastName ; @SQLiteColumn( name = "birthday", index = 3 ) protected Calendar m_dBirthdate ; @SQLiteColumn( name = "address", index = 4 ) protected String m_sAddress ; /** Schema classes must provide a default constructor. */ public Person() {} // other constructors, methods, etc. follow }
Note that the instance members that hold the data need not have the same
name as their database columns, nor are they forced to be public
.
This system of annotations is designed such that it interferes as little as
possible with the other design decisions that might go into the data classes.
As long as the fields that correspond to database table columns are properly
decorated, they will be discovered and used in the database. Note also that
this allows the data object to have any other member fields it wants, which
are not serialized into the database, merely by leaving those members
undecorated.
The @SQLitePrimaryKey
annotation explicitly designates a data
element which could be used as a primary key for the table. However, the
SQLiteHouse
will not actually define the column as such; it will
merely be UNIQUE NOT NULL
in the table creation SQL, and a standard,
magic _id
column will be used as the actual primary key. This is done
because of SQLite's inherent preference for auto-incremented integer keys.
However, the SQLiteHouse
will behave as if this object field is the
actual primary key, allowing consumers to search tables by this field rather
than the magic numeric ID.
For notes on the predictability of column order in the table definition,
see the SQLightable.Reflection.ColumnSequencer
class.
Use the SQLiteHouse.Factory
class to construct an instance of the
database class. The factory will perform all the necessary pre-processing of
the SQLiteDatabaseSpec
annotation and feed those parameters into the
constructor for the database class instance. The factory is templatized such
that your database class does not need to extend it.
The code below continues our example of the MyDatabaseClass
by
constructing an instance.
// given some Context ctx in which the class will operate // given some SQLiteHouse.CursorFactory cf for the database helper MyDatabaseClass dbh = SQLiteHouse.Factory.init().getInstance( MyDatabaseClass.class, ctx, cf ) ;
SQLiteHouse
uses implementations of the Refractor
interface to process various data types. The standard set of implementations,
generally named "lenses", are automatically constructed and mapped by the
RefractorMap
class.
To customize this mapping with your own Refractor
implementations,
you may explicitly name a refractor class in the SQLiteColumn
annotation for any individual field in a schematic class. This is the most
efficient way to define a custom refractor, as it will be picked up
automatically by SQLiteHouse
during the introspection process.
Since this class extends SQLitePortal
, which in turn is descended
from SQLiteOpenHelper
, it provides the same
methods for managing connections to the database. Connections may be
established with SQLitePortal.openDB()
and released with
SQLitePortal.close()
.
The onCreate(android.database.sqlite.SQLiteDatabase)
and onUpgrade(android.database.sqlite.SQLiteDatabase, int, int)
methods, which ensure that
the underlying database is always installed with the current schema, are
already implemented in SQLiteHouse
, and use the schematic information
discovered by the constructor to handle the database creation and upgrade
operations automatically. Descendant classes need not provide their own
implementations of these methods, unless they require some exotic
post-processing logic after the normal creation/update process has been
completed.
The base SQLiteHouse
class provides implementations of some basic
query operations — insertion, selection, updates, and deletion. Once
all of the schematic data is known to the instance, the grammar of
interacting with the database flows relatively simply.
MyDatabaseClass dbh = SQLiteHouse.Factory.init().getInstance( MyDatabaseClass.class, ctx, null ) ; dbh.openDB() ; // wait for connection, either by sleeping or catching connection event Person alice = new Person( UUID.randomUUID().toString(), "Alice", "Appleton", new GregorianCalendar( 1980, 6, 3 ), "1687 Newton Way, Principia, NY 10705" ) ; dbh.insert( alice ) ; Person bob = new Person( UUID.randomUUID().toString(), "Bob", "Bullhead", new GregorianCalendar( 1960, 9, 5 ), "230 South Bouquet St., Oakland, PA 15213" ) ; long idBob = dbh.insert( bob ) ; bob.setAddress( "115 Federal Street, Pittsburgh, PA 15212" ) ; int nUpdated = dbh.update( bob ) ; // nUpdated == 1 Person also_bob = dbh.select( idBob ) ; String sBobAddress = also_bob.getAddress() ; // 115 Federal Street... int nDeleted = dbh.delete( alice ) ; // nDeleted == 1 nDeleted = dbh.delete( alice ) ; // nDeleted == 0 nDeleted = dbh.delete( bob ) ; // nDeleted == 1 nDeleted = dbh.delete( also_bob ) ; // nDeleted == 0 dbh.close() ;
The descendant class may, as with SQLitePortal
, define further
custom instance methods to perform more specific reusable queries.
Modifier and Type | Class and Description |
---|---|
static class |
SQLiteHouse.ColumnIndexComparator
Deprecated.
zer0bandwidth-net/android 0.2.1 (#56) — replaced by
SQLightable.Reflection.ColumnSequencer |
static class |
SQLiteHouse.Factory
Creates instances of a
SQLiteHouse . |
static class |
SQLiteHouse.QueryContext<DBH extends SQLiteHouse>
Deprecated.
zer0bandwidth-net/android 0.2.1 (#56) — use
SQLightable.Reflection instead, by using
getReflection(Class) to fetch the one that the database class
has already generated, or by using
SQLightable.Reflection.reflect(Class) to generate a new one. |
SQLitePortal.ConnectionListener, SQLitePortal.ConnectionTask
Modifier and Type | Field and Description |
---|---|
static java.lang.String |
LOG_TAG
The tag used by logging statements in this class.
|
protected java.util.List<java.lang.Class<? extends SQLightable>> |
m_aclsSchema
A list of classes that, in aggregate, define the schema for the database.
|
protected SQLightable.ReflectionMap |
m_mapReflections
A map of schematic classes to their reflections.
|
protected RefractorMap |
m_mapRefractor
A persistent instance of a refractor map.
|
static java.lang.String |
MAGIC_ID_COLUMN_NAME
This magic column name is used in every table to auto-create a row ID as
preferred by SQLite.
|
protected static int |
SCHEMA_NOT_DEFINED
Magic constant to indicate that the schema version has not yet been
resolved.
|
m_bIsConnected, m_bReadOnly, m_ctx, m_db, m_nLatestVersion, SQLITE_FALSE_INT, SQLITE_FALSE_INTSTRING, SQLITE_TRUE_INT, SQLITE_TRUE_INTSTRING, WHERE_FALSE, WHERE_TRUE
Modifier | Constructor and Description |
---|---|
protected |
SQLiteHouse(SQLiteHouse.Factory factory)
Constructor used by the
SQLiteHouse.Factory to create an instance
of the class. |
Modifier and Type | Method and Description |
---|---|
<ROW extends SQLightable> |
delete(ROW o)
Searches the database for a row of the table represented by the supplied
objects, and deletes that row.
|
<SC extends SQLightable> |
deleteFrom(java.lang.Class<SC> cls)
Shorthand to obtain a
DeletionBuilder bound to this database and
targeting the table corresponding to the specified schematic class. |
<SC extends SQLightable> |
describe(java.lang.Class<SC> cls)
Accesses the reflection of a class that is marshalled by this instance.
|
<SC extends SQLightable> |
fromCursor(android.database.Cursor crs,
java.lang.Class<SC> cls)
Reads a row of data from a cursor, and marshals it into a schematic class
instance corresponding to the table from which the row was fetched.
|
SQLiteHouse.QueryContext<DSC> |
getQueryContext()
Deprecated.
zer0bandwidth-net/android 0.2.1 (#56)
|
SQLiteHouse.QueryContext<DSC> |
getQueryContext(java.lang.Class<? extends SQLightable> clsTable)
Deprecated.
zer0bandwidth-net/android 0.2.1 (#56) — use
getReflection(Class) instead |
protected <SC extends SQLightable> |
getReflection(java.lang.Class<SC> cls)
Similar to
describe(java.lang.Class<SC>) , but will throw a SchematicException
if the specified class is not found. |
Refractor<?> |
getRefractorForField(java.lang.reflect.Field fld)
Discovers the type of refractor needed to marshal the specified field.
|
java.util.List<java.lang.Class<? extends SQLightable>> |
getSchemaClasses()
Accesses the cache of schematic classes for the database.
|
<ROW extends SQLightable> |
insert(ROW o)
Inserts an object of a known schematic class into the database.
|
void |
onCreate(android.database.sqlite.SQLiteDatabase db)
Called by Android when the consumer tries to connect to the database.
|
void |
onUpgrade(android.database.sqlite.SQLiteDatabase db,
int nOld,
int nNew)
Called by Android when the consumer tries to connect to the database, and
the current schema version in the class is newer than the one that is
currently installed.
|
protected DSC |
processReflections()
Given that the list of schematic classes has been populated, discover and
cache their characteristics for future reference.
|
<SC extends SQLightable> |
processResultSet(java.lang.Class<SC> cls,
android.database.Cursor crs)
Given a result set loaded into a
Cursor , iterate over that cursor
to produce a list of schematic class instances containing the rows in the
result set. |
protected DSC |
registerCustomRefractors()
Deprecated.
zer0bandwidth-net/android 0.2.1 (#56) — instead, use
the
refractor attribute of the SQLiteColumn annotation
to define refractors for each relevant field in your schematic classes |
<ROW extends SQLightable> |
search(java.lang.Class<ROW> cls,
java.lang.String sID)
Searches the database for a row of the table represented by the supplied
schematic class, such that the primary key column value matches the value
supplied in the method call.
|
<ROW extends SQLightable> |
search(ROW oCriteria)
Searches the database for a row of the table represented by the supplied
object, such that the primary key value in that object equals the primary
key found in the object.
|
<ROW extends SQLightable> |
select(java.lang.Class<ROW> cls,
long nID)
Searches the database for a row of the table represented by the supplied
object, where the specified integer is equal to the row's magic auto-ID.
|
<SC extends SQLightable> |
selectFrom(java.lang.Class<SC> cls)
Shorthand to obtain a
SelectionBuilder bound to this database and
targeting the table corresponding to the specified schematic class. |
protected DSC |
setSchemaClasses(java.util.List<java.lang.Class<? extends SQLightable>> aclsSchema)
Caches a list of classes that define the database schema.
|
<SC extends SQLightable> |
update(java.lang.Class<SC> cls)
Shorthand to obtain an
UpdateBuilder bound to this database and
targeting the table corresponding to the specified schematic class. |
<ROW extends SQLightable> |
update(ROW o)
Updates the values of an object from a known schematic class.
|
protected <SC extends SQLightable> |
upgradeTable(android.database.sqlite.SQLiteDatabase db,
java.lang.Class<SC> clsTable,
int nOld)
Called by
onUpgrade(android.database.sqlite.SQLiteDatabase, int, int) to upgrade a single SQLite database table
based on the information reflected by a specific schematic class. |
boolToInt, boolToIntString, close, closeCursor, closeDB, databaseExists, getBooleanColumn, getColumnListForTable, getColumnMapForTable, getContext, getDatabaseFileSize, getLatestSchemaVersion, getPathToDatabaseFile, intToBool, isConnected, openDB, openDB, openDB, openDB
public static final java.lang.String LOG_TAG
protected static final int SCHEMA_NOT_DEFINED
public static final java.lang.String MAGIC_ID_COLUMN_NAME
protected java.util.List<java.lang.Class<? extends SQLightable>> m_aclsSchema
setSchemaClasses(List)
protected SQLightable.ReflectionMap m_mapReflections
protected RefractorMap m_mapRefractor
protected SQLiteHouse(SQLiteHouse.Factory factory)
SQLiteHouse.Factory
to create an instance
of the class. The factory passes itself into this constructor, so that it
can provide values for all of the parameters necessary to invoke the
superclass's constructor.
Descendant classes must extend this constructor in order to use
the SQLiteHouse.Factory
to properly process the schematic data in
the various data classes.
protected MyDatabaseClass( SQLiteHouse.Factory factory ) { super(factory) ; }
factory
- the factory which has resolved information about the
database to be bound to this classprotected DSC setSchemaClasses(java.util.List<java.lang.Class<? extends SQLightable>> aclsSchema)
SQLiteHouse(Factory)
.aclsSchema
- the list of classesprotected DSC processReflections()
SQLiteHouse(Factory)
; must follow
setSchemaClasses(java.util.List<java.lang.Class<? extends net.zer0bandwidth.android.lib.database.sqlitehouse.SQLightable>>)
.protected DSC registerCustomRefractors()
refractor
attribute of the SQLiteColumn
annotation
to define refractors for each relevant field in your schematic classesRefractor
implementations that should be used by the instance.
The default implementation of this method returns trivially; descendants
of SQLiteHouse
may override this method to add any custom
Refractor
implementations here.Refractor
,
RefractorMap
public void onCreate(android.database.sqlite.SQLiteDatabase db) throws SchematicException
This method was designed to be a final
implementation, but is
left extensible for descendant classes, just in case they might need to
perform any custom post-processing.
onCreate
in class android.database.sqlite.SQLiteOpenHelper
db
- a direct handle to the SQLite database (provided by the Android
OS)SchematicException
- (since 0.1.7 #50) if something goes
wrong while processing the schema definitionpublic void onUpgrade(android.database.sqlite.SQLiteDatabase db, int nOld, int nNew)
since
version is newer than the old version,
will create the table. Otherwise, it will analyze the table's columns,
and if any column's since
version is newer than the old version,
the method will add the column to the table.
This method was designed to be a final
implementation, but is
left extensible for descendant classes, just in case they might need to
perform any custom post-processing.
onUpgrade
in class android.database.sqlite.SQLiteOpenHelper
db
- a direct handle to the SQLite database (provided by the Android
OS)nOld
- the version of the schema that is installednNew
- the version of the schema that is definedprotected <SC extends SQLightable> SQLiteHouse<DSC> upgradeTable(android.database.sqlite.SQLiteDatabase db, java.lang.Class<SC> clsTable, int nOld) throws SchematicException
onUpgrade(android.database.sqlite.SQLiteDatabase, int, int)
to upgrade a single SQLite database table
based on the information reflected by a specific schematic class.SC
- the schematic classdb
- a direct handle to the SQLite database (provided to
onUpgrade(android.database.sqlite.SQLiteDatabase, int, int)
by the Android OS)clsTable
- the schematic class that defines the tablenOld
- the version of the schema that is installedSchematicException
- if the class is not part of the schemapublic <ROW extends SQLightable> long insert(ROW o) throws SchematicException
o
- the object to be insertedSchematicException
public <ROW extends SQLightable> int update(ROW o) throws SchematicException
o
- the object to be updatedSchematicException
- if the data object's class isn't part of the
schema, or if the table definition for this class didn't specify its own
primary keypublic <SC extends SQLightable> UpdateBuilder update(java.lang.Class<SC> cls) throws SchematicException
UpdateBuilder
bound to this database and
targeting the table corresponding to the specified schematic class.cls
- the class that defines part of the schemaUPDATE
query builder prepared for that tableSchematicException
- if the class is not part of the schemapublic <ROW extends SQLightable> ROW search(ROW oCriteria) throws SchematicException
ROW
- the specific SQLightable
implementation being soughtoCriteria
- the object whose primary key will be used as the
criteria for a searchSchematicException
- if anything goes wrong along the waypublic <ROW extends SQLightable> ROW search(java.lang.Class<ROW> cls, java.lang.String sID) throws SchematicException
ROW
- the schematic class being soughtcls
- the schematic class being soughtsID
- the unique identifier of the row, which must be a
string in this flavor of the methodSchematicException
- if anything goes wrong along the waypublic <ROW extends SQLightable> ROW select(java.lang.Class<ROW> cls, long nID) throws SchematicException
ROW
- the schematic classcls
- the schematic class that will contain the rownID
- the auto-incremented integer ID of the rowSchematicException
- if the class is not part of the schemapublic <SC extends SQLightable> SelectionBuilder selectFrom(java.lang.Class<SC> cls) throws SchematicException
SelectionBuilder
bound to this database and
targeting the table corresponding to the specified schematic class.SC
- the schematic classcls
- the schematic classSELECT
query builder prepared for that tableSchematicException
- if the class is not part of the schemapublic <ROW extends SQLightable> int delete(ROW o) throws SchematicException
ROW
- the schematic classo
- the schematic class instance to be deleted if foundSchematicException
- if the table is not part of the schema, or
doesn't specify a key columnpublic <SC extends SQLightable> DeletionBuilder deleteFrom(java.lang.Class<SC> cls) throws SchematicException
DeletionBuilder
bound to this database and
targeting the table corresponding to the specified schematic class.cls
- the class that defines part of the schemaDELETE
query builder prepared for that tableSchematicException
- if the class is not part of the schemapublic <SC extends SQLightable> SQLightable.Reflection<SC> describe(java.lang.Class<SC> cls)
null
, rather than
invoking SQLightable.Reflection.reflect(Class)
.SC
- the schematic class to be describedcls
- the schematic class to be describedprotected <SC extends SQLightable> SQLightable.Reflection<SC> getReflection(java.lang.Class<SC> cls) throws SchematicException
describe(java.lang.Class<SC>)
, but will throw a SchematicException
if the specified class is not found. This is more useful internally than
as a generaly utility, hence the protected
access control.SC
- the schematic class to be describedcls
- the schematic class to be describedSchematicException
- if the class is not found in this instancepublic <SC extends SQLightable> SC fromCursor(android.database.Cursor crs, java.lang.Class<SC> cls) throws SchematicException
SC
- the schematic class to which data will be marshalledcrs
- the cursor from which data will be marshalledcls
- the schematic class to which data will be marshalledSchematicException
- if the class is not part of the schemapublic <SC extends SQLightable> java.util.List<SC> processResultSet(java.lang.Class<SC> cls, android.database.Cursor crs) throws SchematicException
Cursor
, iterate over that cursor
to produce a list of schematic class instances containing the rows in the
result set.SC
- the schematic class which could contain each rowcls
- the schematic class which could contain each rowcrs
- the cursor containing the result setSchematicException
- if any instance cannot be instantiatedpublic SQLiteHouse.QueryContext<DSC> getQueryContext()
public SQLiteHouse.QueryContext<DSC> getQueryContext(java.lang.Class<? extends SQLightable> clsTable)
getReflection(Class)
insteadclsTable
- the schematic table to be pre-loadedpublic java.util.List<java.lang.Class<? extends SQLightable>> getSchemaClasses()
public Refractor<?> getRefractorForField(java.lang.reflect.Field fld) throws IntrospectionException
fld
- a field in a schematic classIntrospectionException
- if no refractor can be discovered