-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add Android Support SQLite to library * Tests Support SQLite implementation
- Loading branch information
1 parent
ac85ae0
commit 95e5cf6
Showing
5 changed files
with
310 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
...t/src/main/java/co/yello/db/batchlight/androidsupportsqlite/AndroidSupportSQLiteBinder.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package co.yello.db.batchlight.androidsupportsqlite | ||
|
||
import androidx.sqlite.db.SupportSQLiteStatement | ||
import co.yello.db.batchlight.Binder | ||
|
||
/** | ||
* The [Binder] implementation for Support SQLite on Android. | ||
* | ||
* @property sqLiteStatement A [SupportSQLiteStatement] to interact with. | ||
*/ | ||
class AndroidSupportSQLiteBinder( | ||
private val sqLiteStatement: SupportSQLiteStatement | ||
) : Binder { | ||
|
||
override fun execute() { | ||
sqLiteStatement.execute() | ||
} | ||
|
||
override fun clear() { | ||
sqLiteStatement.clearBindings() | ||
} | ||
|
||
override fun bindLong(position: Int, long: Long) { | ||
sqLiteStatement.bindLong(position, long) | ||
} | ||
|
||
override fun bindString(position: Int, string: String) { | ||
sqLiteStatement.bindString(position, string) | ||
} | ||
|
||
override fun bindDouble(position: Int, double: Double) { | ||
sqLiteStatement.bindDouble(position, double) | ||
} | ||
|
||
override fun bindBlob(position: Int, blob: ByteArray) { | ||
sqLiteStatement.bindBlob(position, blob) | ||
} | ||
|
||
override fun bindNull(position: Int) { | ||
sqLiteStatement.bindNull(position) | ||
} | ||
|
||
override fun equals(other: Any?): Boolean { | ||
return sqLiteStatement == (other as? AndroidSupportSQLiteBinder)?.sqLiteStatement | ||
} | ||
|
||
override fun hashCode(): Int { | ||
return sqLiteStatement.hashCode() | ||
} | ||
} |
97 changes: 97 additions & 0 deletions
97
...ht/src/main/java/co/yello/db/batchlight/androidsupportsqlite/SupportSQLiteBinderConfig.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package co.yello.db.batchlight.androidsupportsqlite | ||
|
||
import androidx.sqlite.db.SupportSQLiteDatabase | ||
import co.yello.db.batchlight.Binder | ||
import co.yello.db.batchlight.BinderConfig | ||
import co.yello.db.batchlight.sqlAndroidPreparedStatementStartIndex | ||
import co.yello.db.batchlight.sqlMaxBinds | ||
|
||
/** | ||
* The [BinderConfig] for Android Support SQLite. | ||
* | ||
* @property db the Support SQLite database that is being written to. | ||
* @property batchStatement the statement that will be executed. For SQLite it will be either REPLACE INTO TABLE_NAME or | ||
* INSERT INTO TABLE_NAME | ||
* | ||
* @constructor | ||
* | ||
* @param fieldsPerItem the number of fields per row to be inserted. | ||
* @param maxFields the maximum number of binds that can happen per statement. | ||
*/ | ||
class SupportSQLiteBinderConfig( | ||
private val db: SupportSQLiteDatabase, | ||
private val batchStatement: String, | ||
override val fieldsPerItem: Int, | ||
override val maxFields: Int | ||
) : BinderConfig { | ||
|
||
/** | ||
* The maximum number of items that can be inserted per statement. | ||
*/ | ||
override val maxInsertSize = if (fieldsPerItem > 0) maxFields / fieldsPerItem else 1 | ||
|
||
override val maxInsertBinder: Binder by lazy { | ||
buildBinder(maxInsertSize) | ||
} | ||
|
||
/** | ||
* For a SQLite insert statement each item has the format (?, ?, ?) | ||
*/ | ||
private val objectStatement = (1..fieldsPerItem).joinToString( | ||
prefix = "(", | ||
transform = { "?" }, | ||
separator = ",", | ||
postfix= ")" | ||
) | ||
|
||
override val startIndex: Int = sqlAndroidPreparedStatementStartIndex | ||
|
||
override fun buildBinder(insertCount: Int): Binder { | ||
val allObjects = (1..insertCount).joinToString(",") { objectStatement } | ||
val compiledStatement = db.compileStatement("$batchStatement $allObjects") | ||
return AndroidSupportSQLiteBinder(compiledStatement) | ||
} | ||
|
||
companion object { | ||
|
||
/** | ||
* Creates a statement generator for batch replace statements. | ||
* | ||
* @param db the database to perform the replaces on. | ||
* @param tableName the name of the table to preform the replaces on. | ||
* @param columnCount the number of columns that will be replaced per row. | ||
* @param maxBinds the total number of values that can be bound to the statement. | ||
*/ | ||
fun getReplaceConfig( | ||
db: SupportSQLiteDatabase, | ||
tableName: String, | ||
columnCount: Int, | ||
maxBinds: Int = sqlMaxBinds | ||
) = SupportSQLiteBinderConfig( | ||
db, | ||
"REPLACE INTO $tableName VALUES", | ||
columnCount, | ||
maxBinds | ||
) | ||
|
||
/** | ||
* Creates a statement generator for batch insert statements. | ||
* | ||
* @param db the database to perform the insert on. | ||
* @param tableName the name of the table to preform the insert on. | ||
* @param columnCount the number of columns that will be insert per row. | ||
* @param maxBinds the total number of values that can be bound to the statement. | ||
*/ | ||
fun getInsertConfig( | ||
db: SupportSQLiteDatabase, | ||
tableName: String, | ||
columnCount: Int, | ||
maxBinds: Int = sqlMaxBinds | ||
) = SupportSQLiteBinderConfig( | ||
db, | ||
"INSERT INTO $tableName VALUES", | ||
columnCount, | ||
maxBinds | ||
) | ||
} | ||
} |
84 changes: 84 additions & 0 deletions
84
...c/test/java/co/yello/db/batchlight/androidsupportsqlite/AndroidSupportSQLiteBinderTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package co.yello.db.batchlight.androidsupportsqlite | ||
|
||
import android.database.sqlite.SQLiteStatement | ||
import androidx.sqlite.db.SupportSQLiteStatement | ||
import co.yello.db.batchlight.androidsqlite.AndroidSQLiteBinder | ||
import io.mockk.MockKAnnotations | ||
import io.mockk.impl.annotations.MockK | ||
import io.mockk.mockk | ||
import io.mockk.verify | ||
import org.junit.Assert | ||
import org.junit.Before | ||
import org.junit.Test | ||
|
||
class AndroidSupportSQLiteBinderTest { | ||
@MockK | ||
lateinit var compiledStatement: SupportSQLiteStatement | ||
|
||
private lateinit var androidSQLiteBinder: AndroidSupportSQLiteBinder | ||
|
||
@Before | ||
fun setUp() { | ||
MockKAnnotations.init(this, relaxUnitFun = true) | ||
androidSQLiteBinder = AndroidSupportSQLiteBinder(compiledStatement) | ||
} | ||
|
||
@Test | ||
fun execute() { | ||
androidSQLiteBinder.execute() | ||
verify { compiledStatement.execute() } | ||
} | ||
|
||
@Test | ||
fun clearBindings() { | ||
androidSQLiteBinder.clear() | ||
verify { compiledStatement.clearBindings() } | ||
} | ||
|
||
@Test | ||
fun bindLong() { | ||
androidSQLiteBinder.bindLong(1, 1) | ||
verify { compiledStatement.bindLong(1, 1) } | ||
} | ||
|
||
@Test | ||
fun bindString() { | ||
androidSQLiteBinder.bindString(1, "") | ||
verify { compiledStatement.bindString(1, "") } | ||
} | ||
|
||
@Test | ||
fun bindDouble() { | ||
androidSQLiteBinder.bindDouble(1, 0.0) | ||
verify { compiledStatement.bindDouble(1, 0.0) } | ||
} | ||
|
||
@Test | ||
fun bindBlob() { | ||
val byteArray = ByteArray(1) | ||
androidSQLiteBinder.bindBlob(1, byteArray) | ||
verify { compiledStatement.bindBlob(1, byteArray) } | ||
} | ||
|
||
@Test | ||
fun bindNull() { | ||
androidSQLiteBinder.bindNull(1) | ||
verify { compiledStatement.bindNull(1) } | ||
} | ||
|
||
@Test | ||
fun testHashCode() { | ||
Assert.assertEquals(compiledStatement.hashCode(), androidSQLiteBinder.hashCode()) | ||
} | ||
|
||
@Test | ||
fun `Test two AndroidSQLiteStatements with the same prepared statement are equal` () { | ||
Assert.assertEquals(androidSQLiteBinder, AndroidSupportSQLiteBinder(compiledStatement)) | ||
} | ||
|
||
@Test | ||
fun `Test two AndroidSQLiteStatements with different prepared statement are equal` () { | ||
val compiledStatement2 = mockk<SQLiteStatement>() | ||
Assert.assertNotEquals(androidSQLiteBinder, AndroidSQLiteBinder(compiledStatement2)) | ||
} | ||
} |
78 changes: 78 additions & 0 deletions
78
...rc/test/java/co/yello/db/batchlight/androidsupportsqlite/SupportSQLiteBinderConfigTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package co.yello.db.batchlight.androidsupportsqlite | ||
|
||
import androidx.sqlite.db.SupportSQLiteDatabase | ||
import androidx.sqlite.db.SupportSQLiteStatement | ||
import io.mockk.MockKAnnotations | ||
import io.mockk.every | ||
import io.mockk.impl.annotations.MockK | ||
import io.mockk.verify | ||
import org.junit.Assert | ||
import org.junit.Before | ||
import org.junit.Test | ||
|
||
class SupportSQLiteBinderConfigTest { | ||
|
||
@MockK | ||
lateinit var sqLiteDatabase: SupportSQLiteDatabase | ||
|
||
@MockK | ||
lateinit var compiledStatement: SupportSQLiteStatement | ||
|
||
@Before | ||
fun setUp() = MockKAnnotations.init(this, relaxUnitFun = true) | ||
|
||
@Test | ||
fun `Test maxInsertBinder returns a binder with the maximum number of binds`() { | ||
every { sqLiteDatabase.compileStatement("$insertSQL (?),(?)") } returns compiledStatement | ||
val generator = SupportSQLiteBinderConfig(sqLiteDatabase, | ||
insertSQL, 1, 2) | ||
|
||
Assert.assertEquals(AndroidSupportSQLiteBinder(compiledStatement), generator.maxInsertBinder) | ||
} | ||
|
||
@Test | ||
fun `Test generateBinder works with column size of 1`() { | ||
every { sqLiteDatabase.compileStatement("$insertSQL (?)") } returns compiledStatement | ||
|
||
val generator = SupportSQLiteBinderConfig(sqLiteDatabase, insertSQL, 1, 2) | ||
|
||
Assert.assertEquals(AndroidSupportSQLiteBinder(compiledStatement), generator.buildBinder(1)) | ||
} | ||
|
||
@Test | ||
fun `Test generateStatement works with column size greater than 1`() { | ||
every { sqLiteDatabase.compileStatement("$insertSQL (?,?),(?,?)") } returns compiledStatement | ||
|
||
val generator = SupportSQLiteBinderConfig(sqLiteDatabase, | ||
insertSQL, 2, 2) | ||
|
||
Assert.assertEquals(AndroidSupportSQLiteBinder(compiledStatement), generator.buildBinder(2)) | ||
} | ||
|
||
@Suppress("SyntaxError") | ||
@Test | ||
fun `Test getReplaceGenerator uses replace into to compile the query`() { | ||
val tableName = "MediumObjects" | ||
val expectedSql = "REPLACE INTO $tableName VALUES (?)" | ||
every { sqLiteDatabase.compileStatement(expectedSql) } returns compiledStatement | ||
|
||
SupportSQLiteBinderConfig.getReplaceConfig(sqLiteDatabase, tableName, 1, 1).maxInsertBinder | ||
|
||
verify { sqLiteDatabase.compileStatement(expectedSql) } | ||
} | ||
|
||
@Test | ||
fun `Test getReplaceGenerator uses insert into to compile the query`() { | ||
val tableName = "MediumObjects" | ||
val expectedSql = "INSERT INTO $tableName VALUES (?)" | ||
every { sqLiteDatabase.compileStatement(expectedSql) } returns compiledStatement | ||
|
||
SupportSQLiteBinderConfig.getInsertConfig(sqLiteDatabase, tableName, 1, 1).maxInsertBinder | ||
|
||
verify { sqLiteDatabase.compileStatement(expectedSql) } | ||
} | ||
|
||
companion object { | ||
private const val insertSQL = "INSERT INTO TABLE EXAMPLE" | ||
} | ||
} |