-
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.
- Loading branch information
0 parents
commit 46d2e00
Showing
105 changed files
with
3,714 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
*.iml | ||
.gradle | ||
/local.properties | ||
/.idea/caches/build_file_checksums.ser | ||
/.idea/libraries | ||
/.idea/modules.xml | ||
/.idea/workspace.xml | ||
.DS_Store | ||
/build | ||
/captures | ||
.externalNativeBuild | ||
*.idea |
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,11 @@ | ||
# Changelog | ||
All notable changes to this project will be documented in this file. | ||
|
||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | ||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||
|
||
## [1.0.0] | ||
### Added | ||
- Initial version | ||
- Provides a simple interface for creating batch inserts and replaces. | ||
- Supports Android framework sqlite |
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,8 @@ | ||
Contributing | ||
============ | ||
|
||
If you would like to contribute code to this project you can do so through GitHub by | ||
forking the repository and sending a pull request. | ||
|
||
When submitting code, please make every effort to follow existing conventions | ||
and style in order to keep the code as readable as possible. |
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,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2019 Yello | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
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 @@ | ||
Batch Light | ||
===== | ||
|
||
Batch Light is a library for batch inserting to SQLite on Android. | ||
|
||
A demo project can be found on Google Play, and as an Instant App. | ||
|
||
<a href='https://play.google.com/store/apps/details?id=com.ryancasler.db.batchinsertdemo&launch=true'> | ||
<img alt='Demo Project on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' height=90px/> | ||
</a> | ||
|
||
## Download | ||
|
||
## Usage | ||
Batch Lite has 4 main steps to use. | ||
|
||
1. Create a configuration object. Currently SQLite is the only binder available with the batcher. | ||
The SQLiteBinderConfig has to default types available, Insert (INSERT INTO) and Replace (REPLACE INTO). When getting | ||
an instance of the SQLiteBinderConfig there are three params. A reference to the SQLite Database being written to, | ||
the name of the table being written to and the number of columns that will be written to. | ||
|
||
```kotlin | ||
val binderConfig = SQLiteBinderConfig.getInsertConfig( | ||
db = writableDatabase, | ||
tableName = batchTableName, | ||
columnCount = 3 | ||
) | ||
``` | ||
|
||
2. Create a new batcher using the config from step 1. | ||
|
||
```kotlin | ||
val batcher = BatchStatement<MediumSizeObject>(binderConfig) | ||
``` | ||
|
||
3. call the execute function on the batcher, passing in the list to be inserted and a clojure that tells it how to bind | ||
the items in the list. The config will generate a statement that looks like: | ||
|
||
```kotlin | ||
data class InsertItem(val id: Int, val text: String) | ||
``` | ||
|
||
Table structure: | ||
``` | ||
TABLE_NAME | ||
----------- | ||
id | text | | ||
``` | ||
|
||
The generated SQLite for a list of 3 of the items above would be: | ||
|
||
```roomsql | ||
INSERT INTO TABLE_NAME VALUES (?, ?), (?, ?), (?, ?) | ||
``` | ||
|
||
To bind the list, the closure below should be used. The binder will use the clojure for each item to bind to the generated | ||
statement. | ||
|
||
```kotlin | ||
batcher.execute(list) { listItem -> | ||
bindLong(listItem.id.toLong()) | ||
bindString(listItem.text) | ||
} | ||
``` | ||
|
||
4. The Batch Lite does not handle transactions. It is left up to the end user to wrap the batch | ||
insert into a transaction. If the list that is being batched is over 10,000 items it is recommended to chunk the list | ||
and batch it in separate transactions to avoid blocking other inserts happening in the application. | ||
|
||
An example usage can be found in the sample project. | ||
|
||
Check out the [Kdoc](https://yelloco.github.io/Batchlight) for full documentation. | ||
|
||
## Contributing | ||
|
||
Please read [Contributing.md](CONTRIBUTING.md) for details on the process for submitting pull requests. | ||
|
||
## License | ||
|
||
This project is licensed under the MIT License - see the [License.txt](LICENSE.txt) file for details. | ||
|
||
## Questions | ||
|
||
Any questions comments or concerns can be directed to [email protected]. |
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 @@ | ||
/build |
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,31 @@ | ||
apply plugin: 'com.android.library' | ||
apply plugin: 'kotlin-android' | ||
apply plugin: 'com.github.dcendents.android-maven' | ||
apply plugin: 'org.jetbrains.dokka-android' | ||
|
||
group = 'co.yello.batchlight' | ||
|
||
android { | ||
compileSdkVersion 28 | ||
testOptions.unitTests.includeAndroidResources = true | ||
defaultConfig { | ||
minSdkVersion 21 | ||
targetSdkVersion 28 | ||
} | ||
} | ||
|
||
dokka { | ||
outputFormat = 'html' | ||
outputDirectory = "$buildDir/../javadoc" | ||
reportUndocumented = false | ||
skipDeprecated = true | ||
} | ||
|
||
dependencies { | ||
implementation fileTree(dir: 'libs', include: ['*.jar']) | ||
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" | ||
|
||
testImplementation 'junit:junit:4.12' | ||
testImplementation "io.mockk:mockk:1.9" | ||
testImplementation "org.robolectric:robolectric:4.2" | ||
} |
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 @@ | ||
<manifest package="co.yello.db.batchlight" /> |
69 changes: 69 additions & 0 deletions
69
batchlight/src/main/java/co/yello/db/batchlight/BatchBinder.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,69 @@ | ||
package co.yello.db.batchlight | ||
|
||
/** | ||
* A wrapper around a [Binder] to make sure binds happen in sequential order. | ||
* | ||
* @param binder the specific [Binder] to bind values to. | ||
* @param startBindIndex the index to start binding to the binder. | ||
* | ||
* @constructor Creates a BatchBinder with the given binder. The binder will be cleared on creation to ensure | ||
* no pre existing values will be bound unintentionally. | ||
*/ | ||
class BatchBinder( | ||
private val binder: Binder, | ||
startBindIndex: Int | ||
) { | ||
|
||
/** | ||
* Marks the current binding position. | ||
*/ | ||
var currentBindIndex: Int = startBindIndex | ||
private set | ||
|
||
init { | ||
binder.clear() | ||
} | ||
|
||
/** | ||
* Binds a value of type [Long] to the [Binder] and increments the position. | ||
* | ||
* @param long a [Long] to be bound to the [Binder] | ||
*/ | ||
fun bindLong(long: Long) { | ||
binder.bindLong(currentBindIndex++, long) | ||
} | ||
|
||
/** | ||
* Binds a value of type [String] to the [Binder] and increments the position. | ||
* | ||
* @param string a [String] to be bound to the [Binder]. | ||
*/ | ||
fun bindString(string: String) { | ||
binder.bindString(currentBindIndex++, string) | ||
} | ||
|
||
/** | ||
* Binds a value of type [Double] to the [Binder] and increments the position. | ||
* | ||
* @param double a [Double] to be bound to the [Binder]. | ||
*/ | ||
fun bindDouble(double: Double) { | ||
binder.bindDouble(currentBindIndex++, double) | ||
} | ||
|
||
/** | ||
* Binds a null value to the [Binder] and increments the bind position. | ||
*/ | ||
fun bindNull() { | ||
binder.bindNull(currentBindIndex++) | ||
} | ||
|
||
/** | ||
* Binds a [ByteArray] to the [Binder] and increments the position. | ||
* | ||
* @param blob a [ByteArray] to be bound to the [Binder]. | ||
*/ | ||
fun bindBlob(blob: ByteArray) { | ||
binder.bindBlob(currentBindIndex++, blob) | ||
} | ||
} |
86 changes: 86 additions & 0 deletions
86
batchlight/src/main/java/co/yello/db/batchlight/BatchStatement.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,86 @@ | ||
package co.yello.db.batchlight | ||
|
||
/** | ||
* Drives the inserts into the database. | ||
* | ||
* @param T The type of the collection that will be inserted. This is used to pass into the bind function that is | ||
* passed into the execute function. | ||
* @property binderConfig A [BinderConfig] used to generate all of the [Binder]s that are required to perform | ||
* the inserts. This flexibility lets the library work with a variety of databases. | ||
*/ | ||
class BatchStatement<T>( | ||
private val binderConfig: BinderConfig | ||
) { | ||
|
||
/** | ||
* Chunks the list into the maximum sized list that can be inserted at a time, then executes the insert | ||
* with the [bindItemFunction] passed into the class. | ||
* | ||
* @param itemsToInsert The collection of items of type [T] to batch insert into the database. | ||
* @param bindItemFunction A function that performs the binds for each field in the [T] passed to the function. | ||
* The function is an extension on [BatchBinder] so all bind functions can be accessed from within. | ||
* | ||
* When binding the order of the bind calls should match the structure of the table inserting. | ||
* | ||
* Example usage: | ||
* | ||
* A simple class would look something like | ||
* | ||
* ``` | ||
* data class BatchClass(val id: Int, val text: String, val num: Int) | ||
*``` | ||
* | ||
* The SQL Create statement for the corresponding table to that object would be: | ||
* | ||
* ``` | ||
* CREATE TABLE BatchClass ( | ||
* id INTEGER, | ||
* text TEXT, | ||
* num INTEGER | ||
* ) | ||
*``` | ||
* | ||
* The [Binder] generated for this table will will have the params (?,?,?). To correctly bind the three values | ||
* to their correct ? in the prepared statement the function would be: | ||
* | ||
* ``` | ||
* { batchObject - > | ||
* bindLong(batchObject.id) | ||
* bindString(batchObject.text) | ||
* bindLong(batchObject.num) | ||
* } | ||
* ``` | ||
*/ | ||
fun execute(itemsToInsert: Collection<T>, bindItemFunction: BatchBinder.(T) -> Unit) { | ||
itemsToInsert.asSequence() | ||
.chunked(binderConfig.maxInsertSize) | ||
.forEach { maxSizeList -> performInsert(maxSizeList, bindItemFunction) } | ||
} | ||
|
||
/** | ||
* Binds all values to the correct [Binder] for the given collection then executes the statement. | ||
* | ||
* @param collection The collection of items to be bound and executed. | ||
* @param bindItem The bind statement to execute on each item of the collection. | ||
*/ | ||
private fun performInsert(collection: Collection<T>, bindItem: BatchBinder.(T) -> Unit) { | ||
val statement = if (collection.size == binderConfig.maxInsertSize) { | ||
binderConfig.maxInsertBinder | ||
} else { | ||
binderConfig.buildBinder(collection.size) | ||
} | ||
|
||
val binder = BatchBinder(statement, binderConfig.startIndex) | ||
|
||
collection.forEach { item -> | ||
binder.bindItem(item) | ||
} | ||
|
||
check(binder.currentBindIndex - 1 == collection.size * binderConfig.fieldsPerItem) { | ||
"Expected to bind ${binderConfig.fieldsPerItem} columns per record, " + | ||
"found ${binder.currentBindIndex / collection.size} binds per record." | ||
} | ||
|
||
statement.execute() | ||
} | ||
} |
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,56 @@ | ||
package co.yello.db.batchlight | ||
|
||
/** | ||
* Provides way to bind values to any DB or ORM. | ||
*/ | ||
interface Binder { | ||
|
||
/** | ||
* Clears any bound values. | ||
*/ | ||
fun clear() | ||
|
||
/** | ||
* Executes with any bound values. | ||
*/ | ||
fun execute() | ||
|
||
/** | ||
* Binds a [Long] at the given position. | ||
* | ||
* @param position position to bind at. | ||
* @param long a value of type [Long] to bind. | ||
*/ | ||
fun bindLong(position: Int, long: Long) | ||
|
||
/** | ||
* Binds a [String] at the given position. | ||
* | ||
* @param position position to bind at. | ||
* @param string a value of type [String] to bind. | ||
*/ | ||
fun bindString(position: Int, string: String) | ||
|
||
/** | ||
* Binds a [Double] at the given position. | ||
* | ||
* @param position position to bind at. | ||
* @param double a value of type [Double] to bind. | ||
*/ | ||
fun bindDouble(position: Int, double: Double) | ||
|
||
/** | ||
* Binds a [ByteArray] at the given position. | ||
* | ||
* @param position position to bind at. | ||
* @param blob a value of type [ByteArray] to bind. | ||
*/ | ||
fun bindBlob(position: Int, blob: ByteArray) | ||
|
||
/** | ||
* Binds a null value at the given position. | ||
* | ||
* @param position position to bind at. | ||
*/ | ||
fun bindNull(position: Int) | ||
} |
Oops, something went wrong.