├── .editorconfig ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── SUMMARY.md ├── build.gradle.kts ├── buildSrc ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── Dependencies.kt ├── contentprovider-annotations ├── .gitignore ├── build.gradle.kts ├── gradle.properties └── src │ └── main │ └── kotlin │ └── com │ └── dbflow5 │ └── contentprovider │ └── annotation │ ├── ContentProvider.kt │ ├── ContentUri.kt │ ├── Notify.kt │ └── TableEndpoint.kt ├── contentprovider ├── .gitignore ├── build.gradle.kts ├── gradle.properties ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── kotlin │ └── com │ └── dbflow5 │ └── provider │ ├── BaseContentProvider.kt │ ├── BaseProviderModel.kt │ ├── BaseSyncableProviderModel.kt │ ├── ContentProviderDatabase.kt │ ├── ContentUtils.kt │ ├── ModelProvider.kt │ └── StubContentProvider.kt ├── core ├── .gitignore ├── build.gradle.kts ├── gradle.properties └── src │ └── main │ └── kotlin │ └── com │ └── dbflow5 │ ├── StringUtils.kt │ ├── annotation │ ├── Collate.kt │ ├── Column.kt │ ├── ColumnIgnore.kt │ ├── ColumnMap.kt │ ├── ColumnMapReference.kt │ ├── ConflictAction.kt │ ├── Database.kt │ ├── ForeignKey.kt │ ├── ForeignKeyAction.kt │ ├── ForeignKeyReference.kt │ ├── Fts.kt │ ├── Index.kt │ ├── IndexGroup.kt │ ├── InheritedColumn.kt │ ├── InheritedPrimaryKey.kt │ ├── ManyToMany.kt │ ├── Migration.kt │ ├── ModelCacheField.kt │ ├── ModelView.kt │ ├── ModelViewQuery.kt │ ├── MultiCacheField.kt │ ├── MultipleManyToMany.kt │ ├── NotNull.kt │ ├── OneToMany.kt │ ├── PrimaryKey.kt │ ├── QueryModel.kt │ ├── Table.kt │ ├── TypeConverter.kt │ ├── Unique.kt │ └── UniqueGroup.kt │ ├── converter │ └── TypeConverters.kt │ ├── data │ └── Blob.kt │ └── sql │ ├── Query.kt │ ├── QueryCloneable.kt │ └── SQLiteType.kt ├── coroutines ├── .gitignore ├── build.gradle.kts ├── gradle.properties ├── proguard-rules.pro ├── settings.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── kotlin │ └── com │ └── dbflow5 │ └── coroutines │ └── Coroutines.kt ├── dbflow_banner.png ├── gettingstarted.md ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── issue_template.md ├── java-artifacts.gradle ├── kotlin-artifacts.gradle ├── lib ├── build.gradle.kts ├── gradle.properties ├── settings.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── kotlin │ └── com │ └── dbflow5 │ ├── SqlUtils.kt │ ├── adapter │ ├── CacheAdapter.kt │ ├── CreationAdapter.kt │ ├── InternalAdapter.kt │ ├── ModelAdapter.kt │ ├── ModelViewAdapter.kt │ ├── QueryModelAdapter.kt │ ├── RetrievalAdapter.kt │ ├── queriable │ │ ├── CacheableListModelLoader.kt │ │ ├── CacheableModelLoader.kt │ │ ├── ListModelLoader.kt │ │ ├── ModelLoader.kt │ │ ├── SingleKeyCacheableListModelLoader.kt │ │ ├── SingleKeyCacheableModelLoader.kt │ │ └── SingleModelLoader.kt │ └── saveable │ │ ├── CacheableListModelSaver.kt │ │ ├── ListModelSaver.kt │ │ └── ModelSaver.kt │ ├── config │ ├── DBFlowDatabase.kt │ ├── DatabaseConfig.kt │ ├── DatabaseHolder.kt │ ├── FlowConfig.kt │ ├── FlowLog.kt │ ├── FlowManager.kt │ ├── NaturalOrderComparator.java │ └── TableConfig.kt │ ├── database │ ├── AndroidDatabase.kt │ ├── AndroidDatabaseStatement.kt │ ├── AndroidDatabaseWrapper.kt │ ├── AndroidMigrationFileHelper.kt │ ├── AndroidSQLiteOpenHelper.kt │ ├── BaseDatabaseStatement.kt │ ├── ContentValueExtensions.kt │ ├── DatabaseCallback.kt │ ├── DatabaseHelper.kt │ ├── DatabaseHelperDelegate.kt │ ├── DatabaseStatement.kt │ ├── DatabaseStatementWrapper.kt │ ├── DatabaseWrapper.kt │ ├── FlowCursor.kt │ ├── MigrationFileHelper.kt │ ├── OpenHelper.kt │ └── SQLiteException.kt │ ├── migration │ ├── AlterTableMigration.kt │ ├── BaseMigration.kt │ ├── IndexMigration.kt │ ├── IndexPropertyMigration.kt │ ├── Migration.kt │ └── UpdateTableMigration.kt │ ├── observing │ ├── ObservingTableTracker.kt │ ├── OnTableChangedObserver.kt │ └── TableObserver.kt │ ├── query │ ├── Actionable.kt │ ├── BaseModelQueriable.kt │ ├── BaseOperator.kt │ ├── BaseQueriable.kt │ ├── BaseTransformable.kt │ ├── Case.kt │ ├── CaseCondition.kt │ ├── CompletedTrigger.kt │ ├── ContentValuesListener.kt │ ├── Delete.kt │ ├── ExistenceOperator.kt │ ├── From.kt │ ├── IConditional.kt │ ├── IOperator.kt │ ├── Index.kt │ ├── IndexedBy.kt │ ├── Insert.kt │ ├── Join.kt │ ├── LoadFromCursorListener.kt │ ├── Method.kt │ ├── ModelQueriable.kt │ ├── NameAlias.kt │ ├── Operator.kt │ ├── OperatorGroup.kt │ ├── OrderBy.kt │ ├── Queriable.kt │ ├── SQLOperator.kt │ ├── SQLite.kt │ ├── SQLiteStatementListener.kt │ ├── Select.kt │ ├── Set.kt │ ├── StringQuery.kt │ ├── Transformable.kt │ ├── Trigger.kt │ ├── TriggerMethod.kt │ ├── UnSafeStringOperator.kt │ ├── Update.kt │ ├── Where.kt │ ├── WhereBase.kt │ ├── cache │ │ ├── ModelCache.kt │ │ ├── ModelLruCache.kt │ │ ├── MultiKeyCacheConverter.kt │ │ ├── SimpleMapCache.kt │ │ └── SparseArrayBasedCache.kt │ ├── list │ │ ├── FlowCursorIterator.kt │ │ ├── FlowCursorList.kt │ │ ├── FlowQueryList.kt │ │ └── IFlowCursorIterator.kt │ └── property │ │ ├── IProperty.kt │ │ ├── IndexProperty.kt │ │ ├── Property.kt │ │ ├── PropertyFactory.kt │ │ ├── TypeConvertedProperty.kt │ │ └── WrapperProperty.kt │ ├── runtime │ ├── ContentResolverNotifier.kt │ ├── DBBatchSaveQueue.kt │ ├── DirectModelNotifier.kt │ ├── FlowContentObserver.kt │ ├── ModelNotifier.kt │ ├── NotifyDistributor.kt │ ├── OnTableChangedListener.kt │ └── TableNotifierRegister.kt │ ├── structure │ ├── Action.kt │ ├── BaseModel.kt │ ├── BaseModelView.kt │ ├── BaseQueryModel.kt │ ├── InvalidDBConfiguration.kt │ ├── Model.kt │ ├── NoModificationModel.kt │ ├── OneToMany.kt │ └── ReadOnlyModel.kt │ └── transaction │ ├── BaseTransactionManager.kt │ ├── DefaultTransactionManager.kt │ ├── DefaultTransactionQueue.kt │ ├── FastStoreModelTransaction.kt │ ├── ITransaction.kt │ ├── ITransactionQueue.kt │ ├── PriorityTransactionQueue.kt │ ├── PriorityTransactionWrapper.kt │ ├── ProcessModelTransaction.kt │ ├── Transaction.kt │ └── TransactionWrapper.kt ├── livedata ├── .gitignore ├── build.gradle.kts ├── gradle.properties ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── kotlin │ └── com │ └── dbflow5 │ └── livedata │ └── LiveData.kt ├── paging ├── build.gradle.kts ├── gradle.properties ├── settings.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── kotlin │ └── com │ └── dbflow5 │ └── paging │ └── QueryDataSource.kt ├── processor ├── build.gradle.kts ├── gradle.properties └── src │ ├── main │ ├── kotlin │ │ └── com │ │ │ └── dbflow5 │ │ │ └── processor │ │ │ ├── ClassNames.kt │ │ │ ├── DBFlowProcessor.kt │ │ │ ├── Handlers.kt │ │ │ ├── ProcessorManager.kt │ │ │ ├── SQLiteHelper.kt │ │ │ ├── Validators.kt │ │ │ ├── definition │ │ │ ├── Adders.kt │ │ │ ├── BaseDefinition.kt │ │ │ ├── BasicColumnGenerator.kt │ │ │ ├── DatabaseDefinition.kt │ │ │ ├── DatabaseHolderDefinition.kt │ │ │ ├── DatabaseObjectHolder.kt │ │ │ ├── EntityDefinition.kt │ │ │ ├── IndexGroupsDefinition.kt │ │ │ ├── ManyToManyDefinition.kt │ │ │ ├── Methods.kt │ │ │ ├── MigrationDefinition.kt │ │ │ ├── ModelViewDefinition.kt │ │ │ ├── OneToManyDefinition.kt │ │ │ ├── QueryModelDefinition.kt │ │ │ ├── TableDefinition.kt │ │ │ ├── TypeConverterDefinition.kt │ │ │ ├── TypeDefinition.kt │ │ │ ├── UniqueGroupsDefinition.kt │ │ │ ├── behavior │ │ │ │ ├── Behaviors.kt │ │ │ │ ├── ColumnBehaviors.kt │ │ │ │ ├── ComplexColumnBehavior.kt │ │ │ │ ├── CreationQueryBehavior.kt │ │ │ │ └── FTSBehaviors.kt │ │ │ ├── column │ │ │ │ ├── ColumnAccessCombiner.kt │ │ │ │ ├── ColumnAccessor.kt │ │ │ │ ├── ColumnDefinition.kt │ │ │ │ ├── DefinitionUtils.kt │ │ │ │ ├── ForeignKeyAccessCombiner.kt │ │ │ │ ├── ReferenceColumnDefinition.kt │ │ │ │ └── ReferenceDefinition.kt │ │ │ └── provider │ │ │ │ ├── ContentProvider.kt │ │ │ │ ├── ContentProviderDefinition.kt │ │ │ │ ├── ContentUriDefinition.kt │ │ │ │ ├── NotifyDefinition.kt │ │ │ │ └── TableEndpointDefinition.kt │ │ │ └── utils │ │ │ ├── CodeExtensions.kt │ │ │ ├── DependencyUtils.kt │ │ │ ├── ElementExtensions.kt │ │ │ ├── ElementUtility.kt │ │ │ ├── JavaPoetExtensions.kt │ │ │ ├── LetUtils.kt │ │ │ ├── ModelUtils.kt │ │ │ ├── ProcessorUtils.kt │ │ │ ├── StringUtils.kt │ │ │ └── WriterUtils.kt │ └── resources │ │ └── META-INF │ │ ├── gradle │ │ └── incremental.annotation.processors │ │ └── services │ │ └── javax.annotation.processing.Processor │ └── test │ └── java │ └── com │ └── raizlabs │ └── dbflow5 │ └── processor │ └── test │ ├── ColumnAccessCombinerTests.kt │ ├── ForeignKeyAccessCombinerTests.kt │ └── SimpleColumnAccessorTests.kt ├── proguard-rules.pro ├── reactive-streams ├── build.gradle.kts ├── gradle.properties └── src │ └── main │ ├── AndroidManifest.xml │ └── kotlin │ └── com │ └── dbflow5 │ └── reactivestreams │ ├── query │ ├── CursorListFlowable.kt │ ├── ModelQueriableExtensions.kt │ └── TableChangeOnSubscribe.kt │ ├── structure │ ├── BaseRXModel.kt │ ├── RXModelAdapter.kt │ └── RXRetrievalAdapter.kt │ └── transaction │ └── TransactionObservable.kt ├── settings.gradle ├── sqlcipher ├── .gitignore ├── build.gradle.kts ├── gradle.properties ├── proguard-rules.pro ├── settings.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── kotlin │ └── com │ └── dbflow5 │ └── sqlcipher │ ├── SQLCipherDatabase.kt │ ├── SQLCipherOpenHelper.kt │ └── SQLCipherStatement.kt ├── tests ├── .gitignore ├── build.gradle.kts ├── gradle.properties ├── proguard-rules.pro └── src │ ├── androidTest │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── dbflow5 │ │ ├── BaseUnitTest.kt │ │ ├── DBFlowInstrumentedTestRule.kt │ │ ├── ImmediateTransactionManager.kt │ │ ├── TestDatabase.kt │ │ ├── TestExtensions.kt │ │ ├── TestForeignKeyDatabaseTest.kt │ │ ├── User.kt │ │ ├── config │ │ ├── ConfigIntegrationTest.kt │ │ └── DatabaseConfigTest.kt │ │ ├── contentobserver │ │ ├── ContentObserverDatabase.kt │ │ ├── ContentObserverTest.kt │ │ └── User.kt │ │ ├── database │ │ └── transaction │ │ │ ├── CoroutinesTest.kt │ │ │ └── FastStoreModelTransactionTest.kt │ │ ├── livedata │ │ ├── LiveDataModels.kt │ │ └── LiveDataTest.kt │ │ ├── migration │ │ ├── MigrationModels.kt │ │ └── UpdateTableMigrationTest.kt │ │ ├── models │ │ ├── AutoIncrementTest.kt │ │ ├── CachingModels.kt │ │ ├── CachingModelsTest.kt │ │ ├── CurrencyDAO.kt │ │ ├── CurrencyDAOTest.kt │ │ ├── DontCreateModelTest.kt │ │ ├── ForeignKeyModels.kt │ │ ├── FtsModelTest.kt │ │ ├── IndexModels.kt │ │ ├── InnerClassExample.kt │ │ ├── ManyToMany.kt │ │ ├── ManyToManyTest.kt │ │ ├── ModelViewTest.kt │ │ ├── ModelViews.kt │ │ ├── NonTypical │ │ │ └── nonTypicalClassName.kt │ │ ├── OneToManyModelTest.kt │ │ ├── OneToManyModels.kt │ │ ├── ParentChildCachingTest.kt │ │ ├── ProspectQuiz.kt │ │ ├── QueryModelTest.kt │ │ ├── QueryModels.kt │ │ ├── SimpleTestModels.kt │ │ ├── SimpleTestModelsTest.kt │ │ ├── TempModelTest.kt │ │ └── java │ │ │ ├── DatabaseModel.java │ │ │ ├── JavaModel.java │ │ │ ├── JavaModelView.java │ │ │ └── otherpackage │ │ │ └── ExampleModel.java │ │ ├── paging │ │ └── QueryDataSourceTest.kt │ │ ├── prepackaged │ │ ├── PrepackagedDB.kt │ │ └── PrepackagedDBTest.kt │ │ ├── provider │ │ ├── ContentProviderObjects.kt │ │ ├── ContentProviderTests.kt │ │ └── TestContentProvider.kt │ │ ├── query │ │ ├── cache │ │ │ ├── ModelLruCacheTest.kt │ │ │ └── SimpleMapCacheTest.kt │ │ └── list │ │ │ ├── FlowCursorIteratorTest.kt │ │ │ └── FlowCursorListTest.kt │ │ ├── runtime │ │ └── DirectNotifierTest.kt │ │ ├── rx2 │ │ ├── RXTestRule.kt │ │ ├── TransactionObservablesTest.kt │ │ └── query │ │ │ ├── CursorResultSubscriberTest.kt │ │ │ ├── RXFlowableTest.kt │ │ │ ├── RXQueryTests.kt │ │ │ └── RxModels.kt │ │ ├── sql │ │ └── language │ │ │ ├── CaseTest.kt │ │ │ ├── DeleteTest.kt │ │ │ ├── ExistenceOperatorTest.kt │ │ │ ├── FromTest.kt │ │ │ ├── IndexTest.kt │ │ │ ├── IndexedByTest.kt │ │ │ ├── InsertTest.kt │ │ │ ├── JoinTest.kt │ │ │ ├── MethodTest.kt │ │ │ ├── NameAliasTest.kt │ │ │ ├── OperatorGroupTest.kt │ │ │ ├── OperatorTest.kt │ │ │ ├── OrderByTest.kt │ │ │ ├── SelectTest.kt │ │ │ ├── SetTest.kt │ │ │ ├── TriggerTest.kt │ │ │ ├── UnsafeStringOperatorTest.kt │ │ │ ├── UpdateTest.kt │ │ │ ├── WhereTest.kt │ │ │ └── property │ │ │ ├── BytePropertyTest.kt │ │ │ ├── CharPropertyTest.kt │ │ │ ├── DoublePropertyTest.kt │ │ │ ├── FloatPropertyTest.kt │ │ │ ├── IndexPropertyTest.kt │ │ │ ├── IntPropertyTest.kt │ │ │ ├── LongPropertyTest.kt │ │ │ ├── PropertyFactoryTest.kt │ │ │ ├── PropertyTest.kt │ │ │ ├── ShortPropertyTest.kt │ │ │ └── TypeConvertedPropertyTest.kt │ │ └── sqlcipher │ │ ├── CipherDatabase.kt │ │ ├── CipherTest.kt │ │ └── CipherTestObjects.kt │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── prepackaged.db │ │ └── prepackaged_2.db │ ├── java │ │ └── com │ │ │ └── dbflow5 │ │ │ ├── DemoApp.kt │ │ │ ├── StubContentProvider.kt │ │ │ └── test │ │ │ └── DemoActivity.java │ └── res │ │ ├── layout │ │ └── activity_demo.xml │ │ ├── menu │ │ └── menu_demo.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── dimens.xml │ │ └── strings.xml │ └── test │ ├── AndroidManifest.xml │ ├── assets │ ├── migrations │ │ └── Migrations │ │ │ └── 0.sql │ └── testdb.db │ └── resources │ └── com │ └── android │ └── tools │ └── test_config.properties └── usage2 ├── .gitignore ├── 5.0-migration-guide.md ├── README.md ├── advanced-usage ├── README.md ├── caching.md ├── indexing.md ├── listbasedqueries.md ├── multiplemodules.md ├── querymodels.md └── sqlciphersupport.md ├── book.json ├── contentprovidergeneration.md ├── gettingstarted.md ├── including-in-project.md ├── kotlinsupport.md ├── livedata.md ├── migration4guide.md ├── proguard.md ├── rxjavasupport.md └── usage ├── README.md ├── databases.md ├── migrations.md ├── models.md ├── modelviews.md ├── observability.md ├── relationships.md ├── retrieval.md ├── sqlitewrapperlanguage.md ├── storingdata.md └── typeconverters.md /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | 15 | # Gradle files 16 | .gradle/ 17 | build/ 18 | 19 | # Local configuration file (sdk path, etc) 20 | local.properties 21 | 22 | # Eclipse project files 23 | .classpath 24 | .project 25 | 26 | # Proguard folder generated by Eclipse 27 | proguard/ 28 | 29 | # Intellij project files 30 | *.iml 31 | *.ipr 32 | *.iws 33 | .idea/ 34 | crashlytics-build.properties 35 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "usage2"] 2 | path = usage2 3 | url = https://github.com/agrosner/DBFlowDocs.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Raizlabs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Table of contents 2 | 3 | * [README](README.md) 4 | * [Usage Docs](usage2/README.md) 5 | * [Including In Project](usage2/including-in-project.md) 6 | * [Getting Started](usage2/gettingstarted.md) 7 | * [Proguard](usage2/proguard.md) 8 | * [Advanced Usage](usage2/advanced-usage/README.md) 9 | * [Caching](usage2/advanced-usage/caching.md) 10 | * [List Queries](usage2/advanced-usage/listbasedqueries.md) 11 | * [Multiple Modules](usage2/advanced-usage/multiplemodules.md) 12 | * [QueryModels](usage2/advanced-usage/querymodels.md) 13 | * [Indexing](usage2/advanced-usage/indexing.md) 14 | * [SQLCipher](usage2/advanced-usage/sqlciphersupport.md) 15 | * [Main Usage](usage2/usage/README.md) 16 | * [Databases](usage2/usage/databases.md) 17 | * [Models](usage2/usage/models.md) 18 | * [Migrations](usage2/usage/migrations.md) 19 | * [Views](usage2/usage/modelviews.md) 20 | * [Relationships](usage2/usage/relationships.md) 21 | * [Storing Data](usage2/usage/storingdata.md) 22 | * [Retrieval](usage2/usage/retrieval.md) 23 | * [SQLite Query Language](usage2/usage/sqlitewrapperlanguage.md) 24 | * [TypeConverters](usage2/usage/typeconverters.md) 25 | * [Observability](usage2/usage/observability.md) 26 | * [RXJavaSupport](usage2/rxjavasupport.md) 27 | * [ContentProviderGeneration](usage2/contentprovidergeneration.md) 28 | * [5.0 Migration Guide](usage2/5.0-migration-guide.md) 29 | * [Migration4Guide](usage2/migration4guide.md) 30 | * [ISSUE\_TEMPLATE](issue_template.md) 31 | 32 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | google() 5 | gradlePluginPortal() 6 | } 7 | dependencies { 8 | classpath("com.android.tools.build:gradle:4.1.2") 9 | classpath("com.github.dcendents:android-maven-gradle-plugin:2.1") 10 | classpath("com.getkeepsafe.dexcount:dexcount-gradle-plugin:2.0.0") 11 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.Kotlin}") 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | google() 19 | maven(url = "https://www.jitpack.io") 20 | } 21 | } 22 | 23 | tasks.register("clean", Delete::class) { 24 | delete(rootProject.buildDir) 25 | } -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | } 4 | 5 | repositories { 6 | jcenter() 7 | } -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/Dependencies.kt: -------------------------------------------------------------------------------- 1 | object Versions { 2 | const val Kotlin = "1.4.21" 3 | const val TargetSdk = 28 4 | const val MinSdk = 7 5 | const val MinSdkRX = 16 6 | const val SQLCipherMin = 7 7 | const val ArchMin = 14 8 | } 9 | 10 | object Dependencies { 11 | const val SqlCipher = "net.zetetic:android-database-sqlcipher:4.4.2" 12 | const val RX = "io.reactivex.rxjava3:rxjava:3.0.4" 13 | const val Coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2" 14 | const val JavaPoet = "com.squareup:javapoet:1.11.1" 15 | const val KPoet = "com.github.agrosner:KPoet:1.0.0" 16 | const val JavaXAnnotation = "org.glassfish:javax.annotation:10.0-b28" 17 | const val JUnit = "junit:junit:4.12" 18 | 19 | object AndroidX { 20 | const val Annotations = "androidx.annotation:annotation:1.1.0" 21 | const val LiveData = "androidx.lifecycle:lifecycle-livedata:2.2.0" 22 | const val Paging = "androidx.paging:paging-runtime:2.1.2" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contentprovider-annotations/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /contentprovider-annotations/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | kotlin("jvm") 5 | } 6 | 7 | // project.ext.artifactId = bt_name 8 | 9 | tasks.withType { 10 | kotlinOptions.jvmTarget = "1.8" 11 | } 12 | 13 | dependencies { 14 | api(project(":core")) 15 | } 16 | 17 | apply(from = "../kotlin-artifacts.gradle") 18 | -------------------------------------------------------------------------------- /contentprovider-annotations/gradle.properties: -------------------------------------------------------------------------------- 1 | bt_name=contentprovider-annotations 2 | bt_packaging=jar 3 | bt_artifact_id=contentprovider-annotations -------------------------------------------------------------------------------- /contentprovider-annotations/src/main/kotlin/com/dbflow5/contentprovider/annotation/ContentProvider.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.contentprovider.annotation 2 | 3 | import kotlin.reflect.KClass 4 | 5 | /** 6 | * Description: Defines a Content Provider that gets generated. 7 | */ 8 | @Target(AnnotationTarget.CLASS, AnnotationTarget.FILE) 9 | @Retention(AnnotationRetention.SOURCE) 10 | annotation class ContentProvider( 11 | /** 12 | * @return The authority URI for this provider. 13 | */ 14 | val authority: String, 15 | /** 16 | * @return The class of the database this belongs to 17 | */ 18 | val database: KClass<*>, 19 | /** 20 | * @return The base content uri String to use for all paths 21 | */ 22 | val baseContentUri: String = "", 23 | 24 | /** 25 | * @return the holder class to pass to constructor of the ContentProvider so it will initialize before using DB. 26 | */ 27 | val initializeHolderClass: KClass<*> = Any::class) 28 | -------------------------------------------------------------------------------- /contentprovider-annotations/src/main/kotlin/com/dbflow5/contentprovider/annotation/Notify.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.contentprovider.annotation 2 | 3 | /** 4 | * Description: Annotates a method part of [com.dbflow5.annotation.provider.TableEndpoint] 5 | * that gets called back when changed. The method must return a Uri or an array of Uri[] to notify changed on 6 | * the content provider. 7 | */ 8 | @Retention(AnnotationRetention.SOURCE) 9 | @Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) 10 | annotation class Notify( 11 | /** 12 | * @return The [com.dbflow5.annotation.provider.Notify.Method] notify 13 | */ 14 | val notifyMethod: NotifyMethod, 15 | /** 16 | * @return Registers itself for the following paths. If a specific path is called for the specified 17 | * method, the method this annotation corresponds to will be called. 18 | */ 19 | val paths: Array = []) 20 | 21 | enum class NotifyMethod { 22 | INSERT, 23 | UPDATE, 24 | DELETE 25 | } -------------------------------------------------------------------------------- /contentprovider-annotations/src/main/kotlin/com/dbflow5/contentprovider/annotation/TableEndpoint.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.contentprovider.annotation 2 | 3 | import kotlin.reflect.KClass 4 | 5 | /** 6 | * Description: Defines an endpoint that gets placed inside of a [ContentProvider] 7 | */ 8 | @Target(AnnotationTarget.CLASS, AnnotationTarget.FILE) 9 | @Retention(AnnotationRetention.SOURCE) 10 | annotation class TableEndpoint( 11 | /** 12 | * @return The name of the table this endpoint corresponds to. 13 | */ 14 | val name: String, 15 | /** 16 | * @return When placed in a top-level class, this is required to connect it to a provider. 17 | */ 18 | val contentProvider: KClass<*>) 19 | -------------------------------------------------------------------------------- /contentprovider/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /contentprovider/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.library") 3 | kotlin("android") 4 | } 5 | 6 | // project.ext.artifactId = bt_name 7 | 8 | android { 9 | compileSdkVersion(Versions.TargetSdk) 10 | 11 | defaultConfig { 12 | minSdkVersion(Versions.MinSdk) 13 | targetSdkVersion(Versions.TargetSdk) 14 | } 15 | 16 | compileOptions { 17 | sourceCompatibility = JavaVersion.VERSION_1_8 18 | targetCompatibility = JavaVersion.VERSION_1_8 19 | } 20 | 21 | sourceSets { 22 | getByName("main").java.srcDirs("src/main/kotlin") 23 | } 24 | } 25 | 26 | dependencies { 27 | api(project(":lib")) 28 | api(project(":contentprovider-annotations")) 29 | api(Dependencies.AndroidX.Annotations) 30 | } 31 | 32 | apply(from = "../kotlin-artifacts.gradle") 33 | 34 | -------------------------------------------------------------------------------- /contentprovider/gradle.properties: -------------------------------------------------------------------------------- 1 | bt_name=contentprovider 2 | bt_packaging=aar 3 | bt_artifact_id=contentprovider -------------------------------------------------------------------------------- /contentprovider/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /contentprovider/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /contentprovider/src/main/kotlin/com/dbflow5/provider/ContentProviderDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.provider 2 | 3 | import android.content.ContentValues 4 | import com.dbflow5.config.DBFlowDatabase 5 | import com.dbflow5.database.AndroidDatabaseWrapper 6 | 7 | /** 8 | * Description: Base class providing [ContentValues] for a [DBFlowDatabase]. 9 | */ 10 | abstract class ContentProviderDatabase : AndroidDatabaseWrapper, DBFlowDatabase() { 11 | 12 | private val database 13 | get() = (writableDatabase as? AndroidDatabaseWrapper) 14 | ?: throw IllegalStateException("Invalid DB type used. It must be a type of ${AndroidDatabaseWrapper::class.java}. ") 15 | 16 | override fun updateWithOnConflict(tableName: String, 17 | contentValues: ContentValues, 18 | where: String?, 19 | whereArgs: Array?, 20 | conflictAlgorithm: Int): Long = 21 | database.updateWithOnConflict(tableName, contentValues, where, whereArgs, conflictAlgorithm) 22 | 23 | override fun insertWithOnConflict(tableName: String, 24 | nullColumnHack: String?, 25 | values: ContentValues, 26 | sqLiteDatabaseAlgorithmInt: Int): Long = 27 | database.insertWithOnConflict(tableName, nullColumnHack, values, sqLiteDatabaseAlgorithmInt) 28 | } -------------------------------------------------------------------------------- /contentprovider/src/main/kotlin/com/dbflow5/provider/StubContentProvider.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.provider 2 | 3 | /** 4 | * Description: 5 | */ 6 | 7 | import android.content.ContentProvider 8 | import android.content.ContentValues 9 | import android.database.Cursor 10 | import android.net.Uri 11 | 12 | /** 13 | * Description: Used as a stub, include this in order to work around Android O changes to [ContentProvider] 14 | */ 15 | class StubContentProvider : ContentProvider() { 16 | 17 | override fun insert(uri: Uri, values: ContentValues?): Uri? { 18 | return null 19 | } 20 | 21 | override fun query(uri: Uri, 22 | projection: Array?, 23 | selection: String?, 24 | selectionArgs: Array?, 25 | sortOrder: String?): Cursor? { 26 | return null 27 | } 28 | 29 | override fun onCreate(): Boolean { 30 | return true 31 | } 32 | 33 | override fun update(uri: Uri, values: ContentValues?, 34 | selection: String?, selectionArgs: Array?): Int { 35 | return 0 36 | } 37 | 38 | override fun delete(uri: Uri, selection: String?, selectionArgs: Array?): Int { 39 | return 0 40 | } 41 | 42 | override fun getType(uri: Uri): String? { 43 | return null 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /core/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /core/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | kotlin("jvm") 5 | } 6 | 7 | // project.ext.artifactId = bt_name 8 | 9 | tasks.withType { 10 | kotlinOptions.jvmTarget = "1.8" 11 | } 12 | 13 | apply(from = "../kotlin-artifacts.gradle") 14 | -------------------------------------------------------------------------------- /core/gradle.properties: -------------------------------------------------------------------------------- 1 | bt_name=dbflow-core 2 | bt_packaging=jar 3 | bt_artifact_id=dbflow-core -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/Collate.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | /** 4 | * Represents a SQL Collate method for comparing string columns. 5 | */ 6 | enum class Collate { 7 | 8 | /** 9 | * Tells the table creation and condition that we wont use collation 10 | */ 11 | NONE, 12 | 13 | /** 14 | * Compares string data normally 15 | */ 16 | BINARY, 17 | 18 | /** 19 | * Ignores case for the 26 upper case characters of ASCII are folded to lower case equivalents. 20 | * Does not attempt to fold UTF so be careful! 21 | */ 22 | NOCASE, 23 | 24 | /** 25 | * Trims trailing space characters before performing comparison. 26 | */ 27 | RTRIM, 28 | 29 | /** 30 | * Takes the current locale data into account. 31 | */ 32 | LOCALIZED, 33 | 34 | /** 35 | * The Unicode Collation Algorithm and not tailored to the current locale. 36 | */ 37 | UNICODE 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/ColumnIgnore.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | /** 4 | * Description: An annotation used to ignore a column in the [Table.allFields] instance. 5 | */ 6 | @Retention(AnnotationRetention.BINARY) 7 | @Target(AnnotationTarget.FIELD) 8 | annotation class ColumnIgnore 9 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/ColumnMap.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | /** 4 | * Description: Maps an arbitrary object and its corresponding fields into a set of columns. It is similar 5 | * to [ForeignKey] except it's not represented in the DB hierarchy. 6 | */ 7 | @Retention(AnnotationRetention.BINARY) 8 | @Target(AnnotationTarget.FIELD) 9 | annotation class ColumnMap( 10 | /** 11 | * Defines explicit references for a composite [ColumnMap] definition. 12 | * 13 | * @return override explicit usage of all fields and provide custom references. 14 | */ 15 | val references: Array = []) 16 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/ColumnMapReference.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | import com.dbflow5.converter.TypeConverter 4 | import kotlin.reflect.KClass 5 | 6 | /** 7 | * Description: Allows a [ColumnMap] to specify a reference override for its fields. Anything not 8 | * defined here will not be used. 9 | */ 10 | @Retention(AnnotationRetention.BINARY) 11 | @Target(AnnotationTarget.FIELD) 12 | annotation class ColumnMapReference( 13 | /** 14 | * @return The local column name that will be referenced in the DB 15 | */ 16 | val columnName: String, 17 | /** 18 | * @return The column name in the referenced table 19 | */ 20 | val columnMapFieldName: String, 21 | /** 22 | * @return The default value for the reference column. Same as [Column.defaultValue] 23 | */ 24 | val defaultValue: String = "", 25 | 26 | /** 27 | * @return A custom type converter that's only used for this field. It will be created and used in 28 | * the Adapter associated with this table. 29 | */ 30 | val typeConverter: KClass> = TypeConverter::class, 31 | 32 | /** 33 | * @return Specify the [NotNull] annotation here and it will get pasted into the reference definition. 34 | */ 35 | val notNull: NotNull = NotNull(onNullConflict = ConflictAction.NONE)) 36 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/ForeignKeyAction.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | /** 4 | * Actions associated with on update and on delete 5 | */ 6 | enum class ForeignKeyAction { 7 | /** 8 | * When a parent key is modified or deleted from the database, no special action is taken 9 | */ 10 | NO_ACTION, 11 | /** 12 | * The "RESTRICT" action means that the application is prohibited from deleting (for ON DELETE RESTRICT) 13 | * or modifying (for ON UPDATE RESTRICT) a parent key when there exists one or more child keys mapped to it. 14 | */ 15 | RESTRICT, 16 | /** 17 | * when a parent key is deleted (for ON DELETE SET NULL) or modified (for ON UPDATE SET NULL), 18 | * the child key columns of all rows in the child table that mapped to the parent key are set 19 | * to contain SQL NULL values. 20 | */ 21 | SET_NULL, 22 | /** 23 | * The "SET DEFAULT" actions are similar to [ForeignKeyAction.SET_NULL], except that each of the child key 24 | * columns is set to contain the columns default value instead of NULL 25 | */ 26 | SET_DEFAULT, 27 | /** 28 | * A "CASCADE" action propagates the delete or update operation on the parent key to each dependent child key. 29 | * For an "ON DELETE CASCADE" action, this means that each row in the child table that was associated with 30 | * the deleted parent row is also deleted. For an "ON UPDATE CASCADE" action, it means that the values 31 | * stored in each dependent child key are modified to match the new parent key values. 32 | */ 33 | CASCADE 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/ForeignKeyReference.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | /** 4 | * Description: Used inside of [ForeignKey.references], describes the 5 | * local column name, type, and referencing table column name. 6 | * 7 | * 8 | * Note: the type of the local column must match the 9 | * column type of the referenced column. By using a field as a Model object, 10 | * you will need to ensure the same types are used. 11 | */ 12 | @Retention(AnnotationRetention.SOURCE) 13 | annotation class ForeignKeyReference( 14 | /** 15 | * @return The local column name that will be referenced in the DB 16 | */ 17 | val columnName: String, 18 | /** 19 | * @return The column name in the referenced table 20 | */ 21 | val foreignKeyColumnName: String, 22 | /** 23 | * @return The default value for the reference column. Same as [Column.defaultValue] 24 | */ 25 | val defaultValue: String = "", 26 | 27 | /** 28 | * @return Specify the [NotNull] annotation here and it will get pasted into the reference definition. 29 | */ 30 | val notNull: NotNull = NotNull(onNullConflict = ConflictAction.NONE)) 31 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/Fts.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | import kotlin.reflect.KClass 4 | 5 | /** 6 | * Description: Creates a class using the SQLITE FTS3 [https://www.sqlite.org/fts3.html] 7 | */ 8 | @Retention(AnnotationRetention.SOURCE) 9 | @Target(AnnotationTarget.CLASS) 10 | annotation class Fts3 11 | 12 | 13 | /** 14 | * Description: Creates a class using the SQLITE FTS4 [https://www.sqlite.org/fts3.html] 15 | */ 16 | @Retention(AnnotationRetention.SOURCE) 17 | @Target(AnnotationTarget.CLASS) 18 | annotation class Fts4( 19 | /** 20 | * Optionally points to a content table that fills this FTS4 with content. 21 | * The content option allows FTS4 to forego storing the text being indexed and 22 | * results in significant space savings. 23 | */ 24 | val contentTable: KClass<*> = Any::class 25 | ) 26 | 27 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/Index.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | /** 4 | * Description: Creates an index for a specified [Column]. A single column can belong to multiple 5 | * indexes within the same table if you wish. 6 | */ 7 | @Retention(AnnotationRetention.SOURCE) 8 | @Target(AnnotationTarget.FIELD) 9 | annotation class Index( 10 | /** 11 | * @return The set of index groups that this index belongs to. 12 | */ 13 | val indexGroups: IntArray = []) 14 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/IndexGroup.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | const val INDEX_GENERIC = -1 4 | 5 | /** 6 | * Description: 7 | */ 8 | @Target(AnnotationTarget.ANNOTATION_CLASS) 9 | @Retention(AnnotationRetention.SOURCE) 10 | annotation class IndexGroup( 11 | /** 12 | * @return The number that each contained [Index] points to, so they can be combined into a single index. 13 | * If [.INDEX_GENERIC], this will assume a generic index that covers the whole table. 14 | */ 15 | val number: Int = INDEX_GENERIC, 16 | /** 17 | * @return The name of this index. It must be unique from other [IndexGroup]. 18 | */ 19 | val name: String, 20 | /** 21 | * @return If true, this will disallow duplicate values to be inserted into the table. 22 | */ 23 | val unique: Boolean = false) 24 | 25 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/InheritedColumn.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | import com.dbflow5.annotation.ConflictAction 4 | 5 | /** 6 | * Description: Allows [Table] to inherit fields from other objects to make it part of the DB table. 7 | */ 8 | @Target(AnnotationTarget.ANNOTATION_CLASS) 9 | @Retention(AnnotationRetention.SOURCE) 10 | annotation class InheritedColumn( 11 | /** 12 | * @return The column annotation as if it was part of the class 13 | */ 14 | val column: Column, 15 | /** 16 | * @return The field name that an inherited column uses. It must match exactly case-by-case to the field you're referencing. 17 | * If the field is private, the [Column] allows you to define getter and setters for it. 18 | */ 19 | val fieldName: String, 20 | /** 21 | * @return If specified other than [ConflictAction.NONE], then we assume [NotNull]. 22 | */ 23 | val nonNullConflict: ConflictAction = ConflictAction.NONE) 24 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/InheritedPrimaryKey.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | /** 4 | * Description: Allows you to specify a non-Column to be inherited and used as a [PrimaryKey] 5 | */ 6 | @Target(AnnotationTarget.ANNOTATION_CLASS) 7 | @Retention(AnnotationRetention.SOURCE) 8 | annotation class InheritedPrimaryKey( 9 | /** 10 | * @return The primary key annotation as if it was part of the class 11 | */ 12 | val primaryKey: PrimaryKey, 13 | /** 14 | * @return The column annotation as if it was part of the class 15 | */ 16 | val column: Column, 17 | /** 18 | * @return The field name that an inherited column uses. It must match exactly case-by-case to the field you're referencing. 19 | * If the field is private, the [PrimaryKey] allows you to define getter and setters for it. 20 | */ 21 | val fieldName: String) 22 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/Migration.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | import kotlin.reflect.KClass 4 | 5 | /** 6 | * Description: Marks a Migration class to be included in DB construction. The class using this annotation 7 | * must implement the Migration interface. 8 | */ 9 | @Retention(AnnotationRetention.SOURCE) 10 | @Target(AnnotationTarget.CLASS, AnnotationTarget.FILE) 11 | annotation class Migration( 12 | /** 13 | * @return The version the migration will trigger at. 14 | */ 15 | val version: Int, 16 | /** 17 | * @return Specify the database class that this migration belongs to. 18 | */ 19 | val database: KClass<*>, 20 | /** 21 | * @return If number greater than -1, the migrations are in run in reverse priority, 22 | * meaning ones from the same [version] get ordered from 23 | * lowest to highest number. if they are the same priority, 24 | * there is no telling which one is executed first. The 25 | * annotation processor will process in order it finds the classes. 26 | */ 27 | val priority: Int = -1) 28 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/ModelCacheField.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | /** 4 | * Description: marks a single field as a ModelCache creator that is used in the corresponding ModelAdapter. 5 | */ 6 | @Target(AnnotationTarget.FIELD) 7 | @Retention(AnnotationRetention.SOURCE) 8 | annotation class ModelCacheField 9 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/ModelViewQuery.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | import com.dbflow5.sql.Query 4 | 5 | /** 6 | * Description: Represents a field that is a [Query]. This is only meant to be used as a query 7 | * reference in [ModelView]. This is so the annotation processor knows how to access the query of 8 | * the view. 9 | */ 10 | @Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER) 11 | @Retention(AnnotationRetention.SOURCE) 12 | annotation class ModelViewQuery 13 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/MultiCacheField.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | /** 4 | * Description: Marks a field as the IMultiKeyCacheModel that we use to convert multiple fields into 5 | * a single key for caching. 6 | */ 7 | @Target(AnnotationTarget.FIELD) 8 | @Retention(AnnotationRetention.SOURCE) 9 | annotation class MultiCacheField 10 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/MultipleManyToMany.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | /** 4 | * Description: Provides ability to add multiple [ManyToMany] annotations at once. 5 | */ 6 | @Retention(AnnotationRetention.SOURCE) 7 | @Target(AnnotationTarget.CLASS, AnnotationTarget.FILE) 8 | annotation class MultipleManyToMany(vararg val value: ManyToMany) 9 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/NotNull.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | /** 4 | * Description: Specifies that a [Column] is not null. 5 | * Note this simply inserts the constraint into SQLite statements and does not enforce the column's 6 | * model field nullability, which is separate. 7 | * 8 | * In the case of a [ForeignKeyReference], this will make all references [NotNull] based on the 9 | * [ConflictAction] specified. If you need one to support null, then you need to be explicit 10 | * in the [ForeignKeyReference]. 11 | */ 12 | @Target(AnnotationTarget.FIELD) 13 | @Retention(AnnotationRetention.SOURCE) 14 | annotation class NotNull( 15 | /** 16 | * Defines how to handle conflicts for not null column 17 | * 18 | * @return a [com.dbflow5.annotation.ConflictAction] enum 19 | */ 20 | val onNullConflict: ConflictAction = ConflictAction.FAIL) 21 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/PrimaryKey.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | /** 4 | * Description: 5 | */ 6 | @Retention(AnnotationRetention.SOURCE) 7 | @Target(AnnotationTarget.FIELD) 8 | annotation class PrimaryKey( 9 | /** 10 | * Specifies if the column is autoincrementing or not 11 | */ 12 | val autoincrement: Boolean = false, 13 | /** 14 | * Specifies the column to be treated as a ROWID but is not an [.autoincrement]. This 15 | * overrides [.autoincrement] and is mutually exclusive. 16 | */ 17 | val rowID: Boolean = false, 18 | /** 19 | * @return When true, we simple do {columnName} > 0 when checking for it's existence if [.autoincrement] 20 | * is true. If not, we do a full database SELECT exists. 21 | */ 22 | val quickCheckAutoIncrement: Boolean = false) 23 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/QueryModel.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | import kotlin.reflect.KClass 4 | 5 | /** 6 | * Description: Marks a Model class as NOT a [Table], but generates code for retrieving data from a 7 | * generic query 8 | */ 9 | @Retention(AnnotationRetention.SOURCE) 10 | @Target(AnnotationTarget.CLASS, AnnotationTarget.FILE) 11 | annotation class QueryModel( 12 | /** 13 | * @return Specify the class of the database to use. 14 | */ 15 | val database: KClass<*>, 16 | /** 17 | * @return If true, all accessible, non-static, and non-final fields are treated as valid fields. 18 | * @see Table.allFields 19 | */ 20 | val allFields: Boolean = true, 21 | 22 | /** 23 | * @return If true, we throw away checks for column indexing and simply assume that the cursor returns 24 | * all our columns in order. This may provide a slight performance boost. 25 | */ 26 | val orderedCursorLookUp: Boolean = false, 27 | /** 28 | * @return When true, we reassign the corresponding Model's fields to default values when loading 29 | * from cursor. If false, we assign values only if present in Cursor. 30 | */ 31 | val assignDefaultValuesFromCursor: Boolean = true) 32 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/TypeConverter.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | import kotlin.reflect.KClass 4 | 5 | /** 6 | * Author: andrewgrosner 7 | * Description: Marks a class as being a TypeConverter. A type converter will turn a non-model, non-SQLiteTyped class into 8 | * a valid database type. 9 | */ 10 | @Retention(AnnotationRetention.BINARY) 11 | @Target(AnnotationTarget.CLASS, AnnotationTarget.FILE) 12 | annotation class TypeConverter( 13 | /** 14 | * @return Specify a set of subclasses by which the [TypeConverter] registers for. For 15 | * each one, this will create a new instance of the converter. 16 | */ 17 | val allowedSubtypes: Array> = []) 18 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/Unique.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | /** 4 | * Description: Marks the field as unique, meaning its value cannot be repeated. It is, however, 5 | * NOT a primary key. 6 | */ 7 | @Retention(AnnotationRetention.BINARY) 8 | @Target(AnnotationTarget.FIELD) 9 | annotation class Unique( 10 | /** 11 | * @return if field is unique. If false, we expect [.uniqueGroups] to be specified.` 12 | */ 13 | val unique: Boolean = true, 14 | /** 15 | * @return Marks a unique field as part of a unique group. For every unique number entered, 16 | * it will generate a UNIQUE() column statement. 17 | */ 18 | val uniqueGroups: IntArray = [], 19 | /** 20 | * Defines how to handle conflicts for a unique column 21 | * 22 | * @return a [ConflictAction] enum 23 | */ 24 | val onUniqueConflict: ConflictAction = ConflictAction.FAIL) 25 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/annotation/UniqueGroup.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.annotation 2 | 3 | /** 4 | * Description: 5 | */ 6 | @Target(AnnotationTarget.ANNOTATION_CLASS) 7 | @Retention(AnnotationRetention.SOURCE) 8 | annotation class UniqueGroup( 9 | /** 10 | * @return The number that columns point to to use this group 11 | */ 12 | val groupNumber: Int, 13 | /** 14 | * @return The conflict action that this group takes. 15 | */ 16 | val uniqueConflict: ConflictAction = ConflictAction.FAIL) 17 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/data/Blob.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.data 2 | 3 | /** 4 | * Description: Provides a way to support blob format data. 5 | */ 6 | class Blob @JvmOverloads constructor( 7 | /** 8 | * Sets the underlying blob data. 9 | * 10 | * @param blob The set of bytes to use. 11 | */ 12 | var blob: ByteArray? = null) 13 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/sql/Query.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sql 2 | 3 | /** 4 | * Description: The basic interface for something that has a piece of a query. 5 | */ 6 | interface Query { 7 | 8 | /** 9 | * @return the SQL query statement here 10 | */ 11 | val query: String 12 | } 13 | -------------------------------------------------------------------------------- /core/src/main/kotlin/com/dbflow5/sql/QueryCloneable.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sql 2 | 3 | /** 4 | * Description: 5 | */ 6 | interface QueryCloneable { 7 | 8 | fun cloneSelf(): T 9 | } -------------------------------------------------------------------------------- /coroutines/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /coroutines/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.library") 3 | kotlin("android") 4 | } 5 | 6 | // project.ext.artifactId = bt_name 7 | 8 | android { 9 | compileSdkVersion(Versions.TargetSdk) 10 | defaultConfig { 11 | minSdkVersion(15) 12 | targetSdkVersion(Versions.TargetSdk) 13 | } 14 | 15 | buildTypes { 16 | getByName("release") { 17 | minifyEnabled (false) 18 | proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro") 19 | } 20 | } 21 | 22 | sourceSets { 23 | getByName("main").java.srcDirs("src/main/kotlin") 24 | } 25 | } 26 | 27 | dependencies { 28 | implementation(project(":lib")) 29 | api(Dependencies.Coroutines) 30 | } 31 | 32 | apply(from = "../kotlin-artifacts.gradle") 33 | -------------------------------------------------------------------------------- /coroutines/gradle.properties: -------------------------------------------------------------------------------- 1 | bt_name=dbflow-coroutines 2 | bt_packaging=aar 3 | bt_artifact_id=dbflow-coroutines -------------------------------------------------------------------------------- /coroutines/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /coroutines/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = buildName -------------------------------------------------------------------------------- /coroutines/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dbflow_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agrosner/DBFlow/e1b6211dac6ddc0aa0c1c9a76a116478ccf92b86/dbflow_banner.png -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## For more details on how to configure your build environment visit 2 | # http://www.gradle.org/docs/current/userguide/build_environment.html 3 | # 4 | # Specifies the JVM arguments used for the daemon process. 5 | # The setting is particularly useful for tweaking memory settings. 6 | # Default value: -Xmx1024m -XX:MaxPermSize=256m 7 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 8 | # 9 | # When configured, Gradle will run in incubating parallel mode. 10 | # This option should only be used with decoupled projects. More details, visit 11 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 12 | # org.gradle.parallel=true 13 | #Sat Jan 30 13:55:08 EST 2021 14 | android.enableJetifier=true 15 | android.useAndroidX=true 16 | bt_gitUrl=https\://github.com/agrosner/DBFlow.git 17 | bt_licenseName=The MIT License 18 | bt_licenseUrl=http\://opensource.org/licenses/MIT 19 | bt_repo=Libraries 20 | bt_siteUrl=https\://github.com/agrosner/DBFlow 21 | dbflow_build_tools_version=26.0.2 22 | dbflow_min_sdk=4 23 | dbflow_min_sdk_rx=15 24 | dbflow_project_prefix=\: 25 | dbflow_target_sdk=26 26 | group=com.dbflow5 27 | kotlin.incremental=false 28 | version=5.0.0-alpha2 29 | version_code=1 30 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agrosner/DBFlow/e1b6211dac6ddc0aa0c1c9a76a116478ccf92b86/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Jan 30 13:51:40 EST 2021 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip 7 | -------------------------------------------------------------------------------- /issue_template.md: -------------------------------------------------------------------------------- 1 | # ISSUE\_TEMPLATE 2 | 3 | DBFlow Version: 4 | 5 | Bug or Feature Request: 6 | 7 | Description: 8 | 9 | -------------------------------------------------------------------------------- /java-artifacts.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.github.dcendents.android-maven' 2 | 3 | install { 4 | repositories.mavenInstaller { 5 | pom { 6 | project { 7 | packaging bt_packaging 8 | name bt_name 9 | url bt_siteUrl 10 | licenses { 11 | license { 12 | name bt_licenseName 13 | url bt_licenseUrl 14 | } 15 | } 16 | scm { 17 | connection bt_gitUrl 18 | developerConnection bt_gitUrl 19 | url bt_siteUrl 20 | } 21 | } 22 | } 23 | } 24 | } 25 | 26 | task sourcesJar(type: Jar, dependsOn: classes) { 27 | classifier = 'sources' 28 | from sourceSets.main.allSource 29 | } 30 | 31 | task javadocJar(type: Jar, dependsOn: javadoc) { 32 | classifier = 'javadoc' 33 | from javadoc.destinationDir 34 | } 35 | 36 | artifacts { 37 | archives sourcesJar 38 | archives javadocJar 39 | } -------------------------------------------------------------------------------- /kotlin-artifacts.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.github.dcendents.android-maven' 2 | 3 | install { 4 | repositories.mavenInstaller { 5 | pom { 6 | project { 7 | packaging bt_packaging 8 | name bt_name 9 | url bt_siteUrl 10 | licenses { 11 | license { 12 | name bt_licenseName 13 | url bt_licenseUrl 14 | } 15 | } 16 | scm { 17 | connection bt_gitUrl 18 | developerConnection bt_gitUrl 19 | url bt_siteUrl 20 | } 21 | } 22 | } 23 | } 24 | } 25 | 26 | task sourcesJar(type: Jar) { 27 | from "src" 28 | classifier = "sources" 29 | } 30 | 31 | artifacts { 32 | archives sourcesJar 33 | } -------------------------------------------------------------------------------- /lib/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.library") 3 | kotlin("android") 4 | } 5 | // project.ext.artifactId = bt_name 6 | 7 | android { 8 | compileSdkVersion(Versions.TargetSdk) 9 | 10 | defaultConfig { 11 | minSdkVersion(Versions.MinSdk) 12 | targetSdkVersion(Versions.TargetSdk) 13 | } 14 | 15 | lintOptions { 16 | isAbortOnError = false 17 | } 18 | 19 | compileOptions { 20 | sourceCompatibility = JavaVersion.VERSION_1_8 21 | targetCompatibility = JavaVersion.VERSION_1_8 22 | } 23 | 24 | sourceSets { 25 | getByName("main").java.srcDirs("src/main/kotlin") 26 | } 27 | 28 | kotlinOptions { 29 | freeCompilerArgs = listOf("-Xinline-classes") 30 | } 31 | } 32 | 33 | dependencies { 34 | api(project(":core")) 35 | api(Dependencies.AndroidX.Annotations) 36 | } 37 | 38 | apply(from = "../kotlin-artifacts.gradle") 39 | -------------------------------------------------------------------------------- /lib/gradle.properties: -------------------------------------------------------------------------------- 1 | bt_name=dbflow 2 | bt_packaging=aar 3 | bt_artifact_id=dbflow -------------------------------------------------------------------------------- /lib/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = buildName -------------------------------------------------------------------------------- /lib/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/adapter/CreationAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.adapter 2 | 3 | import com.dbflow5.database.DatabaseWrapper 4 | 5 | enum class ObjectType(val value: String) { 6 | View("VIEW"), 7 | Table("TABLE"); 8 | } 9 | 10 | /** 11 | * Description: Provides a set of methods for creating a DB object. 12 | */ 13 | interface CreationAdapter { 14 | /** 15 | * @return The query used to create this table. 16 | */ 17 | val creationQuery: String 18 | 19 | val name: String 20 | 21 | val type: ObjectType 22 | 23 | /** 24 | * @return When false, this table gets generated and associated with database, however it will not immediately 25 | * get created upon startup. This is useful for keeping around legacy tables for migrations. 26 | */ 27 | fun createWithDatabase(): Boolean = true 28 | } 29 | 30 | /** 31 | * Runs the creation query on the DB. 32 | */ 33 | fun CreationAdapter.createIfNotExists(wrapper: DatabaseWrapper) { 34 | wrapper.compileStatement(creationQuery).use { 35 | it.execute() 36 | } 37 | } 38 | 39 | /** 40 | * Drops the table by running a drop query. 41 | */ 42 | fun CreationAdapter.drop(wrapper: DatabaseWrapper, ifExists: Boolean = false) { 43 | wrapper.compileStatement("DROP ${type.value} $name ${if (ifExists) "IF EXISTS" else ""};").use { 44 | it.execute() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/adapter/ModelViewAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.adapter 2 | 3 | import com.dbflow5.config.DBFlowDatabase 4 | 5 | /** 6 | * Description: The base class for a [T] adapter that defines how it interacts with the DB. 7 | */ 8 | abstract class ModelViewAdapter(databaseDefinition: DBFlowDatabase) 9 | : RetrievalAdapter(databaseDefinition), CreationAdapter 10 | 11 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/adapter/QueryModelAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.adapter 2 | 3 | import com.dbflow5.annotation.QueryModel 4 | import com.dbflow5.config.DBFlowDatabase 5 | 6 | /** 7 | * Description: The baseclass for adapters to [QueryModel] that defines how it interacts with the DB. The 8 | * where query is not defined here, rather its determined by the cursor used. 9 | */ 10 | @Deprecated(replaceWith = ReplaceWith("RetrievalAdapter", "com.dbflow5.adapter"), 11 | message = "QueryModelAdapter is now redundant. Use Retrieval Adapter") 12 | abstract class QueryModelAdapter(databaseDefinition: DBFlowDatabase) 13 | : RetrievalAdapter(databaseDefinition) 14 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/adapter/queriable/ListModelLoader.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.adapter.queriable 2 | 3 | import com.dbflow5.database.DatabaseWrapper 4 | import com.dbflow5.database.FlowCursor 5 | 6 | /** 7 | * Description: Loads a [List] of [T]. 8 | */ 9 | open class ListModelLoader(modelClass: Class) 10 | : ModelLoader>(modelClass) { 11 | 12 | override fun convertToData(cursor: FlowCursor, 13 | databaseWrapper: DatabaseWrapper): MutableList { 14 | val retData = arrayListOf() 15 | if (cursor.moveToFirst()) { 16 | do { 17 | retData.add(instanceAdapter.loadFromCursor(cursor, databaseWrapper)) 18 | } while (cursor.moveToNext()) 19 | } 20 | return retData 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/adapter/queriable/ModelLoader.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.adapter.queriable 2 | 3 | import com.dbflow5.adapter.RetrievalAdapter 4 | import com.dbflow5.config.FlowManager 5 | import com.dbflow5.database.DatabaseWrapper 6 | import com.dbflow5.database.FlowCursor 7 | 8 | /** 9 | * Description: Represents how models load from DB. It will query a [DatabaseWrapper] 10 | * and query for a [FlowCursor]. Then the cursor is used to convert itself into an object. 11 | */ 12 | abstract class ModelLoader(val modelClass: Class) { 13 | 14 | protected val instanceAdapter: RetrievalAdapter by lazy { FlowManager.getRetrievalAdapter(modelClass) } 15 | 16 | /** 17 | * Loads the data from a query and returns it as a [TReturn]. 18 | * 19 | * @param databaseWrapper A custom database wrapper object to use. 20 | * @param query The query to call. 21 | * @return The data loaded from the database. 22 | */ 23 | open fun load(databaseWrapper: DatabaseWrapper, query: String): TReturn? = 24 | load(databaseWrapper.rawQuery(query, null), databaseWrapper) 25 | 26 | open fun load(cursor: FlowCursor?, databaseWrapper: DatabaseWrapper): TReturn? { 27 | var data: TReturn? = null 28 | cursor?.use { data = convertToData(it, databaseWrapper) } 29 | return data 30 | } 31 | 32 | /** 33 | * Specify how to convert the [FlowCursor] data into a [TReturn]. Can be null. 34 | * 35 | * @param cursor The cursor resulting from a query passed into [.load] 36 | * @return A new (or reused) instance that represents the [FlowCursor]. 37 | */ 38 | abstract fun convertToData(cursor: FlowCursor, databaseWrapper: DatabaseWrapper): TReturn? 39 | } 40 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/adapter/queriable/SingleKeyCacheableListModelLoader.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.adapter.queriable 2 | 3 | import com.dbflow5.adapter.CacheAdapter 4 | import com.dbflow5.database.DatabaseWrapper 5 | import com.dbflow5.database.FlowCursor 6 | import com.dbflow5.query.cache.addOrReload 7 | 8 | /** 9 | * Description: 10 | */ 11 | class SingleKeyCacheableListModelLoader(tModelClass: Class, 12 | cacheAdapter: CacheAdapter) 13 | : CacheableListModelLoader(tModelClass, cacheAdapter) { 14 | 15 | override fun convertToData(cursor: FlowCursor, databaseWrapper: DatabaseWrapper): MutableList { 16 | val data = arrayListOf() 17 | var cacheValue: Any? 18 | // Ensure that we aren't iterating over this cursor concurrently from different threads 19 | if (cursor.moveToFirst()) { 20 | do { 21 | cacheValue = cacheAdapter.getCachingColumnValueFromCursor(cursor) 22 | val model = modelCache.addOrReload(cacheValue, cacheAdapter, modelAdapter, cursor, databaseWrapper) 23 | data.add(model) 24 | } while (cursor.moveToNext()) 25 | } 26 | return data 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/adapter/queriable/SingleKeyCacheableModelLoader.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.adapter.queriable 2 | 3 | import com.dbflow5.adapter.CacheAdapter 4 | import com.dbflow5.database.DatabaseWrapper 5 | import com.dbflow5.database.FlowCursor 6 | import com.dbflow5.query.cache.addOrReload 7 | import com.dbflow5.structure.Model 8 | 9 | /** 10 | * Description: More optimized version of [CacheableModelLoader] which assumes that the [Model] 11 | * only utilizes a single primary key. 12 | */ 13 | class SingleKeyCacheableModelLoader(modelClass: Class, 14 | cacheAdapter: CacheAdapter) 15 | : CacheableModelLoader(modelClass, cacheAdapter) { 16 | 17 | /** 18 | * Converts data by loading from cache based on its sequence of caching ids. Will reuse the passed 19 | * [T] if it's not found in the cache and non-null. 20 | * 21 | * @return A model from cache. 22 | */ 23 | override fun convertToData(cursor: FlowCursor, moveToFirst: Boolean, databaseWrapper: DatabaseWrapper): T? { 24 | return if (!moveToFirst || cursor.moveToFirst()) { 25 | val value = cacheAdapter.getCachingColumnValueFromCursor(cursor) 26 | modelCache.addOrReload(value, cacheAdapter, modelAdapter, cursor, databaseWrapper) 27 | } else null 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/adapter/queriable/SingleModelLoader.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.adapter.queriable 2 | 3 | import com.dbflow5.database.DatabaseWrapper 4 | import com.dbflow5.database.FlowCursor 5 | 6 | /** 7 | * Description: Responsible for loading data into a single object. 8 | */ 9 | open class SingleModelLoader(modelClass: Class) 10 | : ModelLoader(modelClass) { 11 | 12 | open fun convertToData(cursor: FlowCursor, 13 | moveToFirst: Boolean, 14 | databaseWrapper: DatabaseWrapper): T? = 15 | if (!moveToFirst || cursor.moveToFirst()) { 16 | instanceAdapter.loadFromCursor(cursor, databaseWrapper) 17 | } else null 18 | 19 | override fun convertToData(cursor: FlowCursor, databaseWrapper: DatabaseWrapper): T? { 20 | return convertToData(cursor, true, databaseWrapper) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/database/AndroidDatabaseWrapper.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.database 2 | 3 | import android.content.ContentValues 4 | 5 | /** 6 | * Description: 7 | */ 8 | interface AndroidDatabaseWrapper : DatabaseWrapper { 9 | 10 | 11 | fun updateWithOnConflict(tableName: String, 12 | contentValues: ContentValues, 13 | where: String?, 14 | whereArgs: Array?, conflictAlgorithm: Int): Long 15 | 16 | fun insertWithOnConflict(tableName: String, 17 | nullColumnHack: String?, 18 | values: ContentValues, 19 | sqLiteDatabaseAlgorithmInt: Int): Long 20 | 21 | } -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/database/BaseDatabaseStatement.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.database 2 | 3 | /** 4 | * Description: Default implementation for some [DatabaseStatement] methods. 5 | */ 6 | abstract class BaseDatabaseStatement : DatabaseStatement { 7 | 8 | override fun bindStringOrNull(index: Int, s: String?) { 9 | if (s != null) { 10 | bindString(index, s) 11 | } else { 12 | bindNull(index) 13 | } 14 | } 15 | 16 | override fun bindNumber(index: Int, number: Number?) { 17 | bindNumberOrNull(index, number) 18 | } 19 | 20 | override fun bindNumberOrNull(index: Int, number: Number?) { 21 | if (number != null) { 22 | bindLong(index, number.toLong()) 23 | } else { 24 | bindNull(index) 25 | } 26 | } 27 | 28 | override fun bindDoubleOrNull(index: Int, aDouble: Double?) { 29 | if (aDouble != null) { 30 | bindDouble(index, aDouble) 31 | } else { 32 | bindNull(index) 33 | } 34 | } 35 | 36 | override fun bindFloatOrNull(index: Int, aFloat: Float?) { 37 | if (aFloat != null) { 38 | bindDouble(index, aFloat.toDouble()) 39 | } else { 40 | bindNull(index) 41 | } 42 | } 43 | 44 | override fun bindBlobOrNull(index: Int, bytes: ByteArray?) { 45 | if (bytes != null) { 46 | bindBlob(index, bytes) 47 | } else { 48 | bindNull(index) 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/database/ContentValueExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.database 2 | 3 | import android.content.ContentValues 4 | 5 | operator fun ContentValues.set(key: String, value: String?) = put(key, value) 6 | 7 | operator fun ContentValues.set(key: String, value: Byte?) = put(key, value) 8 | 9 | operator fun ContentValues.set(key: String, value: Short?) = put(key, value) 10 | 11 | operator fun ContentValues.set(key: String, value: Int?) = put(key, value) 12 | 13 | operator fun ContentValues.set(key: String, value: Long?) = put(key, value) 14 | 15 | operator fun ContentValues.set(key: String, value: Float?) = put(key, value) 16 | 17 | operator fun ContentValues.set(key: String, value: Double?) = put(key, value) 18 | 19 | operator fun ContentValues.set(key: String, value: Boolean?) = put(key, value) 20 | 21 | operator fun ContentValues.set(key: String, value: ByteArray?) = put(key, value) 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/database/DatabaseCallback.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.database 2 | 3 | /** 4 | * Description: Provides callbacks for [OpenHelper] methods 5 | */ 6 | interface DatabaseCallback { 7 | 8 | /** 9 | * Called when the DB is opened 10 | * 11 | * @param database The database that is opened 12 | */ 13 | fun onOpen(database: DatabaseWrapper) = Unit 14 | 15 | /** 16 | * Called when the DB is created 17 | * 18 | * @param database The database that is created 19 | */ 20 | fun onCreate(database: DatabaseWrapper) = Unit 21 | 22 | /** 23 | * Called when the DB is upgraded. 24 | * 25 | * @param database The database that is upgraded 26 | * @param oldVersion The previous DB version 27 | * @param newVersion The new DB version 28 | */ 29 | fun onUpgrade(database: DatabaseWrapper, oldVersion: Int, newVersion: Int) = Unit 30 | 31 | /** 32 | * Called when DB is downgraded. Note that this may not be supported by all implementations of the DB. 33 | * 34 | * @param databaseWrapper The database downgraded. 35 | * @param oldVersion The old. higher version. 36 | * @param newVersion The new lower version. 37 | */ 38 | fun onDowngrade(databaseWrapper: DatabaseWrapper, oldVersion: Int, newVersion: Int) = Unit 39 | 40 | /** 41 | * Called when DB connection is being configured. Useful for checking foreign key support or enabling 42 | * write-ahead-logging. 43 | */ 44 | fun onConfigure(db: DatabaseWrapper) = Unit 45 | } 46 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/database/DatabaseStatement.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.database 2 | 3 | import java.io.Closeable 4 | 5 | /** 6 | * Description: Abstracts out an Android SQLiteStatement. 7 | */ 8 | interface DatabaseStatement : Closeable { 9 | 10 | fun executeUpdateDelete(): Long 11 | 12 | fun execute() 13 | 14 | override fun close() 15 | 16 | fun simpleQueryForLong(): Long 17 | 18 | fun simpleQueryForString(): String? 19 | 20 | fun executeInsert(): Long 21 | 22 | fun bindString(index: Int, s: String) 23 | 24 | fun bindStringOrNull(index: Int, s: String?) 25 | 26 | fun bindNull(index: Int) 27 | 28 | fun bindLong(index: Int, aLong: Long) 29 | 30 | fun bindNumber(index: Int, number: Number?) 31 | 32 | fun bindNumberOrNull(index: Int, number: Number?) 33 | 34 | fun bindDouble(index: Int, aDouble: Double) 35 | 36 | fun bindDoubleOrNull(index: Int, aDouble: Double?) 37 | 38 | fun bindFloatOrNull(index: Int, aFloat: Float?) 39 | 40 | fun bindBlob(index: Int, bytes: ByteArray) 41 | 42 | fun bindBlobOrNull(index: Int, bytes: ByteArray?) 43 | 44 | fun bindAllArgsAsStrings(selectionArgs: Array?) 45 | } 46 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/database/MigrationFileHelper.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.database 2 | 3 | /** 4 | * Description: 5 | */ 6 | interface MigrationFileHelper { 7 | 8 | fun getListFiles(dbMigrationPath: String): List 9 | 10 | fun executeMigration(fileName: String, dbFunction: (queryString: String) -> Unit) 11 | } -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/database/OpenHelper.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.database 2 | 3 | interface OpenHelperDelegate { 4 | val database: DatabaseWrapper 5 | 6 | val delegate: DatabaseHelperDelegate? 7 | 8 | val isDatabaseIntegrityOk: Boolean 9 | 10 | fun performRestoreFromBackup() 11 | 12 | fun backupDB() 13 | } 14 | 15 | 16 | /** 17 | * Description: Abstracts out the [DatabaseHelperDelegate] into the one used in this library. 18 | */ 19 | interface OpenHelper : OpenHelperDelegate { 20 | 21 | fun setWriteAheadLoggingEnabled(enabled: Boolean) 22 | 23 | fun setDatabaseListener(callback: DatabaseCallback?) 24 | 25 | fun closeDB() 26 | 27 | fun deleteDB() 28 | } 29 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/database/SQLiteException.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.database 2 | 3 | /** 4 | * Description: DBFlow mirror to an Android SQLiteException. 5 | */ 6 | class SQLiteException : RuntimeException { 7 | constructor() 8 | 9 | constructor(error: String) : super(error) 10 | 11 | constructor(error: String, cause: Throwable) : super(error, cause) 12 | } 13 | 14 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/migration/BaseMigration.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.migration 2 | 3 | import com.dbflow5.database.DatabaseWrapper 4 | 5 | /** 6 | * Description: Provides the base implementation of [Migration] with 7 | * only [Migration.migrate] needing to be implemented. 8 | */ 9 | abstract class BaseMigration : Migration { 10 | 11 | 12 | override fun onPreMigrate() { 13 | 14 | } 15 | 16 | abstract override fun migrate(database: DatabaseWrapper) 17 | 18 | override fun onPostMigrate() { 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/migration/IndexMigration.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.migration 2 | 3 | import com.dbflow5.database.DatabaseWrapper 4 | import com.dbflow5.query.index 5 | import com.dbflow5.query.property.IProperty 6 | import kotlin.reflect.KClass 7 | 8 | /** 9 | * Description: Defines and enables an Index structurally through a migration. 10 | */ 11 | abstract class IndexMigration( 12 | /** 13 | * The table to index on 14 | */ 15 | private var onTable: Class) : BaseMigration() { 16 | 17 | private var unique: Boolean = false 18 | private val columns = arrayListOf>() 19 | 20 | abstract val name: String 21 | 22 | constructor(onTable: KClass) : this(onTable.java) 23 | 24 | override fun migrate(database: DatabaseWrapper) { 25 | val index = index(name, onTable).unique(unique) 26 | columns.forEach { index.and(it) } 27 | database.execSQL(index.query) 28 | } 29 | 30 | /** 31 | * Adds a column to the underlying INDEX 32 | * 33 | * @param property The name of the column to add to the Index 34 | * @return This migration 35 | */ 36 | fun addColumn(property: IProperty<*>) = apply { 37 | columns.add(property) 38 | } 39 | 40 | /** 41 | * Sets the INDEX to UNIQUE 42 | * 43 | * @return This migration. 44 | */ 45 | fun unique() = apply { 46 | unique = true 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/migration/IndexPropertyMigration.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.migration 2 | 3 | import com.dbflow5.database.DatabaseWrapper 4 | import com.dbflow5.query.property.IndexProperty 5 | 6 | /** 7 | * Description: Allows you to specify if and when an [IndexProperty] gets used or created. 8 | */ 9 | abstract class IndexPropertyMigration( 10 | /** 11 | * @return true if create the index, false to drop the index. 12 | */ 13 | open val shouldCreate: Boolean = true) : BaseMigration() { 14 | 15 | abstract val indexProperty: IndexProperty<*> 16 | 17 | override fun migrate(database: DatabaseWrapper) { 18 | if (shouldCreate) { 19 | indexProperty.createIfNotExists(database) 20 | } else { 21 | indexProperty.drop(database) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/migration/Migration.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.migration 2 | 3 | import com.dbflow5.database.DatabaseWrapper 4 | 5 | /** 6 | * Description: Called when the Database is migrating. We can perform custom migrations here. A [com.dbflow5.annotation.Migration] 7 | * is required for registering this class to automatically be called in an upgrade of the DB. 8 | */ 9 | interface Migration { 10 | 11 | /** 12 | * Called before we migrate data. Instantiate migration data before releasing it in [.onPostMigrate] 13 | */ 14 | fun onPreMigrate() 15 | 16 | /** 17 | * Perform your migrations here 18 | * 19 | * @param database The database to operate on 20 | */ 21 | fun migrate(database: DatabaseWrapper) 22 | 23 | /** 24 | * Called after the migration completes. Release migration data here. 25 | */ 26 | fun onPostMigrate() 27 | } 28 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/observing/OnTableChangedObserver.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.observing 2 | 3 | /** 4 | * Description: 5 | */ 6 | abstract class OnTableChangedObserver(internal val tables: List>) { 7 | 8 | /** 9 | * Called when a table or set of tables are invalidated in the DB. 10 | */ 11 | abstract fun onChanged(tables: Set>) 12 | 13 | } 14 | 15 | class OnTableChangedObserverWithIds(internal val observer: OnTableChangedObserver, 16 | internal val tableIds: IntArray) { 17 | 18 | private var singleTableSet: MutableSet>? = when { 19 | tableIds.size == 1 -> mutableSetOf(observer.tables[0]) 20 | else -> null 21 | } 22 | 23 | internal fun notifyTables(invalidationStatus: BooleanArray) { 24 | var invalidatedTables: MutableSet>? = null 25 | tableIds.forEachIndexed { index, tableId -> 26 | if (invalidationStatus[tableId]) { 27 | val singleTableSet = singleTableSet 28 | if (singleTableSet != null) { 29 | invalidatedTables = singleTableSet 30 | } else { 31 | if (invalidatedTables == null) { 32 | invalidatedTables = mutableSetOf() 33 | } 34 | invalidatedTables!!.add(observer.tables[index]) 35 | } 36 | } 37 | } 38 | invalidatedTables?.let { observer.onChanged(it) } 39 | } 40 | } -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/query/Actionable.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query 2 | 3 | import com.dbflow5.structure.ChangeAction 4 | 5 | /** 6 | * Description: Provides [Action] for SQL constructs. 7 | */ 8 | interface Actionable { 9 | 10 | val primaryAction: ChangeAction 11 | } 12 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/query/CompletedTrigger.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query 2 | 3 | import com.dbflow5.database.DatabaseWrapper 4 | import com.dbflow5.dropTrigger 5 | import com.dbflow5.sql.Query 6 | 7 | /** 8 | * Description: The last piece of a TRIGGER statement, this class contains the BEGIN...END and the logic in between. 9 | */ 10 | class CompletedTrigger internal constructor( 11 | /** 12 | * The first pieces of this TRIGGER statement 13 | */ 14 | private val triggerMethod: TriggerMethod, triggerLogicQuery: Query) : Query { 15 | 16 | /** 17 | * The query to run between the BEGIN and END of this statement 18 | */ 19 | private val triggerLogicQuery = arrayListOf() 20 | 21 | override val query: String 22 | get() = 23 | "${triggerMethod.query}\nBEGIN\n${triggerLogicQuery.joinToString(separator = ";\n")};\nEND" 24 | 25 | init { 26 | this.triggerLogicQuery.add(triggerLogicQuery) 27 | } 28 | 29 | /** 30 | * Appends the nextStatement to this query as another line to be executed by trigger. 31 | */ 32 | infix fun and(nextStatement: Query) = apply { 33 | this.triggerLogicQuery.add(nextStatement) 34 | } 35 | 36 | 37 | /** 38 | * Turns on this trigger 39 | */ 40 | fun enable(databaseWrapper: DatabaseWrapper) { 41 | databaseWrapper.execSQL(query) 42 | } 43 | 44 | /** 45 | * Disables this trigger 46 | */ 47 | fun disable(databaseWrapper: DatabaseWrapper) { 48 | dropTrigger(databaseWrapper, triggerMethod.trigger.name) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/query/ContentValuesListener.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query 2 | 3 | import android.content.ContentValues 4 | import com.dbflow5.adapter.ModelAdapter 5 | import com.dbflow5.annotation.Table 6 | import com.dbflow5.structure.Model 7 | 8 | /** 9 | * Description: Called after the declared [ContentValues] are binded. It enables 10 | * us to listen and add custom behavior to the [ContentValues]. These must be 11 | * defined in a [Model] class to register properly. 12 | * 13 | * 14 | * This class will no longer get called during updates unless explicit call to 15 | * [ModelAdapter.bindToContentValues] 16 | * or [ModelAdapter.bindToInsertValues] with setting [Table.generateContentValues] to true. 17 | * 18 | * @see SQLiteStatementListener 19 | */ 20 | @Deprecated("") 21 | interface ContentValuesListener { 22 | 23 | /** 24 | * Called during an [Model.update] and at the end of 25 | * [ModelAdapter.bindToContentValues] 26 | * . It enables you to customly change the values as necessary during update to the database. 27 | * 28 | * @param contentValues The content values to bind to for an update. 29 | */ 30 | fun onBindToContentValues(contentValues: ContentValues) 31 | 32 | /** 33 | * Called during an [Model.update] and at the end of 34 | * [ModelAdapter.bindToInsertValues]. 35 | * It enables you to customly change the values as necessary during insert 36 | * to the database for a [ContentProvider]. 37 | * 38 | * @param contentValues The content values to insert into DB for a ContentProvider 39 | */ 40 | fun onBindToInsertValues(contentValues: ContentValues) 41 | } 42 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/query/Delete.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query 2 | 3 | import com.dbflow5.sql.Query 4 | import kotlin.reflect.KClass 5 | 6 | /** 7 | * Description: Constructs the beginning of a SQL DELETE query 8 | */ 9 | class Delete internal constructor() : Query { 10 | 11 | override val query: String 12 | get() = "DELETE " 13 | 14 | /** 15 | * Returns the new SQL FROM statement wrapper 16 | * 17 | * @param table The table we want to run this query from 18 | * @param [T] The table class 19 | * @return [T] 20 | **/ 21 | infix fun from(table: Class): From = From(this, table) 22 | 23 | infix fun from(table: KClass): From = from(table.java) 24 | 25 | } 26 | 27 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/query/ExistenceOperator.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query 2 | 3 | import com.dbflow5.appendQualifier 4 | import com.dbflow5.sql.Query 5 | 6 | /** 7 | * Description: The condition that represents EXISTS in a SQL statement. 8 | */ 9 | class ExistenceOperator(private val innerWhere: Where<*>) : SQLOperator, Query { 10 | 11 | override val query: String 12 | get() = appendToQuery() 13 | 14 | override fun appendConditionToQuery(queryBuilder: StringBuilder) { 15 | queryBuilder.appendQualifier("EXISTS", innerWhere.enclosedQuery) 16 | } 17 | 18 | override fun columnName(): String { 19 | throw RuntimeException("Method not valid for ExistenceOperator") 20 | } 21 | 22 | override fun separator(): String? { 23 | throw RuntimeException("Method not valid for ExistenceOperator") 24 | } 25 | 26 | override fun separator(separator: String): SQLOperator { 27 | // not used. 28 | throw RuntimeException("Method not valid for ExistenceOperator") 29 | } 30 | 31 | override fun hasSeparator(): Boolean = false 32 | 33 | override fun operation(): String = "" 34 | 35 | override fun value(): Any? = innerWhere 36 | 37 | } 38 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/query/IndexedBy.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query 2 | 3 | import com.dbflow5.query.property.IndexProperty 4 | import com.dbflow5.quoteIfNeeded 5 | import com.dbflow5.sql.Query 6 | import com.dbflow5.structure.ChangeAction 7 | 8 | /** 9 | * Description: The INDEXED BY part of a SELECT/UPDATE/DELETE 10 | */ 11 | class IndexedBy 12 | /** 13 | * Creates the INDEXED BY part of the clause. 14 | * 15 | * @param indexProperty The index property generated. 16 | * @param whereBase The base piece of this query 17 | */ 18 | (private val indexProperty: IndexProperty, 19 | private val whereBase: WhereBase) 20 | : BaseTransformable(whereBase.table) { 21 | 22 | override val queryBuilderBase: Query 23 | get() = whereBase.queryBuilderBase 24 | 25 | override val query: String 26 | get() = buildString { 27 | append(whereBase.query) 28 | append(" INDEXED BY ") 29 | append(indexProperty.indexName.quoteIfNeeded()) 30 | append(" ") 31 | } 32 | 33 | override val primaryAction: ChangeAction 34 | get() = whereBase.primaryAction 35 | 36 | override fun cloneSelf(): IndexedBy = IndexedBy(indexProperty, whereBase.cloneSelf()) 37 | } 38 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/query/LoadFromCursorListener.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query 2 | 3 | import com.dbflow5.database.FlowCursor 4 | import com.dbflow5.structure.Model 5 | 6 | /** 7 | * Description: Marks a [Model] as listening to [FlowCursor] 8 | * events for custom handling when loading from the DB. 9 | */ 10 | interface LoadFromCursorListener { 11 | 12 | /** 13 | * Called when the [Model] is loaded from the DB. 14 | * 15 | * @param cursor The cursor that is loaded. 16 | */ 17 | fun onLoadFromCursor(cursor: FlowCursor) 18 | } 19 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/query/SQLOperator.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query 2 | 3 | /** 4 | * Description: Basic interface for all of the Operator classes. 5 | */ 6 | interface SQLOperator { 7 | 8 | /** 9 | * Appends itself to the [StringBuilder] 10 | * 11 | * @param queryBuilder The builder to append to. 12 | */ 13 | fun appendConditionToQuery(queryBuilder: StringBuilder) 14 | 15 | /** 16 | * The name of the column. 17 | * 18 | * @return The column name. 19 | */ 20 | fun columnName(): String 21 | 22 | /** 23 | * The separator for this condition when paired with a [OperatorGroup] 24 | * 25 | * @return The separator, an AND, OR, or other kinds. 26 | */ 27 | fun separator(): String? 28 | 29 | /** 30 | * Sets the separator for this condition 31 | * 32 | * @param separator The string AND, OR, or something else. 33 | * @return This instance. 34 | */ 35 | fun separator(separator: String): SQLOperator 36 | 37 | /** 38 | * @return true if it has a separator, false if not. 39 | */ 40 | fun hasSeparator(): Boolean 41 | 42 | /** 43 | * @return the operation that is used. 44 | */ 45 | fun operation(): String 46 | 47 | /** 48 | * @return The raw value of the condition. 49 | */ 50 | fun value(): Any? 51 | 52 | } 53 | 54 | fun SQLOperator.appendToQuery(): String { 55 | val queryBuilder = StringBuilder() 56 | appendConditionToQuery(queryBuilder) 57 | return queryBuilder.toString() 58 | } -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/query/SQLiteStatementListener.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query 2 | 3 | import com.dbflow5.adapter.InternalAdapter 4 | import com.dbflow5.adapter.ModelAdapter 5 | import com.dbflow5.database.DatabaseStatement 6 | import com.dbflow5.structure.Model 7 | 8 | /** 9 | * Description: Marks a [Model] as subscribing to the [DatabaseStatement] 10 | * that is used to [Model.insert] a model into the DB. 11 | */ 12 | interface SQLiteStatementListener { 13 | 14 | /** 15 | * Called at the end of [InternalAdapter.bindToInsertStatement] 16 | * Perform a custom manipulation of the statement as willed. 17 | * 18 | * @param databaseStatement The insert statement from the [ModelAdapter] 19 | */ 20 | fun onBindToInsertStatement(databaseStatement: DatabaseStatement) 21 | 22 | /** 23 | * Called at the end of [InternalAdapter.bindToUpdateStatement] 24 | * Perform a custom manipulation of the statement as willed. 25 | * 26 | * @param databaseStatement The insert statement from the [ModelAdapter] 27 | */ 28 | fun onBindToUpdateStatement(databaseStatement: DatabaseStatement) 29 | 30 | fun onBindToDeleteStatement(databaseStatement: DatabaseStatement) 31 | } 32 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/query/Set.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query 2 | 3 | import android.content.ContentValues 4 | import com.dbflow5.addContentValues 5 | import com.dbflow5.sql.Query 6 | import com.dbflow5.structure.ChangeAction 7 | 8 | /** 9 | * Description: Used to specify the SET part of an [com.dbflow5.query.Update] query. 10 | */ 11 | class Set internal constructor( 12 | override val queryBuilderBase: Query, table: Class) 13 | : BaseTransformable(table), WhereBase { 14 | 15 | private val operatorGroup: OperatorGroup = OperatorGroup.nonGroupingClause().setAllCommaSeparated(true) 16 | 17 | override val query: String 18 | get() = " ${queryBuilderBase.query}SET ${operatorGroup.query} " 19 | 20 | override val primaryAction: ChangeAction 21 | get() = ChangeAction.UPDATE 22 | 23 | /** 24 | * Specifies a varg of conditions to append to this SET 25 | * 26 | * @param conditions The varg of conditions 27 | * @return This instance. 28 | */ 29 | fun conditions(vararg conditions: SQLOperator) = apply { 30 | operatorGroup.andAll(*conditions) 31 | } 32 | 33 | /** 34 | * Specifies a varg of conditions to append to this SET 35 | * 36 | * @param condition The varg of conditions 37 | * @return This instance. 38 | */ 39 | infix fun and(condition: SQLOperator) = apply { 40 | operatorGroup.and(condition) 41 | } 42 | 43 | fun conditionValues(contentValues: ContentValues) = apply { 44 | addContentValues(contentValues, operatorGroup) 45 | } 46 | 47 | override fun cloneSelf(): Set { 48 | val set = Set( 49 | when (queryBuilderBase) { 50 | is Update<*> -> queryBuilderBase.cloneSelf() 51 | else -> queryBuilderBase 52 | }, table) 53 | set.operatorGroup.andAll(operatorGroup.conditions) 54 | return set 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/query/Transformable.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("TransformableUtils") 2 | 3 | package com.dbflow5.query 4 | 5 | import com.dbflow5.query.property.IProperty 6 | import com.dbflow5.sql.QueryCloneable 7 | 8 | /** 9 | * Description: Provides a standard set of methods for ending a SQLite query method. These include 10 | * groupby, orderby, having, limit and offset. 11 | */ 12 | interface Transformable { 13 | 14 | fun groupBy(vararg nameAliases: NameAlias): Where 15 | 16 | fun groupBy(vararg properties: IProperty<*>): Where 17 | 18 | fun orderBy(nameAlias: NameAlias, ascending: Boolean = true): Where 19 | 20 | fun orderBy(property: IProperty<*>, ascending: Boolean = true): Where 21 | 22 | infix fun orderBy(orderBy: OrderBy): Where 23 | 24 | infix fun limit(count: Long): Where 25 | 26 | infix fun offset(offset: Long): Where 27 | 28 | fun having(vararg conditions: SQLOperator): Where 29 | 30 | fun orderByAll(orderByList: List): Where 31 | 32 | /** 33 | * Constrains the given [Transformable] by the [offset] and [limit] specified. It copies over itself 34 | * into a new instance to not preserve changes. 35 | */ 36 | fun constrain(offset: Long, limit: Long): ModelQueriable { 37 | var tr: Transformable = this 38 | @Suppress("UNCHECKED_CAST") 39 | if (tr is QueryCloneable<*>) { 40 | tr = tr.cloneSelf() as Transformable 41 | } 42 | return tr.offset(offset).limit(limit) 43 | } 44 | } 45 | 46 | infix fun Transformable.groupBy(nameAlias: NameAlias): Where = groupBy(nameAlias) 47 | 48 | infix fun Transformable.groupBy(property: IProperty<*>): Where = groupBy(property) 49 | 50 | infix fun Transformable.having(sqlOperator: SQLOperator): Where = having(sqlOperator) -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/query/UnSafeStringOperator.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query 2 | 3 | import com.dbflow5.isNotNullOrEmpty 4 | import com.dbflow5.sql.Query 5 | 6 | /** 7 | * Description: This class will use a String to describe its condition. 8 | * Not recommended for normal queries, but can be used as a fall-back. 9 | */ 10 | class UnSafeStringOperator(selection: String, selectionArgs: Array) : SQLOperator, Query { 11 | 12 | private val conditionString: String? 13 | private var separator = "" 14 | 15 | override val query: String 16 | get() = appendToQuery() 17 | 18 | init { 19 | var newSelection: String? = selection 20 | // replace question marks in order 21 | if (newSelection != null) { 22 | for (selectionArg in selectionArgs) { 23 | newSelection = newSelection?.replaceFirst("\\?".toRegex(), selectionArg) 24 | } 25 | } 26 | this.conditionString = newSelection 27 | } 28 | 29 | override fun appendConditionToQuery(queryBuilder: StringBuilder) { 30 | queryBuilder.append(conditionString) 31 | } 32 | 33 | override fun columnName(): String = "" 34 | 35 | override fun separator(): String? = separator 36 | 37 | override fun separator(separator: String) = apply { 38 | this.separator = separator 39 | } 40 | 41 | override fun hasSeparator(): Boolean = separator.isNotNullOrEmpty() 42 | 43 | override fun operation(): String = "" 44 | 45 | override fun value(): Any? = "" 46 | } -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/query/WhereBase.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query 2 | 3 | import com.dbflow5.sql.Query 4 | import com.dbflow5.sql.QueryCloneable 5 | 6 | /** 7 | * Description: The base for a [Where] statement. 8 | */ 9 | interface WhereBase : Query, Actionable, QueryCloneable> { 10 | 11 | /** 12 | * @return The table of this query. 13 | */ 14 | val table: Class 15 | 16 | /** 17 | * @return The base Query object. 18 | */ 19 | val queryBuilderBase: Query 20 | 21 | } 22 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/query/cache/MultiKeyCacheConverter.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query.cache 2 | 3 | import com.dbflow5.structure.Model 4 | 5 | /** 6 | * Description: This interface allows for [Model] to have multiple primary keys in a cache. This 7 | * interface "zips" the complex primary keys into one "representative" key. Also this can be used to 8 | * override the default caching key and provide a custom key. 9 | */ 10 | fun interface MultiKeyCacheConverter { 11 | 12 | /** 13 | * Converts the array of values into a singular representative key. The values are in order 14 | * of the primary key declaration and are the same length. 15 | * 16 | * @param values The values to convert into a singular key. 17 | * @return The non-null 18 | */ 19 | fun getCachingKey(values: Array): CacheKeyType 20 | } 21 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/query/cache/SimpleMapCache.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query.cache 2 | 3 | import com.dbflow5.config.FlowLog 4 | import com.dbflow5.structure.Model 5 | import java.util.HashMap 6 | 7 | /** 8 | * Description: A simple implementation that keeps [Model] you interact with in memory. 9 | */ 10 | class SimpleMapCache : ModelCache> { 11 | 12 | /** 13 | * Constructs new instance with a [HashMap] with the specified capacity. 14 | * 15 | * @param capacity The capacity to use on the hashmap. 16 | */ 17 | constructor(capacity: Int) : super(HashMap(capacity)) 18 | 19 | /** 20 | * Constructs new instance with a cache 21 | * 22 | * @param cache The arbitrary underlying cache class. 23 | */ 24 | constructor(cache: MutableMap) : super(cache) 25 | 26 | override fun addModel(id: Any?, model: TModel) { 27 | cache.put(id, model) 28 | } 29 | 30 | override fun removeModel(id: Any): TModel? = cache.remove(id) 31 | 32 | override fun clear() { 33 | cache.clear() 34 | } 35 | 36 | override fun get(id: Any?): TModel? = cache[id] 37 | 38 | override fun setCacheSize(size: Int) { 39 | FlowLog.log(FlowLog.Level.W, "The cache size for SimpleMapCache is not re-configurable.") 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/query/list/IFlowCursorIterator.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query.list 2 | 3 | import com.dbflow5.database.FlowCursor 4 | import java.io.Closeable 5 | import java.io.IOException 6 | 7 | /** 8 | * Description: Simple interface that allows you to iterate a [FlowCursor]. 9 | */ 10 | interface IFlowCursorIterator : Closeable, Iterable { 11 | 12 | /** 13 | * @return Count of the [FlowCursor]. 14 | */ 15 | val count: Long 16 | 17 | /** 18 | * @param index The index within the [FlowCursor] to retrieve and convert into a [T] 19 | */ 20 | operator fun get(index: Long): T 21 | 22 | /** 23 | * @param index The index within the [FlowCursor] to retrieve and convert into a [T] 24 | */ 25 | operator fun get(index: Int): T = get(index.toLong()) 26 | 27 | /** 28 | * @return The cursor. 29 | */ 30 | val cursor: FlowCursor? 31 | 32 | /** 33 | * If true, we are tracking a passed cursor. If not, we are using new cursor constructed within this class. 34 | */ 35 | val trackingCursor: Boolean 36 | 37 | /** 38 | * If true, [FlowCursor] is closed and this object should be discarded. 39 | */ 40 | val isClosed: Boolean 41 | 42 | override fun iterator(): FlowCursorIterator 43 | 44 | /** 45 | * @return Can iterate the [FlowCursor]. Specifies a starting location + count limit of results. 46 | */ 47 | fun iterator(startingLocation: Long, limit: Long): FlowCursorIterator 48 | 49 | @Throws(IOException::class) 50 | override fun close() 51 | } -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/query/property/IndexProperty.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query.property 2 | 3 | import com.dbflow5.annotation.Table 4 | import com.dbflow5.database.DatabaseWrapper 5 | import com.dbflow5.query.Index 6 | import com.dbflow5.quoteIfNeeded 7 | 8 | /** 9 | * Description: Defines an INDEX in Sqlite. It basically speeds up data retrieval over large datasets. 10 | * It gets generated from [Table.indexGroups], but also can be manually constructed. These are activated 11 | * and deactivated manually. 12 | */ 13 | class IndexProperty(indexName: String, 14 | private val unique: Boolean, 15 | private val table: Class, 16 | vararg properties: IProperty<*>) { 17 | 18 | @Suppress("UNCHECKED_CAST") 19 | private val properties: Array> = properties as Array> 20 | 21 | val index: Index 22 | get() = Index(indexName, table).on(*properties).unique(unique) 23 | 24 | val indexName = indexName.quoteIfNeeded() ?: "" 25 | 26 | fun createIfNotExists(wrapper: DatabaseWrapper) = index.createIfNotExists(wrapper) 27 | 28 | fun drop(wrapper: DatabaseWrapper) = index.drop(wrapper) 29 | } 30 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/query/property/WrapperProperty.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query.property 2 | 3 | import com.dbflow5.config.FlowManager 4 | import com.dbflow5.query.NameAlias 5 | 6 | /** 7 | * Description: Provides convenience for types that are represented in different ways in the DB. 8 | * 9 | * @author Andrew Grosner (fuzz) 10 | */ 11 | class WrapperProperty : Property { 12 | 13 | private var databaseProperty: WrapperProperty? = null 14 | 15 | override val table: Class<*> 16 | get() = super.table!! 17 | 18 | constructor(table: Class<*>, nameAlias: NameAlias) : super(table, nameAlias) 19 | 20 | constructor(table: Class<*>, columnName: String) : super(table, columnName) 21 | 22 | override fun withTable(): WrapperProperty { 23 | val nameAlias = this.nameAlias 24 | .newBuilder() 25 | .withTable(FlowManager.getTableName(table)) 26 | .build() 27 | return WrapperProperty(this.table, nameAlias) 28 | } 29 | 30 | override fun withTable(tableNameAlias: NameAlias): WrapperProperty { 31 | val nameAlias = this.nameAlias 32 | .newBuilder() 33 | .withTable(tableNameAlias.tableName) 34 | .build() 35 | return WrapperProperty(this.table, nameAlias) 36 | } 37 | 38 | /** 39 | * @return A new [Property] that corresponds to the inverted type of the [WrapperProperty]. Convenience 40 | * for types that have different DB representations. 41 | */ 42 | fun invertProperty(): WrapperProperty = databaseProperty 43 | ?: WrapperProperty(table, nameAlias).also { databaseProperty = it } 44 | } 45 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/runtime/ModelNotifier.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.runtime 2 | 3 | import com.dbflow5.adapter.ModelAdapter 4 | import com.dbflow5.structure.ChangeAction 5 | 6 | /** 7 | * Interface for defining how we notify model changes. 8 | */ 9 | interface ModelNotifier { 10 | 11 | fun notifyModelChanged(model: T, adapter: ModelAdapter, action: ChangeAction) 12 | 13 | fun notifyTableChanged(table: Class, action: ChangeAction) 14 | 15 | fun newRegister(): TableNotifierRegister 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/runtime/NotifyDistributor.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.runtime 2 | 3 | import com.dbflow5.adapter.ModelAdapter 4 | import com.dbflow5.config.FlowManager 5 | import com.dbflow5.structure.ChangeAction 6 | 7 | /** 8 | * Description: Distributes notifications to the [ModelNotifier]. 9 | */ 10 | class NotifyDistributor : ModelNotifier { 11 | 12 | override fun newRegister(): TableNotifierRegister { 13 | throw RuntimeException("Cannot create a register from the distributor class") 14 | } 15 | 16 | override fun notifyModelChanged(model: T, 17 | adapter: ModelAdapter, 18 | action: ChangeAction) { 19 | FlowManager.getModelNotifierForTable(adapter.table) 20 | .notifyModelChanged(model, adapter, action) 21 | } 22 | 23 | /** 24 | * Notifies listeners of table-level changes from the SQLite-wrapper language. 25 | */ 26 | override fun notifyTableChanged(table: Class, 27 | action: ChangeAction) { 28 | FlowManager.getModelNotifierForTable(table).notifyTableChanged(table, action) 29 | } 30 | 31 | companion object { 32 | 33 | private val distributor by lazy { NotifyDistributor() } 34 | 35 | @JvmStatic 36 | fun get(): NotifyDistributor = distributor 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/runtime/OnTableChangedListener.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.runtime 2 | 3 | import com.dbflow5.structure.ChangeAction 4 | 5 | /** 6 | * Interface for when a generic change on a table occurs. 7 | */ 8 | interface OnTableChangedListener { 9 | 10 | /** 11 | * Called when table changes. 12 | * 13 | * @param table The table that has changed. NULL unless version of app is JellyBean. 14 | * or higher. 15 | * @param action The action that occurred. 16 | */ 17 | fun onTableChanged(table: Class<*>?, action: ChangeAction) 18 | } 19 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/runtime/TableNotifierRegister.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.runtime 2 | 3 | import com.dbflow5.structure.ChangeAction 4 | 5 | /** 6 | * Description: Defines how [ModelNotifier] registers listeners. Abstracts that away. 7 | */ 8 | interface TableNotifierRegister { 9 | 10 | val isSubscribed: Boolean 11 | 12 | fun register(tClass: Class) 13 | 14 | fun unregister(tClass: Class) 15 | 16 | fun unregisterAll() 17 | 18 | fun setListener(listener: OnTableChangedListener?) 19 | 20 | 21 | } 22 | 23 | inline fun TableNotifierRegister.setListener(crossinline listener: (Class<*>?, ChangeAction) -> Unit) = 24 | setListener(object : OnTableChangedListener { 25 | override fun onTableChanged(table: Class<*>?, action: ChangeAction) = listener(table, action) 26 | }) 27 | 28 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/structure/Action.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.structure 2 | 3 | /** 4 | * Specifies the Action that was taken when data changes 5 | */ 6 | enum class ChangeAction { 7 | 8 | INSERT, 9 | 10 | UPDATE, 11 | 12 | DELETE, 13 | 14 | /** 15 | * The model was changed. used in prior to Android JellyBean and in generic change 16 | * actions like [com.dbflow5.query.StringQuery] 17 | */ 18 | CHANGE 19 | } -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/structure/BaseModel.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.structure 2 | 3 | import com.dbflow5.adapter.ModelAdapter 4 | import com.dbflow5.annotation.ColumnIgnore 5 | import com.dbflow5.config.FlowManager 6 | import com.dbflow5.config.modelAdapter 7 | import com.dbflow5.database.DatabaseWrapper 8 | 9 | /** 10 | * Description: The base implementation of [Model]. It is recommended to use this class as 11 | * the base for your [Model], but it is not required. 12 | */ 13 | open class BaseModel : Model { 14 | 15 | /** 16 | * @return The associated [ModelAdapter]. The [FlowManager] 17 | * may throw a [InvalidDBConfiguration] for this call if this class 18 | * is not associated with a table, so be careful when using this method. 19 | */ 20 | @delegate:ColumnIgnore 21 | @delegate:Transient 22 | val modelAdapter: ModelAdapter by lazy { javaClass.modelAdapter } 23 | 24 | @Suppress("UNCHECKED_CAST") 25 | override fun load(wrapper: DatabaseWrapper): T? = modelAdapter.load(this, wrapper) as T? 26 | 27 | override fun save(wrapper: DatabaseWrapper): Boolean = modelAdapter.save(this, wrapper) 28 | 29 | override fun delete(wrapper: DatabaseWrapper): Boolean = modelAdapter.delete(this, wrapper) 30 | 31 | override fun update(wrapper: DatabaseWrapper): Boolean = modelAdapter.update(this, wrapper) 32 | 33 | override fun insert(wrapper: DatabaseWrapper): Long = modelAdapter.insert(this, wrapper) 34 | 35 | override fun exists(wrapper: DatabaseWrapper): Boolean = modelAdapter.exists(this, wrapper) 36 | } 37 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/structure/BaseModelView.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.structure 2 | 3 | import com.dbflow5.annotation.ModelView 4 | import com.dbflow5.annotation.ModelViewQuery 5 | 6 | /** 7 | * Description: Provides a base implementation for a ModelView. Use a [ModelView] 8 | * annotation to register it properly. Also you need to specify a singular 9 | * field via [ModelViewQuery]. 10 | */ 11 | abstract class BaseModelView : NoModificationModel() 12 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/structure/BaseQueryModel.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.structure 2 | 3 | import com.dbflow5.annotation.QueryModel 4 | import com.dbflow5.database.DatabaseWrapper 5 | 6 | /** 7 | * Description: Provides a base class for objects that represent [QueryModel]. 8 | */ 9 | class BaseQueryModel : NoModificationModel() { 10 | 11 | override fun exists(wrapper: DatabaseWrapper): Boolean { 12 | throw InvalidSqlViewOperationException("Query ${wrapper.javaClass.name} does not exist as a table." + 13 | "It's a convenient representation of a complex SQLite cursor.") 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/structure/InvalidDBConfiguration.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.structure 2 | 3 | /** 4 | * Description: Thrown when a DB is incorrectly configured. 5 | */ 6 | class InvalidDBConfiguration(message: String) : RuntimeException(message) 7 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/structure/NoModificationModel.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.structure 2 | 3 | import com.dbflow5.adapter.RetrievalAdapter 4 | import com.dbflow5.config.FlowManager 5 | import com.dbflow5.database.DatabaseWrapper 6 | 7 | /** 8 | * Description: A convenience class for [ReadOnlyModel]. 9 | */ 10 | abstract class NoModificationModel : ReadOnlyModel { 11 | 12 | @delegate:Transient 13 | private val retrievalAdapter: RetrievalAdapter by lazy { FlowManager.getRetrievalAdapter(javaClass) } 14 | 15 | override fun exists(wrapper: DatabaseWrapper): Boolean = retrievalAdapter.exists(this, wrapper) 16 | 17 | @Suppress("UNCHECKED_CAST") 18 | override fun load(wrapper: DatabaseWrapper): T? = retrievalAdapter.load(this, wrapper) as T? 19 | 20 | /** 21 | * Gets thrown when an operation is not valid for the SQL View 22 | */ 23 | internal class InvalidSqlViewOperationException(detailMessage: String) : RuntimeException(detailMessage) 24 | } 25 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/structure/OneToMany.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.structure 2 | 3 | import com.dbflow5.config.FlowManager 4 | import com.dbflow5.query.ModelQueriable 5 | import kotlin.properties.ReadWriteProperty 6 | import kotlin.reflect.KProperty 7 | 8 | /** 9 | * Description: 10 | */ 11 | fun oneToMany(query: () -> ModelQueriable) = OneToMany(query) 12 | 13 | /** 14 | * Description: Wraps a [OneToMany] annotation getter into a concise property setter. 15 | */ 16 | class OneToMany(private val query: () -> ModelQueriable) : ReadWriteProperty?> { 17 | 18 | private var list: List? = null 19 | 20 | override fun getValue(thisRef: Any, property: KProperty<*>): List? { 21 | if (list?.isEmpty() != false) { 22 | list = query().queryList(FlowManager.getDatabaseForTable(thisRef::class.java)) 23 | } 24 | return list 25 | } 26 | 27 | override fun setValue(thisRef: Any, property: KProperty<*>, value: List?) { 28 | list = value 29 | } 30 | } -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/structure/ReadOnlyModel.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.structure 2 | 3 | import com.dbflow5.database.DatabaseWrapper 4 | 5 | interface ReadOnlyModel { 6 | 7 | /** 8 | * Loads from the database the most recent version of the model based on it's primary keys. 9 | */ 10 | fun load(wrapper: DatabaseWrapper): T? 11 | 12 | /** 13 | * @return true if this object exists in the DB. It combines all of it's primary key fields 14 | * into a SELECT query and checks to see if any results occur. 15 | */ 16 | fun exists(wrapper: DatabaseWrapper): Boolean 17 | 18 | } 19 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/transaction/BaseTransactionManager.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.transaction 2 | 3 | import com.dbflow5.config.DBFlowDatabase 4 | import com.dbflow5.config.FlowLog 5 | import com.dbflow5.runtime.DBBatchSaveQueue 6 | 7 | /** 8 | * Description: The base implementation of Transaction manager. 9 | */ 10 | abstract class BaseTransactionManager(val queue: ITransactionQueue, 11 | databaseDefinition: DBFlowDatabase) { 12 | 13 | private val _saveQueue: DBBatchSaveQueue = DBBatchSaveQueue(databaseDefinition) 14 | 15 | init { 16 | checkQueue() 17 | } 18 | 19 | val saveQueue: DBBatchSaveQueue 20 | get() { 21 | try { 22 | if (!_saveQueue.isAlive) { 23 | _saveQueue.start() 24 | } 25 | } catch (i: IllegalThreadStateException) { 26 | FlowLog.logError(i) // if queue is alive, will throw error. might occur in multithreading. 27 | } 28 | 29 | return _saveQueue 30 | } 31 | 32 | /** 33 | * Checks if queue is running. If not, should be started here. 34 | */ 35 | fun checkQueue() = queue.startIfNotAlive() 36 | 37 | /** 38 | * Stops the queue this manager contains. 39 | */ 40 | fun stopQueue() = queue.quit() 41 | 42 | /** 43 | * Adds a transaction to the [ITransactionQueue]. 44 | * 45 | * @param transaction The transaction to add. 46 | */ 47 | fun addTransaction(transaction: Transaction) = queue.add(transaction) 48 | 49 | /** 50 | * Cancels a transaction on the [ITransactionQueue]. 51 | * 52 | * @param transaction 53 | */ 54 | fun cancelTransaction(transaction: Transaction) = queue.cancel(transaction) 55 | } 56 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/transaction/DefaultTransactionManager.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.transaction 2 | 3 | import com.dbflow5.config.DBFlowDatabase 4 | 5 | /** 6 | * Description: This class manages batch database interactions. Places DB operations onto the same Thread. 7 | */ 8 | class DefaultTransactionManager : BaseTransactionManager { 9 | 10 | constructor(databaseDefinition: DBFlowDatabase) 11 | : super(DefaultTransactionQueue("DBFlow Transaction Queue"), databaseDefinition) 12 | 13 | constructor(transactionQueue: ITransactionQueue, 14 | databaseDefinition: DBFlowDatabase) 15 | : super(transactionQueue, databaseDefinition) 16 | 17 | } 18 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/transaction/ITransaction.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.transaction 2 | 3 | import com.dbflow5.database.DatabaseWrapper 4 | 5 | /** 6 | * Description: Simplest form of a transaction. It represents an interface by which code is executed 7 | * inside a database transaction. 8 | */ 9 | interface ITransaction { 10 | 11 | /** 12 | * Called within a database transaction. 13 | * 14 | * @param databaseWrapper The database to save data into. Use this access to operate on the DB 15 | * without causing an Android SQLiteDatabaseLockedException or other problems due to locking. 16 | */ 17 | fun execute(databaseWrapper: DatabaseWrapper): R 18 | } 19 | -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/transaction/ITransactionQueue.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.transaction 2 | 3 | /** 4 | * Description: Interface for a queue that manages transactions. 5 | */ 6 | interface ITransactionQueue { 7 | 8 | /** 9 | * Adds a transaction to the queue. 10 | * 11 | * @param transaction The transaction to run on the queue. 12 | */ 13 | fun add(transaction: Transaction) 14 | 15 | /** 16 | * Cancels a transaction. 17 | * 18 | * @param transaction The transaction to cancel on the queue. 19 | */ 20 | fun cancel(transaction: Transaction) 21 | 22 | /** 23 | * Starts if not alive. 24 | */ 25 | fun startIfNotAlive() 26 | 27 | /** 28 | * Cancels a transaction by name. 29 | * 30 | * @param name the [Transaction.name] property. 31 | */ 32 | fun cancel(name: String) 33 | 34 | /** 35 | * Stops/interrupts the queue. 36 | */ 37 | fun quit() 38 | 39 | } -------------------------------------------------------------------------------- /lib/src/main/kotlin/com/dbflow5/transaction/TransactionWrapper.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.transaction 2 | 3 | import com.dbflow5.database.DatabaseWrapper 4 | 5 | /** 6 | * Description: Wraps multiple transactions together. 7 | */ 8 | class TransactionWrapper : ITransaction { 9 | 10 | private val transactions = arrayListOf>() 11 | 12 | constructor(vararg transactions: ITransaction) { 13 | this.transactions.addAll(transactions) 14 | } 15 | 16 | constructor(transactions: Collection>) { 17 | this.transactions.addAll(transactions) 18 | } 19 | 20 | override fun execute(databaseWrapper: DatabaseWrapper) { 21 | transactions.forEach { it.execute(databaseWrapper) } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /livedata/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /livedata/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.library") 3 | kotlin("android") 4 | } 5 | // project.ext.artifactId = bt_name 6 | 7 | android { 8 | compileSdkVersion(Versions.TargetSdk) 9 | 10 | defaultConfig { 11 | minSdkVersion(Versions.ArchMin) 12 | targetSdkVersion(Versions.TargetSdk) 13 | } 14 | 15 | compileOptions { 16 | sourceCompatibility = JavaVersion.VERSION_1_8 17 | targetCompatibility = JavaVersion.VERSION_1_8 18 | } 19 | 20 | sourceSets { 21 | getByName("main").java.srcDirs("src/main/kotlin") 22 | } 23 | } 24 | 25 | dependencies { 26 | implementation(project(":lib")) 27 | api(Dependencies.AndroidX.LiveData) 28 | } 29 | 30 | apply(from = "../kotlin-artifacts.gradle") 31 | -------------------------------------------------------------------------------- /livedata/gradle.properties: -------------------------------------------------------------------------------- 1 | bt_name=dbflow-livedata 2 | bt_packaging=aar 3 | bt_artifact_id=dbflow-livedata -------------------------------------------------------------------------------- /livedata/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /livedata/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /paging/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.library") 3 | kotlin("android") 4 | } 5 | // project.ext.artifactId = bt_name 6 | 7 | android { 8 | compileSdkVersion(Versions.TargetSdk) 9 | 10 | defaultConfig { 11 | minSdkVersion(Versions.ArchMin) 12 | targetSdkVersion(Versions.TargetSdk) 13 | } 14 | 15 | compileOptions { 16 | sourceCompatibility = JavaVersion.VERSION_1_8 17 | targetCompatibility = JavaVersion.VERSION_1_8 18 | } 19 | 20 | sourceSets { 21 | getByName("main").java.srcDirs("src/main/kotlin") 22 | } 23 | } 24 | 25 | dependencies { 26 | implementation(project(":lib")) 27 | api(Dependencies.AndroidX.Paging) 28 | } 29 | 30 | apply(from = "../kotlin-artifacts.gradle") 31 | -------------------------------------------------------------------------------- /paging/gradle.properties: -------------------------------------------------------------------------------- 1 | bt_name=dbflow-paging 2 | bt_packaging=aar 3 | bt_artifact_id=dbflow-paging -------------------------------------------------------------------------------- /paging/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = buildName -------------------------------------------------------------------------------- /paging/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /processor/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | plugins { 4 | kotlin("jvm") 5 | } 6 | 7 | // project.ext.artifactId = bt_name 8 | 9 | tasks.withType { 10 | kotlinOptions.jvmTarget = "1.8" 11 | } 12 | 13 | dependencies { 14 | api(project(":core")) 15 | api(project(":contentprovider-annotations")) 16 | api(Dependencies.JavaPoet) 17 | api(Dependencies.KPoet) 18 | 19 | compileOnly(Dependencies.JavaXAnnotation) 20 | testImplementation(Dependencies.JUnit) 21 | } 22 | 23 | apply(from = "../kotlin-artifacts.gradle") 24 | -------------------------------------------------------------------------------- /processor/gradle.properties: -------------------------------------------------------------------------------- 1 | bt_name=dbflow-processor 2 | bt_packaging=aar 3 | bt_artifact_id=dbflow-processor -------------------------------------------------------------------------------- /processor/src/main/kotlin/com/dbflow5/processor/definition/Adders.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.processor.definition 2 | 3 | import com.squareup.javapoet.CodeBlock 4 | import com.squareup.javapoet.TypeSpec 5 | 6 | /** 7 | * Description: 8 | * 9 | * @author Andrew Grosner (fuzz) 10 | */ 11 | interface TypeAdder { 12 | 13 | fun addToType(typeBuilder: TypeSpec.Builder) 14 | } 15 | 16 | interface CodeAdder { 17 | 18 | fun addCode(code: CodeBlock.Builder): CodeBlock.Builder 19 | } -------------------------------------------------------------------------------- /processor/src/main/kotlin/com/dbflow5/processor/definition/IndexGroupsDefinition.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.processor.definition 2 | 3 | import com.grosner.kpoet.S 4 | import com.grosner.kpoet.`=` 5 | import com.grosner.kpoet.field 6 | import com.grosner.kpoet.final 7 | import com.grosner.kpoet.public 8 | import com.grosner.kpoet.static 9 | import com.dbflow5.annotation.IndexGroup 10 | import com.dbflow5.processor.definition.column.ColumnDefinition 11 | import com.squareup.javapoet.ParameterizedTypeName 12 | import java.util.concurrent.atomic.AtomicInteger 13 | 14 | /** 15 | * Description: 16 | */ 17 | class IndexGroupsDefinition(private val tableDefinition: TableDefinition, indexGroup: IndexGroup) { 18 | 19 | val indexName = indexGroup.name 20 | val indexNumber = indexGroup.number 21 | val isUnique = indexGroup.unique 22 | 23 | val columnDefinitionList: MutableList = arrayListOf() 24 | 25 | val fieldSpec 26 | get() = field(ParameterizedTypeName.get(com.dbflow5.processor.ClassNames.INDEX_PROPERTY, tableDefinition.elementClassName), 27 | "index_$indexName") { 28 | addModifiers(public, static, final) 29 | `=` { 30 | add("new \$T<>(${indexName.S}, $isUnique, \$T.class", 31 | com.dbflow5.processor.ClassNames.INDEX_PROPERTY, tableDefinition.elementTypeName) 32 | 33 | if (columnDefinitionList.isNotEmpty()) { 34 | add(",") 35 | } 36 | val index = AtomicInteger(0) 37 | columnDefinitionList.forEach { it.appendIndexInitializer(this, index) } 38 | add(")") 39 | } 40 | }.build()!! 41 | 42 | } 43 | -------------------------------------------------------------------------------- /processor/src/main/kotlin/com/dbflow5/processor/definition/TypeDefinition.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.processor.definition 2 | 3 | import com.squareup.javapoet.TypeSpec 4 | 5 | /** 6 | * Description: Simple interface for returning a [TypeSpec]. 7 | */ 8 | interface TypeDefinition { 9 | 10 | /** 11 | * @return The [TypeSpec] used to write this class' type file. 12 | */ 13 | val typeSpec: TypeSpec 14 | } 15 | 16 | -------------------------------------------------------------------------------- /processor/src/main/kotlin/com/dbflow5/processor/definition/UniqueGroupsDefinition.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.processor.definition 2 | 3 | import com.dbflow5.annotation.ConflictAction 4 | import com.dbflow5.annotation.UniqueGroup 5 | import com.dbflow5.processor.definition.column.ColumnDefinition 6 | import com.dbflow5.processor.definition.column.ReferenceColumnDefinition 7 | import com.dbflow5.quote 8 | import com.squareup.javapoet.CodeBlock 9 | 10 | /** 11 | * Description: 12 | */ 13 | class UniqueGroupsDefinition(uniqueGroup: UniqueGroup) { 14 | 15 | val columnDefinitionList: MutableList = arrayListOf() 16 | val number: Int = uniqueGroup.groupNumber 17 | 18 | private val uniqueConflict: ConflictAction = uniqueGroup.uniqueConflict 19 | 20 | fun addColumnDefinition(columnDefinition: ColumnDefinition) { 21 | columnDefinitionList.add(columnDefinition) 22 | } 23 | 24 | val creationName: CodeBlock 25 | get() { 26 | val codeBuilder = CodeBlock.builder().add(", UNIQUE(") 27 | codeBuilder.add(columnDefinitionList.joinToString { columnDefinition -> 28 | if (columnDefinition is ReferenceColumnDefinition) { 29 | columnDefinition.referenceDefinitionList.joinToString { it.columnName.quote() } 30 | } else { 31 | columnDefinition.columnName.quote() 32 | } 33 | }) 34 | codeBuilder.add(") ON CONFLICT \$L", uniqueConflict) 35 | return codeBuilder.build() 36 | } 37 | } -------------------------------------------------------------------------------- /processor/src/main/kotlin/com/dbflow5/processor/definition/behavior/ColumnBehaviors.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.processor.definition.behavior 2 | 3 | import com.dbflow5.annotation.ForeignKeyAction 4 | import com.dbflow5.processor.definition.column.ColumnDefinition 5 | 6 | /** 7 | * Defines how Primary Key columns behave. If has autoincrementing column or ROWID, the [associatedColumn] is not null. 8 | */ 9 | data class PrimaryKeyColumnBehavior( 10 | val hasRowID: Boolean, 11 | /** 12 | * Either [hasRowID] or [hasAutoIncrement] or null. 13 | */ 14 | val associatedColumn: ColumnDefinition?, 15 | val hasAutoIncrement: Boolean) 16 | 17 | 18 | /** 19 | * Defines how Foreign Key columns behave. 20 | */ 21 | data class ForeignKeyColumnBehavior( 22 | val onDelete: ForeignKeyAction, 23 | val onUpdate: ForeignKeyAction, 24 | val saveForeignKeyModel: Boolean, 25 | val deleteForeignKeyModel: Boolean, 26 | val deferred: Boolean 27 | ) -------------------------------------------------------------------------------- /processor/src/main/kotlin/com/dbflow5/processor/definition/behavior/CreationQueryBehavior.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.processor.definition.behavior 2 | 3 | import com.dbflow5.processor.definition.TypeAdder 4 | import com.dbflow5.processor.utils.`override fun` 5 | import com.grosner.kpoet.L 6 | import com.grosner.kpoet.`return` 7 | import com.grosner.kpoet.final 8 | import com.grosner.kpoet.modifiers 9 | import com.grosner.kpoet.public 10 | import com.squareup.javapoet.TypeName 11 | import com.squareup.javapoet.TypeSpec 12 | 13 | /** 14 | * Description: 15 | */ 16 | data class CreationQueryBehavior(val createWithDatabase: Boolean) : TypeAdder { 17 | 18 | override fun addToType(typeBuilder: TypeSpec.Builder) { 19 | typeBuilder.apply { 20 | if (!createWithDatabase) { 21 | `override fun`(TypeName.BOOLEAN, "createWithDatabase") { 22 | modifiers(public, final) 23 | `return`(false.L) 24 | } 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /processor/src/main/kotlin/com/dbflow5/processor/definition/column/DefinitionUtils.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.processor.definition.column 2 | 3 | import com.dbflow5.processor.SQLiteHelper 4 | import com.dbflow5.quote 5 | import com.squareup.javapoet.CodeBlock 6 | import com.squareup.javapoet.TypeName 7 | 8 | /** 9 | * Description: 10 | */ 11 | object DefinitionUtils { 12 | 13 | fun getCreationStatement(elementTypeName: TypeName?, 14 | wrapperTypeName: TypeName?, 15 | columnName: String): CodeBlock.Builder { 16 | var statement: String? = null 17 | 18 | if (SQLiteHelper.containsType(wrapperTypeName ?: elementTypeName)) { 19 | statement = SQLiteHelper[wrapperTypeName ?: elementTypeName].toString() 20 | } 21 | 22 | return CodeBlock.builder().add("\$L \$L", columnName.quote(), statement) 23 | 24 | } 25 | 26 | fun getLoadFromCursorMethodString(elementTypeName: TypeName?, 27 | wrapperTypeName: TypeName?): String { 28 | var method = "" 29 | if (SQLiteHelper.containsMethod(wrapperTypeName ?: elementTypeName)) { 30 | method = SQLiteHelper.getMethod(elementTypeName) 31 | } 32 | return method 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /processor/src/main/kotlin/com/dbflow5/processor/definition/provider/ContentUriDefinition.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.processor.definition.provider 2 | 3 | import com.dbflow5.contentprovider.annotation.ContentUri 4 | import com.dbflow5.processor.ClassNames 5 | import com.dbflow5.processor.ProcessorManager 6 | import com.dbflow5.processor.definition.BaseDefinition 7 | import javax.lang.model.element.Element 8 | import javax.lang.model.element.ExecutableElement 9 | import javax.lang.model.element.VariableElement 10 | 11 | /** 12 | * Description: 13 | */ 14 | class ContentUriDefinition(contentUri: ContentUri, 15 | typeElement: Element, processorManager: ProcessorManager) 16 | : BaseDefinition(typeElement, processorManager) { 17 | 18 | var name = "${typeElement.enclosingElement.simpleName}_${typeElement.simpleName}" 19 | 20 | val path: String = contentUri.path 21 | val type: String = contentUri.type 22 | val queryEnabled: Boolean = contentUri.queryEnabled 23 | val insertEnabled: Boolean = contentUri.insertEnabled 24 | val deleteEnabled: Boolean = contentUri.deleteEnabled 25 | val updateEnabled: Boolean = contentUri.updateEnabled 26 | val segments = contentUri.segments 27 | 28 | init { 29 | if (typeElement is VariableElement) { 30 | if (ClassNames.URI != elementTypeName) { 31 | processorManager.logError("Content Uri field returned wrong type. It must return a Uri") 32 | } 33 | } else if (typeElement is ExecutableElement) { 34 | if (ClassNames.URI != elementTypeName) { 35 | processorManager.logError("ContentUri method returns wrong type. It must return Uri") 36 | } 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /processor/src/main/kotlin/com/dbflow5/processor/utils/CodeExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.processor.utils 2 | 3 | import com.grosner.kpoet.end 4 | import com.grosner.kpoet.nextControl 5 | import com.squareup.javapoet.CodeBlock 6 | import com.squareup.javapoet.MethodSpec 7 | import kotlin.reflect.KClass 8 | 9 | /** 10 | * Description: Set of utility methods to save code 11 | * 12 | * @author Andrew Grosner (fuzz) 13 | */ 14 | 15 | /** 16 | * Collapses the control flow into an easy to use block 17 | */ 18 | fun CodeBlock.Builder.controlFlow(statement: String, vararg args: Any?, 19 | method: (CodeBlock.Builder) -> Unit) = beginControlFlow(statement, *args).apply { method(this) }.endControlFlow()!! 20 | 21 | fun MethodSpec.Builder.controlFlow(statement: String, vararg args: Any?, 22 | method: CodeBlock.Builder.() -> Unit) = beginControlFlow(statement, *args).apply { 23 | addCode(CodeBlock.builder().apply { method(this) }.build()) 24 | }.endControlFlow()!! 25 | 26 | /** 27 | * Description: Convenience method for adding [CodeBlock] statements without needing to do so every time. 28 | * 29 | * @author Andrew Grosner (fuzz) 30 | */ 31 | fun CodeBlock.Builder.statement(codeBlock: CodeBlock?): CodeBlock.Builder 32 | = this.addStatement("\$L", codeBlock) 33 | 34 | fun MethodSpec.Builder.statement(codeBlock: CodeBlock?): MethodSpec.Builder 35 | 36 | = this.addStatement("\$L", codeBlock) 37 | 38 | inline fun CodeBlock.Builder.catch(exception: KClass, 39 | function: CodeBlock.Builder.() -> CodeBlock.Builder) 40 | = nextControl("catch", statement = "\$T e", args = *arrayOf(exception.java), function = function).end() 41 | 42 | fun codeBlock(function: CodeBlock.Builder.() -> CodeBlock.Builder) = CodeBlock.builder().function().build() 43 | 44 | -------------------------------------------------------------------------------- /processor/src/main/kotlin/com/dbflow5/processor/utils/DependencyUtils.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.processor.utils 2 | 3 | import com.dbflow5.processor.ProcessorManager 4 | 5 | /** 6 | * Used to check if class exists on class path, if so, we add the annotation to generated class files. 7 | */ 8 | fun hasJavaX() = ProcessorManager.manager.elements.getTypeElement("javax.annotation.Generated") != null -------------------------------------------------------------------------------- /processor/src/main/kotlin/com/dbflow5/processor/utils/LetUtils.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.processor.utils 2 | 3 | /** 4 | * Description: Multi-let execution. 5 | */ 6 | inline fun safeLet(a: A?, b: B?, fn: (a: A, b: B) -> R) { 7 | if (a != null && b != null) fn(a, b) 8 | } -------------------------------------------------------------------------------- /processor/src/main/kotlin/com/dbflow5/processor/utils/ModelUtils.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.processor.utils 2 | 3 | object ModelUtils { 4 | 5 | val variable = "model" 6 | 7 | val wrapper = "wrapper" 8 | } 9 | -------------------------------------------------------------------------------- /processor/src/main/kotlin/com/dbflow5/processor/utils/StringUtils.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.processor.utils 2 | 3 | /** 4 | * Description: 5 | */ 6 | fun String?.isNullOrEmpty(): Boolean { 7 | return this == null || this.trim { it <= ' ' }.isEmpty() || this == "null" 8 | } 9 | 10 | fun String?.capitalizeFirstLetter(): String { 11 | if (this == null || this.trim { it <= ' ' }.isEmpty()) { 12 | return this ?: "" 13 | } 14 | 15 | return this.capitalize() 16 | } 17 | 18 | fun String?.lower(): String { 19 | if (this == null || this.trim { it <= ' ' }.isEmpty()) { 20 | return this ?: "" 21 | } 22 | 23 | return this.substring(0, 1).toLowerCase() + this.substring(1) 24 | } 25 | -------------------------------------------------------------------------------- /processor/src/main/kotlin/com/dbflow5/processor/utils/WriterUtils.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.processor.utils 2 | 3 | import com.dbflow5.processor.ProcessorManager 4 | import com.dbflow5.processor.definition.BaseDefinition 5 | import com.grosner.kpoet.javaFile 6 | import java.io.IOException 7 | 8 | fun BaseDefinition.writeBaseDefinition(processorManager: ProcessorManager): Boolean { 9 | var success = false 10 | try { 11 | javaFile(packageName) { typeSpec } 12 | .writeTo(processorManager.processingEnvironment.filer) 13 | success = true 14 | } catch (e: IOException) { 15 | // ignored 16 | } catch (i: IllegalStateException) { 17 | processorManager.logError(this::class, "Found error for class: $elementName") 18 | processorManager.logError(this::class, i.message) 19 | } 20 | 21 | return success 22 | } -------------------------------------------------------------------------------- /processor/src/main/resources/META-INF/gradle/incremental.annotation.processors: -------------------------------------------------------------------------------- 1 | com.dbflow5.processor.DBFlowProcessor,isolating -------------------------------------------------------------------------------- /processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor: -------------------------------------------------------------------------------- 1 | com.dbflow5.processor.DBFlowProcessor -------------------------------------------------------------------------------- /proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Applications/Android Studio.app/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /reactive-streams/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.library") 3 | kotlin("android") 4 | } 5 | // project.ext.artifactId = bt_name 6 | 7 | android { 8 | compileSdkVersion(Versions.TargetSdk) 9 | 10 | defaultConfig { 11 | minSdkVersion(Versions.MinSdkRX) 12 | targetSdkVersion(Versions.TargetSdk) 13 | } 14 | 15 | compileOptions { 16 | sourceCompatibility = JavaVersion.VERSION_1_8 17 | targetCompatibility = JavaVersion.VERSION_1_8 18 | } 19 | 20 | sourceSets { 21 | getByName("main").java.srcDirs("src/main/kotlin") 22 | } 23 | 24 | kotlinOptions { 25 | jvmTarget = "1.8" 26 | } 27 | } 28 | 29 | dependencies { 30 | api(project(":lib")) 31 | api(Dependencies.RX) 32 | } 33 | 34 | apply(from = "../kotlin-artifacts.gradle") 35 | -------------------------------------------------------------------------------- /reactive-streams/gradle.properties: -------------------------------------------------------------------------------- 1 | bt_name=dbflow-rx2 2 | bt_packaging=aar 3 | bt_artifact_id=dbflow-rx2 4 | -------------------------------------------------------------------------------- /reactive-streams/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /reactive-streams/src/main/kotlin/com/dbflow5/reactivestreams/query/ModelQueriableExtensions.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("RXModelQueriable") 2 | 3 | package com.dbflow5.reactivestreams.query 4 | 5 | import com.dbflow5.config.DBFlowDatabase 6 | import com.dbflow5.query.ModelQueriable 7 | import com.dbflow5.transaction.ITransactionQueue 8 | import io.reactivex.rxjava3.core.Flowable 9 | 10 | /** 11 | * Streams the results of this [ModelQueriable] through the [ITransactionQueue] and emitted one at 12 | * time. 13 | */ 14 | fun ModelQueriable.queryStreamResults(dbFlowDatabase: DBFlowDatabase): Flowable = 15 | CursorListFlowable(this, dbFlowDatabase) 16 | 17 | -------------------------------------------------------------------------------- /reactive-streams/src/main/kotlin/com/dbflow5/reactivestreams/structure/RXRetrievalAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.reactivestreams.structure 2 | 3 | import com.dbflow5.adapter.RetrievalAdapter 4 | import com.dbflow5.config.FlowManager 5 | import com.dbflow5.database.DatabaseWrapper 6 | import io.reactivex.rxjava3.core.Completable 7 | import io.reactivex.rxjava3.core.Single 8 | 9 | /** 10 | * Description: Mirrors the [RetrievalAdapter] with subset of exposed methods, mostly for 11 | * [.load] and [.exists] 12 | */ 13 | open class RXRetrievalAdapter 14 | internal constructor(private val retrievalAdapter: RetrievalAdapter) { 15 | 16 | internal constructor(table: Class) : this(FlowManager.getRetrievalAdapter(table)) 17 | 18 | fun load(model: T, databaseWrapper: DatabaseWrapper): Completable = Completable.fromCallable { 19 | retrievalAdapter.load(model, databaseWrapper) 20 | null 21 | } 22 | 23 | /** 24 | * @param model The model to query values from 25 | * @return True if it exists as a row in the corresponding database table 26 | */ 27 | fun exists(model: T, wrapper: DatabaseWrapper): Single = 28 | Single.fromCallable { retrievalAdapter.exists(model, wrapper) } 29 | 30 | companion object { 31 | 32 | @JvmStatic 33 | fun from(modelAdapter: RetrievalAdapter): RXRetrievalAdapter = 34 | RXRetrievalAdapter(modelAdapter) 35 | 36 | @JvmStatic 37 | fun from(table: Class): RXRetrievalAdapter = RXRetrievalAdapter(table) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':lib', ':reactive-streams', ':coroutines', ':contentprovider', ':contentprovider-annotations', ':livedata', 2 | ':processor', 3 | ':core', 4 | ':sqlcipher', 5 | ':tests', 6 | ':paging' 7 | 8 | -------------------------------------------------------------------------------- /sqlcipher/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sqlcipher/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.library") 3 | kotlin("android") 4 | } 5 | // project.ext.artifactId = bt_name 6 | 7 | android { 8 | compileSdkVersion(Versions.TargetSdk) 9 | 10 | defaultConfig { 11 | minSdkVersion(Versions.SQLCipherMin) 12 | targetSdkVersion(Versions.TargetSdk) 13 | } 14 | 15 | compileOptions { 16 | sourceCompatibility = JavaVersion.VERSION_1_8 17 | targetCompatibility = JavaVersion.VERSION_1_8 18 | } 19 | 20 | sourceSets { 21 | getByName("main").java.srcDirs("src/main/kotlin") 22 | } 23 | } 24 | 25 | dependencies { 26 | api(Dependencies.SqlCipher) 27 | api(project(":lib")) 28 | } 29 | 30 | apply(from = "../kotlin-artifacts.gradle") 31 | -------------------------------------------------------------------------------- /sqlcipher/gradle.properties: -------------------------------------------------------------------------------- 1 | bt_name=dbflow-sqlcipher 2 | bt_packaging=aar 3 | bt_artifact_id=dbflow-sqlcipher -------------------------------------------------------------------------------- /sqlcipher/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/andrewgrosner/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /sqlcipher/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = buildName -------------------------------------------------------------------------------- /sqlcipher/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /tests/gradle.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agrosner/DBFlow/e1b6211dac6ddc0aa0c1c9a76a116478ccf92b86/tests/gradle.properties -------------------------------------------------------------------------------- /tests/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/andrewgrosner/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /tests/src/androidTest/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 12 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/BaseUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5 2 | 3 | import android.content.Context 4 | import androidx.test.core.app.ApplicationProvider 5 | import androidx.test.ext.junit.runners.AndroidJUnit4 6 | import org.junit.Rule 7 | import org.junit.runner.RunWith 8 | 9 | @RunWith(AndroidJUnit4::class) 10 | abstract class BaseUnitTest { 11 | 12 | @JvmField 13 | @Rule 14 | var dblflowTestRule = DBFlowInstrumentedTestRule.create() 15 | 16 | val context: Context 17 | get() = ApplicationProvider.getApplicationContext() 18 | 19 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/DBFlowInstrumentedTestRule.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5 2 | 3 | import com.dbflow5.config.DBFlowDatabase 4 | import com.dbflow5.config.FlowConfig 5 | import com.dbflow5.config.FlowLog 6 | import com.dbflow5.config.FlowManager 7 | import com.dbflow5.contentobserver.ContentObserverDatabase 8 | import com.dbflow5.database.AndroidSQLiteOpenHelper 9 | import com.dbflow5.runtime.ContentResolverNotifier 10 | import org.junit.rules.TestRule 11 | import org.junit.runner.Description 12 | import org.junit.runners.model.Statement 13 | 14 | 15 | class DBFlowInstrumentedTestRule(private val dbConfigBlock: FlowConfig.Builder.() -> Unit) : TestRule { 16 | 17 | override fun apply(base: Statement, description: Description): Statement { 18 | return object : Statement() { 19 | 20 | @Throws(Throwable::class) 21 | override fun evaluate() { 22 | FlowLog.setMinimumLoggingLevel(FlowLog.Level.V) 23 | FlowManager.init(DemoApp.context) { 24 | database({ 25 | transactionManagerCreator(::ImmediateTransactionManager) 26 | }, AndroidSQLiteOpenHelper.createHelperCreator(DemoApp.context)) 27 | dbConfigBlock() 28 | } 29 | try { 30 | base.evaluate() 31 | } finally { 32 | FlowManager.destroy() 33 | } 34 | } 35 | } 36 | } 37 | 38 | companion object { 39 | fun create(dbConfigBlock: FlowConfig.Builder.() -> Unit = {}) = DBFlowInstrumentedTestRule(dbConfigBlock) 40 | } 41 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/ImmediateTransactionManager.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5 2 | 3 | import com.dbflow5.config.DBFlowDatabase 4 | import com.dbflow5.transaction.BaseTransactionManager 5 | import com.dbflow5.transaction.ITransactionQueue 6 | import com.dbflow5.transaction.Transaction 7 | 8 | /** 9 | * Description: Executes all transactions on same thread for testing. 10 | */ 11 | class ImmediateTransactionManager(databaseDefinition: DBFlowDatabase) 12 | : BaseTransactionManager(ImmediateTransactionQueue(), databaseDefinition) 13 | 14 | 15 | class ImmediateTransactionQueue : ITransactionQueue { 16 | 17 | override fun add(transaction: Transaction) { 18 | transaction.newBuilder() 19 | .runCallbacksOnSameThread(true) 20 | .build() 21 | .executeSync() 22 | } 23 | 24 | override fun cancel(transaction: Transaction) { 25 | 26 | } 27 | 28 | override fun startIfNotAlive() { 29 | } 30 | 31 | override fun cancel(name: String) { 32 | } 33 | 34 | override fun quit() { 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/TestDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5 2 | 3 | import com.dbflow5.annotation.Database 4 | import com.dbflow5.annotation.ForeignKey 5 | import com.dbflow5.annotation.Migration 6 | import com.dbflow5.annotation.PrimaryKey 7 | import com.dbflow5.annotation.Table 8 | import com.dbflow5.config.DBFlowDatabase 9 | import com.dbflow5.database.DatabaseWrapper 10 | import com.dbflow5.migration.BaseMigration 11 | import com.dbflow5.migration.UpdateTableMigration 12 | import com.dbflow5.models.SimpleModel 13 | 14 | /** 15 | * Description: 16 | */ 17 | @Database(version = 1) 18 | abstract class TestDatabase : DBFlowDatabase() { 19 | 20 | @Migration(version = 1, database = TestDatabase::class, priority = 5) 21 | class TestMigration : UpdateTableMigration(SimpleModel::class.java) { 22 | override fun onPreMigrate() { 23 | super.onPreMigrate() 24 | set(SimpleModel_Table.name.eq("Test")).where(SimpleModel_Table.name.eq("Test1")) 25 | } 26 | } 27 | 28 | @Migration(version = 1, database = TestDatabase::class, priority = 1) 29 | class SecondMigration : BaseMigration() { 30 | override fun migrate(database: DatabaseWrapper) { 31 | 32 | } 33 | } 34 | } 35 | 36 | @Database(version = 1, foreignKeyConstraintsEnforced = true) 37 | abstract class TestForeignKeyDatabase : DBFlowDatabase() { 38 | 39 | @Table(database = TestForeignKeyDatabase::class) 40 | data class SimpleModel(@PrimaryKey var name: String = "") 41 | 42 | @Table(database = TestForeignKeyDatabase::class) 43 | data class SimpleForeignModel(@PrimaryKey var id: Int = 0, 44 | @ForeignKey var model: SimpleModel? = null) 45 | } 46 | -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/TestExtensions.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5 2 | 3 | import com.dbflow5.sql.Query 4 | import org.junit.Assert.assertEquals 5 | import org.junit.Assert.fail 6 | import kotlin.reflect.KClass 7 | 8 | 9 | fun String.assertEquals(query: Query) = assertEquals(this, query.query.trim()) 10 | 11 | fun Query.assertEquals(actual: Query) = assertEquals(query.trim(), actual.query.trim()) 12 | 13 | fun assertThrowsException(expectedException: KClass, function: () -> Unit) { 14 | try { 15 | function() 16 | fail("Expected call to fail. Unexpectedly passed") 17 | } catch (e: Exception) { 18 | if (e.javaClass != expectedException.java) { 19 | e.printStackTrace() 20 | fail("Expected $expectedException but got ${e.javaClass}") 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/TestForeignKeyDatabaseTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5 2 | 3 | import com.dbflow5.config.database 4 | import org.junit.Test 5 | 6 | class TestForeignKeyDatabaseTest : BaseUnitTest() { 7 | 8 | @Test 9 | fun verifyDB() { 10 | database { db -> 11 | val enabled = longForQuery(db, "PRAGMA foreign_keys;") 12 | assert(enabled == 1L) 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/User.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5 2 | 3 | import com.dbflow5.annotation.Column 4 | import com.dbflow5.annotation.PrimaryKey 5 | import com.dbflow5.annotation.Table 6 | import com.dbflow5.contentobserver.ContentObserverDatabase 7 | 8 | @Table(database = ContentObserverDatabase::class, name = "User2") 9 | class User(@PrimaryKey var id: Int = 0, 10 | @Column var firstName: String? = null, 11 | @Column var lastName: String? = null, 12 | @Column var email: String? = null) 13 | -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/contentobserver/ContentObserverDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.contentobserver 2 | 3 | import com.dbflow5.annotation.Database 4 | import com.dbflow5.config.DBFlowDatabase 5 | 6 | @Database(version = 1) 7 | abstract class ContentObserverDatabase : DBFlowDatabase() 8 | -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/contentobserver/User.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.contentobserver 2 | 3 | import com.dbflow5.annotation.Column 4 | import com.dbflow5.annotation.PrimaryKey 5 | import com.dbflow5.annotation.Table 6 | 7 | @Table(database = ContentObserverDatabase::class) 8 | class User(@PrimaryKey var id: Int = 0, @PrimaryKey var name: String = "", @Column var age: Int = 0) -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/livedata/LiveDataModels.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.livedata 2 | 3 | import com.dbflow5.TestDatabase 4 | import com.dbflow5.annotation.PrimaryKey 5 | import com.dbflow5.annotation.Table 6 | 7 | /** 8 | * Description: Basic live data object model. 9 | */ 10 | @Table(database = TestDatabase::class) 11 | data class LiveDataModel(@PrimaryKey var id: String = "", 12 | var name: Int = 0) -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/livedata/LiveDataTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.livedata 2 | 3 | import androidx.arch.core.executor.testing.InstantTaskExecutorRule 4 | import androidx.lifecycle.Lifecycle 5 | import androidx.lifecycle.LifecycleRegistry 6 | import androidx.lifecycle.Observer 7 | import com.dbflow5.BaseUnitTest 8 | import com.dbflow5.TestDatabase 9 | import com.dbflow5.config.database 10 | import com.dbflow5.query.select 11 | import com.dbflow5.structure.insert 12 | import com.nhaarman.mockitokotlin2.mock 13 | import org.junit.Rule 14 | import org.junit.Test 15 | import org.junit.rules.TestRule 16 | 17 | /** 18 | * Description: 19 | */ 20 | class LiveDataTest : BaseUnitTest() { 21 | 22 | @get:Rule 23 | val rule: TestRule = InstantTaskExecutorRule() 24 | 25 | @Test 26 | fun live_data_executes_for_a_few_model_queries() { 27 | val data = (select from LiveDataModel::class) 28 | .toLiveData { db -> queryList(db) } 29 | 30 | val observer = mock>>() 31 | val lifecycle = LifecycleRegistry(mock()) 32 | lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME) 33 | 34 | data.observeForever(observer) 35 | 36 | val value = data.value!! 37 | assert(value.isEmpty()) 38 | 39 | database() 40 | .beginTransactionAsync { db -> 41 | (0..2).forEach { 42 | LiveDataModel(id = "$it", name = it).insert(db) 43 | } 44 | } 45 | .execute() 46 | 47 | database().tableObserver.checkForTableUpdates() 48 | 49 | val value2 = data.value!! 50 | assert(value2.size == 3) { "expected ${value2.size} == 3" } 51 | } 52 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/migration/MigrationModels.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.migration 2 | 3 | import com.dbflow5.TestDatabase 4 | import com.dbflow5.annotation.Migration 5 | import com.dbflow5.database.DatabaseWrapper 6 | 7 | @Migration(database = TestDatabase::class, priority = 1, version = 1) 8 | class FirstMigration : BaseMigration() { 9 | override fun migrate(database: DatabaseWrapper) { 10 | 11 | } 12 | } 13 | 14 | @Migration(database = TestDatabase::class, priority = 2, version = 1) 15 | class SecondMigration : BaseMigration() { 16 | override fun migrate(database: DatabaseWrapper) { 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/migration/UpdateTableMigrationTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.migration 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.config.databaseForTable 5 | import com.dbflow5.models.SimpleModel 6 | import com.dbflow5.models.SimpleModel_Table 7 | import org.junit.Test 8 | 9 | /** 10 | * Description: 11 | */ 12 | 13 | class UpdateTableMigrationTest : BaseUnitTest() { 14 | 15 | 16 | @Test 17 | fun testUpdateMigrationQuery() { 18 | val update = UpdateTableMigration(SimpleModel::class.java) 19 | update.set(SimpleModel_Table.name.eq("yes")) 20 | update.migrate(databaseForTable()) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/AutoIncrementTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.TestDatabase 5 | import com.dbflow5.annotation.PrimaryKey 6 | import com.dbflow5.annotation.Table 7 | import com.dbflow5.config.databaseForTable 8 | import com.dbflow5.structure.insert 9 | import org.junit.Assert.assertEquals 10 | import org.junit.Test 11 | 12 | /** 13 | * Description: 14 | */ 15 | class AutoIncrementTest : BaseUnitTest() { 16 | 17 | @Test 18 | fun testCanInsertAutoIncrement() { 19 | val model = AutoIncrementingModel() 20 | model.insert(databaseForTable()) 21 | assertEquals(1L, model.id) 22 | } 23 | 24 | @Test 25 | fun testCanInsertExistingIdAutoIncrement() { 26 | val model = AutoIncrementingModel(3) 27 | model.insert(databaseForTable()) 28 | assertEquals(3L, model.id) 29 | } 30 | } 31 | 32 | 33 | @Table(database = TestDatabase::class) 34 | class AutoIncrementingModel(@PrimaryKey(autoincrement = true) var id: Long = 0) -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/CachingModels.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models 2 | 3 | import com.dbflow5.TestDatabase 4 | import com.dbflow5.annotation.Column 5 | import com.dbflow5.annotation.ForeignKey 6 | import com.dbflow5.annotation.MultiCacheField 7 | import com.dbflow5.annotation.PrimaryKey 8 | import com.dbflow5.annotation.Table 9 | import com.dbflow5.query.cache.MultiKeyCacheConverter 10 | 11 | @Table(database = TestDatabase::class, cachingEnabled = true) 12 | class SimpleCacheObject(@PrimaryKey var id: String = "") 13 | 14 | @Table(database = TestDatabase::class, cachingEnabled = true) 15 | class Coordinate(@PrimaryKey var latitude: Double = 0.0, 16 | @PrimaryKey var longitude: Double = 0.0, 17 | @ForeignKey var path: Path? = null) { 18 | 19 | companion object { 20 | @JvmField 21 | @MultiCacheField 22 | val cacheConverter = MultiKeyCacheConverter { values -> "${values[0]},${values[1]}" } 23 | } 24 | } 25 | 26 | @Table(database = TestDatabase::class) 27 | class Path(@PrimaryKey var id: String = "", 28 | @Column var name: String = "") -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/CachingModelsTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.TestDatabase 5 | import com.dbflow5.config.database 6 | import com.dbflow5.query.select 7 | import com.dbflow5.structure.save 8 | import org.junit.Assert.assertEquals 9 | import org.junit.Assert.assertNotEquals 10 | import org.junit.Test 11 | 12 | /** 13 | * Description: Tests to ensure caching works as expected. 14 | */ 15 | class CachingModelsTest : BaseUnitTest() { 16 | 17 | @Test 18 | fun testSimpleCache() { 19 | database { db -> 20 | val list = arrayListOf() 21 | (0..9).forEach { 22 | val simpleCacheObject = SimpleCacheObject("$it") 23 | simpleCacheObject.save(db) 24 | list += simpleCacheObject 25 | } 26 | 27 | val loadedList = (select from SimpleCacheObject::class).queryList(db) 28 | 29 | loadedList.forEachIndexed { index, simpleCacheObject -> 30 | assertEquals(list[index], simpleCacheObject) 31 | } 32 | } 33 | } 34 | 35 | @Test 36 | fun testComplexObject() { 37 | database { db -> 38 | val path = Path("1", "Path") 39 | path.save(db) 40 | 41 | val coordinate = Coordinate(40.5, 84.0, path) 42 | coordinate.save(db) 43 | 44 | val oldPath = coordinate.path 45 | 46 | val loadedCoordinate = (select from Coordinate::class).querySingle(db)!! 47 | assertEquals(coordinate, loadedCoordinate) 48 | 49 | // we want to ensure relationships reloaded. 50 | assertNotEquals(oldPath, loadedCoordinate.path) 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/CurrencyDAOTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.TestDatabase 5 | import com.dbflow5.config.database 6 | import com.dbflow5.rx2.RXTestRule 7 | import kotlinx.coroutines.test.runBlockingTest 8 | import org.junit.Before 9 | import org.junit.Rule 10 | import org.junit.Test 11 | 12 | class CurrencyDAOTest : BaseUnitTest() { 13 | 14 | lateinit var currencyDAO: CurrencyDAO 15 | 16 | val currency = Currency(symbol = "$", name = "United States Dollar", shortName = "USD") 17 | 18 | @Rule 19 | @JvmField 20 | val rxTestRule = RXTestRule() 21 | 22 | @Before 23 | fun setupTest() { 24 | currencyDAO = object : CurrencyDAO { 25 | override val database: TestDatabase = database() 26 | } 27 | } 28 | 29 | @Test 30 | fun validateCoroutine() = runBlockingTest { 31 | val success = currencyDAO.coroutineStoreUSD(currency).await() 32 | assert(success) { "Currency didn't save" } 33 | val result = currencyDAO.coroutineRetrieveUSD().await() 34 | assert(result.size == 1) { "Results list was empty" } 35 | assert(result[0] == currency) { "Expected ${currency} but got ${result[0]}" } 36 | } 37 | 38 | @Test 39 | fun validateRx() { 40 | val success = currencyDAO.rxStoreUSD(currency).blockingGet() 41 | assert(success) { "Currency didn't save" } 42 | val result = currencyDAO.rxRetrieveUSD().blockingGet() 43 | assert(result.size == 1) { "Results list was empty" } 44 | assert(result[0] == currency) { "Expected ${currency} but got ${result[0]}" } 45 | } 46 | 47 | 48 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/DontCreateModelTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.assertThrowsException 5 | import com.dbflow5.config.databaseForTable 6 | import com.dbflow5.database.SQLiteException 7 | import com.dbflow5.query.select 8 | import org.junit.Test 9 | 10 | /** 11 | * Description: 12 | */ 13 | class DontCreateModelTest : BaseUnitTest() { 14 | 15 | @Test 16 | fun testModelNotCreated() { 17 | databaseForTable { dbFlowDatabase -> 18 | assertThrowsException(SQLiteException::class) { 19 | (select from DontCreateModel::class).queryList(dbFlowDatabase) 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/IndexModels.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models 2 | 3 | import com.dbflow5.TestDatabase 4 | import com.dbflow5.annotation.Column 5 | import com.dbflow5.annotation.Index 6 | import com.dbflow5.annotation.IndexGroup 7 | import com.dbflow5.annotation.PrimaryKey 8 | import com.dbflow5.annotation.Table 9 | import java.util.* 10 | 11 | /** 12 | * Description: 13 | */ 14 | 15 | @Table(database = TestDatabase::class, 16 | indexGroups = [ 17 | IndexGroup(number = 1, name = "firstIndex"), 18 | IndexGroup(number = 2, name = "secondIndex"), 19 | IndexGroup(number = 3, name = "thirdIndex"), 20 | ]) 21 | class IndexModel { 22 | @Index(indexGroups = [1, 2, 3]) 23 | @PrimaryKey 24 | var id: Int = 0 25 | 26 | @Index(indexGroups = [1]) 27 | @Column 28 | var first_name: String? = null 29 | 30 | @Index(indexGroups = [2]) 31 | @Column 32 | var last_name: String? = null 33 | 34 | @Index(indexGroups = [3]) 35 | @Column 36 | var created_date: Date? = null 37 | 38 | @Index(indexGroups = [2, 3]) 39 | @Column 40 | var isPro: Boolean = false 41 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/InnerClassExample.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models 2 | 3 | import com.dbflow5.TestDatabase 4 | import com.dbflow5.annotation.PrimaryKey 5 | import com.dbflow5.annotation.Table 6 | 7 | /** 8 | * Example ensuring static inner classes work. 9 | */ 10 | class Outer { 11 | 12 | @Table(database = TestDatabase::class) 13 | class Inner(@PrimaryKey var id: Int = 0) 14 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/ManyToMany.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models 2 | 3 | import com.dbflow5.TestDatabase 4 | import com.dbflow5.annotation.Column 5 | import com.dbflow5.annotation.ManyToMany 6 | import com.dbflow5.annotation.PrimaryKey 7 | import com.dbflow5.annotation.Table 8 | 9 | @ManyToMany(referencedTable = Song::class) 10 | @Table(database = TestDatabase::class) 11 | class Artist(@PrimaryKey(autoincrement = true) var id: Int = 0, 12 | @Column var name: String = "") 13 | 14 | @Table(database = TestDatabase::class) 15 | class Song(@PrimaryKey(autoincrement = true) var id: Int = 0, 16 | @Column var name: String = "") -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/ManyToManyTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.config.databaseForTable 5 | import com.dbflow5.structure.save 6 | import org.junit.Assert.assertTrue 7 | import org.junit.Test 8 | 9 | class ManyToManyTest : BaseUnitTest() { 10 | 11 | @Test 12 | fun testCanCreateManyToMany() { 13 | databaseForTable { db -> 14 | val artist = Artist(name = "Andrew Grosner") 15 | val song = Song(name = "Livin' on A Prayer") 16 | 17 | artist.save(db) 18 | song.save(db) 19 | 20 | val artistSong = Artist_Song() 21 | artistSong.artist = artist 22 | artistSong.song = song 23 | assertTrue(artistSong.save(db)) 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/ModelViewTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.assertEquals 5 | import com.dbflow5.models.java.JavaModelView 6 | import org.junit.Test 7 | 8 | class ModelViewTest : BaseUnitTest() { 9 | 10 | @Test 11 | fun validateModelViewQuery() { 12 | "SELECT `id` AS `authorId`,`first_name` || ' ' || `last_name` AS `authorName` FROM `Author`" 13 | .assertEquals(AuthorView.getQuery()) 14 | } 15 | 16 | @Test 17 | fun validateJavaModelViewQuery() { 18 | "SELECT `first_name` AS `firstName`,`id` AS `id`".assertEquals(JavaModelView.getQuery()) 19 | } 20 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/ModelViews.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models 2 | 3 | import com.dbflow5.TestDatabase 4 | import com.dbflow5.annotation.Column 5 | import com.dbflow5.annotation.ColumnMap 6 | import com.dbflow5.annotation.ModelView 7 | import com.dbflow5.annotation.ModelViewQuery 8 | import com.dbflow5.models.Author_Table.* 9 | import com.dbflow5.query.From 10 | import com.dbflow5.query.property.IProperty 11 | import com.dbflow5.query.property.property 12 | import com.dbflow5.query.select 13 | 14 | class AuthorName(var name: String = "", var age: Int = 0) 15 | 16 | 17 | @ModelView(database = TestDatabase::class) 18 | class AuthorView(@Column var authorId: Int = 0, @Column var authorName: String = "", 19 | @ColumnMap var author: AuthorName? = null) { 20 | 21 | companion object { 22 | @JvmStatic 23 | @ModelViewQuery 24 | fun getQuery(): From = (select(id.`as`("authorId"), 25 | first_name.concatenate(" ".property as IProperty>) 26 | .concatenate(last_name as IProperty>) 27 | .`as`("authorName")) 28 | from Author::class) 29 | } 30 | } 31 | 32 | @ModelView(database = TestDatabase::class, priority = 2, allFields = true) 33 | class PriorityView(var name: String = "") { 34 | 35 | companion object { 36 | @JvmStatic 37 | @get:ModelViewQuery 38 | val query: From = select((first_name + last_name).`as`("name")) from Author::class 39 | } 40 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/NonTypical/nonTypicalClassName.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models.NonTypical 2 | 3 | import com.dbflow5.TestDatabase 4 | import com.dbflow5.annotation.PrimaryKey 5 | import com.dbflow5.annotation.Table 6 | 7 | /** 8 | * Tests package name capitalized, class name is lower cased. 9 | */ 10 | @Table(database = TestDatabase::class) 11 | class nonTypicalClassName(@PrimaryKey var id: Int = 0) -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/OneToManyModelTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.TestDatabase 5 | import com.dbflow5.config.database 6 | import com.dbflow5.query.select 7 | import com.dbflow5.structure.delete 8 | import com.dbflow5.structure.exists 9 | import com.dbflow5.structure.save 10 | import org.junit.Assert.* 11 | import org.junit.Test 12 | 13 | class OneToManyModelTest : BaseUnitTest() { 14 | 15 | @Test 16 | fun testOneToManyModel() { 17 | database(TestDatabase::class) { db -> 18 | var testModel2 = TwoColumnModel("Greater", 4) 19 | testModel2.save(db) 20 | 21 | testModel2 = TwoColumnModel("Lesser", 1) 22 | testModel2.save(db) 23 | 24 | // assert we save 25 | var oneToManyModel = OneToManyModel("HasOrders") 26 | oneToManyModel.save(db) 27 | assertTrue(oneToManyModel.exists(db)) 28 | 29 | // assert loading works as expected. 30 | oneToManyModel = (select from OneToManyModel::class).requireSingle(db) 31 | assertNotNull(oneToManyModel.getRelatedOrders(db)) 32 | assertTrue(!oneToManyModel.getRelatedOrders(db).isEmpty()) 33 | 34 | // assert the deletion cleared the variable 35 | oneToManyModel.delete(db) 36 | assertFalse(oneToManyModel.exists(db)) 37 | assertNull(oneToManyModel.orders) 38 | 39 | // assert singular relationship was deleted. 40 | val list = (select from TwoColumnModel::class).queryList(db) 41 | assertTrue(list.size == 1) 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/ParentChildCachingTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.TestDatabase 5 | import com.dbflow5.config.database 6 | import com.dbflow5.query.select 7 | import org.junit.Assert.assertEquals 8 | import org.junit.Test 9 | 10 | /** 11 | * Description: 12 | */ 13 | class ParentChildCachingTest : BaseUnitTest() { 14 | 15 | 16 | @Test 17 | fun testCanLoadChildFromCache() { 18 | database { db -> 19 | val child = TestModelChild() 20 | child.id = 1 21 | child.name = "Test child" 22 | child.save(db) 23 | 24 | var parent = TestModelParent() 25 | parent.id = 1 26 | parent.name = "Test parent" 27 | parent.child = child 28 | parent.save(db) 29 | 30 | parent = (select from TestModelParent::class).requireSingle(db) 31 | var parentChild = parent.child!! 32 | parentChild = parentChild.load(db)!! 33 | 34 | assertEquals(1, parentChild.id) 35 | assertEquals("Test child", parentChild.name) 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/QueryModelTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.TestDatabase 5 | import com.dbflow5.config.database 6 | import com.dbflow5.models.Author_Table.id 7 | import com.dbflow5.models.Blog_Table.author_id 8 | import com.dbflow5.models.Blog_Table.name 9 | import com.dbflow5.query.select 10 | import com.dbflow5.structure.exists 11 | import com.dbflow5.structure.save 12 | import org.junit.Assert.assertEquals 13 | import org.junit.Test 14 | 15 | /** 16 | * Description: Tests to ensure we can load a Query model from the DB 17 | */ 18 | class QueryModelTest : BaseUnitTest() { 19 | 20 | @Test 21 | fun testCanLoadAuthorBlogs() { 22 | database { db -> 23 | val author = Author(0, "Andrew", "Grosner") 24 | author.save(db) 25 | val blog = Blog(0, "My First Blog", author) 26 | blog.save(db) 27 | 28 | assert(author.exists(db)) 29 | assert(blog.exists(db)) 30 | 31 | val result = (select(name.withTable().`as`("blogName"), id.withTable().`as`("authorId"), 32 | Blog_Table.id.withTable().`as`("blogId")) from Blog::class innerJoin 33 | Author::class on (author_id.withTable() eq id.withTable())) 34 | .queryCustomSingle(AuthorNameQuery::class.java, db)!! 35 | assertEquals(author.id, result.authorId) 36 | assertEquals(blog.id, result.blogId) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/QueryModels.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models 2 | 3 | import com.dbflow5.TestDatabase 4 | import com.dbflow5.annotation.Column 5 | import com.dbflow5.annotation.QueryModel 6 | import com.dbflow5.converter.TypeConverter 7 | import com.dbflow5.data.Blob 8 | 9 | @QueryModel(database = TestDatabase::class, allFields = true) 10 | class AuthorNameQuery(var blogName: String = "", 11 | var authorId: Int = 0, var blogId: Int = 0) 12 | 13 | 14 | @QueryModel(database = TestDatabase::class) 15 | class CustomBlobModel(@Column var myBlob: MyBlob? = null) { 16 | 17 | class MyBlob(val blob: ByteArray) 18 | 19 | @com.dbflow5.annotation.TypeConverter 20 | class MyTypeConverter : TypeConverter() { 21 | 22 | override fun getDBValue(model: MyBlob?) = model?.let { Blob(model.blob) } 23 | 24 | override fun getModelValue(data: Blob?) = data?.blob?.let { MyBlob(it) } 25 | } 26 | } 27 | 28 | @QueryModel(database = TestDatabase::class, allFields = true) 29 | class AllFieldsQueryModel(var fieldModel: String? = null) -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/SimpleTestModelsTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.config.modelAdapter 5 | import org.junit.Assert.assertEquals 6 | import org.junit.Test 7 | 8 | /** 9 | * Description: 10 | */ 11 | class SimpleTestModelsTest : BaseUnitTest() { 12 | 13 | @Test 14 | fun validateCreationQuery() { 15 | assertEquals("CREATE TABLE IF NOT EXISTS `TypeConverterModel`(" + 16 | "`id` INTEGER, " + 17 | "`opaqueData` BLOB, " + 18 | "`blob` BLOB, " + 19 | "`customType` INTEGER, " + 20 | "PRIMARY KEY(`id`, `customType`))", modelAdapter().creationQuery) 21 | } 22 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/TempModelTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.TestDatabase 5 | import com.dbflow5.adapter.createIfNotExists 6 | import com.dbflow5.adapter.drop 7 | import com.dbflow5.annotation.PrimaryKey 8 | import com.dbflow5.annotation.Table 9 | import com.dbflow5.config.database 10 | import com.dbflow5.config.modelAdapter 11 | import com.dbflow5.structure.save 12 | import org.junit.Test 13 | 14 | 15 | @Table(database = TestDatabase::class, temporary = true, createWithDatabase = false) 16 | class TempModel(@PrimaryKey var id: Int = 0) 17 | 18 | class TempModelTest: BaseUnitTest() { 19 | 20 | @Test 21 | fun createTempTable() { 22 | database { db -> 23 | modelAdapter().createIfNotExists(db) 24 | 25 | TempModel(id = 5).save(db) 26 | 27 | modelAdapter().drop(db) 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/java/DatabaseModel.java: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models.java; 2 | 3 | import com.dbflow5.annotation.PrimaryKey; 4 | import com.dbflow5.structure.BaseModel; 5 | 6 | public class DatabaseModel extends BaseModel { 7 | @PrimaryKey 8 | private Integer id; 9 | 10 | public Integer getId() { 11 | return id; 12 | } 13 | 14 | public void setId(Integer id) { 15 | this.id = id; 16 | } 17 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/java/JavaModel.java: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models.java; 2 | 3 | import com.dbflow5.TestDatabase; 4 | import com.dbflow5.annotation.PrimaryKey; 5 | import com.dbflow5.annotation.Table; 6 | 7 | @Table(database = TestDatabase.class) 8 | public class JavaModel { 9 | 10 | @PrimaryKey 11 | String id; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/java/JavaModelView.java: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models.java; 2 | 3 | import com.dbflow5.TestDatabase; 4 | import com.dbflow5.annotation.Column; 5 | import com.dbflow5.annotation.ModelView; 6 | import com.dbflow5.annotation.ModelViewQuery; 7 | import com.dbflow5.database.DatabaseWrapper; 8 | import com.dbflow5.models.Author_Table; 9 | import com.dbflow5.query.SQLite; 10 | import com.dbflow5.sql.Query; 11 | 12 | @ModelView(database = TestDatabase.class) 13 | public class JavaModelView { 14 | 15 | @ModelViewQuery 16 | public static Query getQuery() { 17 | return SQLite.select(Author_Table.first_name.as("firstName"), Author_Table.id.as("id")); 18 | } 19 | 20 | @Column 21 | String id; 22 | 23 | @Column 24 | Integer firstName; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/models/java/otherpackage/ExampleModel.java: -------------------------------------------------------------------------------- 1 | package com.dbflow5.models.java.otherpackage; 2 | 3 | import com.dbflow5.TestDatabase; 4 | import com.dbflow5.annotation.Column; 5 | import com.dbflow5.annotation.ForeignKey; 6 | import com.dbflow5.annotation.Table; 7 | import com.dbflow5.models.java.DatabaseModel; 8 | import com.dbflow5.models.java.JavaModel; 9 | 10 | @Table(database = TestDatabase.class) 11 | public class ExampleModel extends DatabaseModel { 12 | @Column 13 | String name; 14 | 15 | @ForeignKey 16 | JavaModel model; 17 | } 18 | -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/prepackaged/PrepackagedDB.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.prepackaged 2 | 3 | import com.dbflow5.annotation.Column 4 | import com.dbflow5.annotation.Database 5 | import com.dbflow5.annotation.Migration 6 | import com.dbflow5.annotation.PrimaryKey 7 | import com.dbflow5.annotation.Table 8 | import com.dbflow5.config.DBFlowDatabase 9 | import com.dbflow5.database.DatabaseWrapper 10 | import com.dbflow5.migration.AlterTableMigration 11 | import com.dbflow5.migration.BaseMigration 12 | import com.dbflow5.sql.SQLiteType 13 | import com.dbflow5.structure.BaseModel 14 | 15 | @Database(version = 1) 16 | abstract class PrepackagedDB : DBFlowDatabase() 17 | 18 | @Database(version = 2) 19 | abstract class MigratedPrepackagedDB : DBFlowDatabase() { 20 | 21 | @Migration(version = 2, database = MigratedPrepackagedDB::class, priority = 1) 22 | class AddNewFieldMigration : AlterTableMigration(Dog2::class) { 23 | override fun onPreMigrate() { 24 | addColumn(SQLiteType.TEXT, "newField") 25 | } 26 | } 27 | 28 | @Migration(version = 2, database = MigratedPrepackagedDB::class, priority = 2) 29 | class AddSomeDataMigration : BaseMigration() { 30 | override fun migrate(database: DatabaseWrapper) { 31 | Dog2(breed = "NewBreed", newField = "New Field Data").insert(database) 32 | } 33 | } 34 | 35 | } 36 | 37 | @Table(database = PrepackagedDB::class, allFields = true) 38 | class Dog( 39 | @PrimaryKey var id: Int = 0, 40 | @Column var breed: String? = null, 41 | @Column var color: String? = null, 42 | ) : BaseModel() 43 | 44 | @Table(database = MigratedPrepackagedDB::class, allFields = true, name = "Dog") 45 | class Dog2( 46 | @PrimaryKey var id: Int = 0, 47 | @Column var breed: String? = null, 48 | @Column var color: String? = null, 49 | @Column var newField: String? = null, 50 | ) : BaseModel() 51 | -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/prepackaged/PrepackagedDBTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.prepackaged 2 | 3 | import com.dbflow5.DBFlowInstrumentedTestRule 4 | import com.dbflow5.DemoApp 5 | import com.dbflow5.config.database 6 | import com.dbflow5.database.AndroidSQLiteOpenHelper 7 | import com.dbflow5.query.select 8 | import org.junit.Assert.assertTrue 9 | import org.junit.Rule 10 | import org.junit.Test 11 | 12 | /** 13 | * Description: Asserts our prepackaged DB loads. 14 | */ 15 | class PrepackagedDBTest { 16 | 17 | @JvmField 18 | @Rule 19 | var dblflowTestRule = DBFlowInstrumentedTestRule.create { 20 | database({ 21 | databaseName("prepackaged") 22 | }, AndroidSQLiteOpenHelper.createHelperCreator(DemoApp.context)) 23 | database({ 24 | databaseName("prepackaged_2") 25 | }, AndroidSQLiteOpenHelper.createHelperCreator(DemoApp.context)) 26 | } 27 | 28 | @Test 29 | fun assertWeCanLoadFromDB() { 30 | database { db -> 31 | val list = (select from Dog::class).queryList(db) 32 | assertTrue(list.isNotEmpty()) 33 | } 34 | } 35 | 36 | @Test 37 | fun assertWeCanLoadFromDBPostMigrate() { 38 | database { db -> 39 | val list = (select from Dog2::class).queryList(db) 40 | assertTrue(list.isNotEmpty()) 41 | 42 | val newData = (select 43 | from Dog2::class 44 | where Dog2_Table.breed.eq("NewBreed") 45 | and Dog2_Table.newField.eq("New Field Data")) 46 | .querySingle(db) 47 | assertTrue(newData != null) 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/query/cache/ModelLruCacheTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query.cache 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.models.NumberModel 5 | import org.junit.Assert 6 | import org.junit.Test 7 | 8 | class ModelLruCacheTest : BaseUnitTest() { 9 | 10 | 11 | @Test 12 | fun validateCacheAddRemove() { 13 | val cache = SimpleMapCache(10) 14 | cache.addModel(1, NumberModel(1)) 15 | 16 | Assert.assertEquals(1, cache[1]!!.id) 17 | Assert.assertEquals(1, cache.cache.size) 18 | 19 | cache.removeModel(1) 20 | 21 | Assert.assertTrue(cache.cache.isEmpty()) 22 | } 23 | 24 | @Test 25 | fun validateCacheClear() { 26 | val cache = SimpleMapCache(10) 27 | cache.addModel(1, NumberModel(1)) 28 | cache.addModel(2, NumberModel(2)) 29 | Assert.assertEquals(2, cache.cache.size) 30 | 31 | cache.clear() 32 | 33 | Assert.assertTrue(cache.cache.isEmpty()) 34 | } 35 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/query/cache/SimpleMapCacheTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.query.cache 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.models.SimpleModel 5 | import org.junit.Assert.assertEquals 6 | import org.junit.Assert.assertTrue 7 | import org.junit.Test 8 | 9 | class SimpleMapCacheTest : BaseUnitTest() { 10 | 11 | @Test 12 | fun validateCacheAddRemove() { 13 | val cache = SimpleMapCache(10) 14 | cache.addModel("1", SimpleModel("1")) 15 | 16 | assertEquals("1", cache["1"]!!.name) 17 | assertEquals(1, cache.cache.size) 18 | 19 | cache.removeModel("1") 20 | 21 | assertTrue(cache.cache.isEmpty()) 22 | } 23 | 24 | @Test 25 | fun validateCacheClear() { 26 | val cache = SimpleMapCache(10) 27 | cache.addModel("1", SimpleModel("1")) 28 | cache.addModel("2", SimpleModel("2")) 29 | assertEquals(2, cache.cache.size) 30 | 31 | cache.clear() 32 | 33 | assertTrue(cache.cache.isEmpty()) 34 | } 35 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/rx2/RXTestRule.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.rx2 2 | 3 | import io.reactivex.rxjava3.plugins.RxJavaPlugins 4 | import io.reactivex.rxjava3.schedulers.Schedulers 5 | import org.junit.rules.TestRule 6 | import org.junit.runner.Description 7 | import org.junit.runners.model.Statement 8 | 9 | class RXTestRule : TestRule { 10 | 11 | override fun apply(base: Statement, description: Description): Statement { 12 | return object : Statement() { 13 | override fun evaluate() { 14 | RxJavaPlugins.setComputationSchedulerHandler { Schedulers.trampoline() } 15 | RxJavaPlugins.setIoSchedulerHandler { Schedulers.trampoline() } 16 | } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/rx2/query/RxModels.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.rx2.query 2 | 3 | import com.dbflow5.TestDatabase 4 | import com.dbflow5.annotation.PrimaryKey 5 | import com.dbflow5.annotation.Table 6 | import com.dbflow5.reactivestreams.structure.BaseRXModel 7 | 8 | 9 | @Table(database = TestDatabase::class, allFields = true) 10 | class SimpleRXModel(@PrimaryKey var id: String = "") : BaseRXModel() -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sql/language/CaseTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sql.language 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.models.SimpleModel_Table 5 | import com.dbflow5.query.case 6 | import com.dbflow5.query.caseWhen 7 | import com.dbflow5.query.property.propertyString 8 | import org.junit.Assert.* 9 | import org.junit.Test 10 | 11 | class CaseTest : BaseUnitTest() { 12 | 13 | @Test 14 | fun simpleCaseTest() { 15 | val case = case(propertyString("country")) 16 | .whenever("USA") 17 | .then("Domestic") 18 | .`else`("Foreign") 19 | assertEquals("CASE country WHEN 'USA' THEN 'Domestic' ELSE 'Foreign' END `Country`", 20 | case.end("Country").query.trim()) 21 | assertTrue(case.isEfficientCase) 22 | } 23 | 24 | @Test 25 | fun searchedCaseTest() { 26 | val case = caseWhen(SimpleModel_Table.name.eq("USA")).then("Domestic") 27 | .whenever(SimpleModel_Table.name.eq("CA")).then("Canada") 28 | .`else`("Foreign") 29 | assertEquals("CASE WHEN `name`='USA' THEN 'Domestic' WHEN `name`='CA' THEN 'Canada' ELSE 'Foreign'", 30 | case.query.trim()) 31 | assertFalse(case.isEfficientCase) 32 | } 33 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sql/language/DeleteTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sql.language 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.config.databaseForTable 5 | import com.dbflow5.models.SimpleModel 6 | import com.dbflow5.models.SimpleModel_Table 7 | import com.dbflow5.query.delete 8 | import com.dbflow5.query.select 9 | import com.dbflow5.structure.save 10 | import org.junit.Assert.assertEquals 11 | import org.junit.Assert.assertFalse 12 | import org.junit.Test 13 | 14 | class DeleteTest : BaseUnitTest() { 15 | 16 | @Test 17 | fun validateQuery() { 18 | assertEquals("DELETE ", delete().query) 19 | } 20 | 21 | @Test 22 | fun validateDeletion() { 23 | databaseForTable { db -> 24 | SimpleModel("name").save(db) 25 | delete().execute(db) 26 | assertFalse((select from SimpleModel::class).hasData(db)) 27 | } 28 | } 29 | 30 | @Test 31 | fun validateDeletionWithQuery() { 32 | databaseForTable { db -> 33 | SimpleModel("name").save(db) 34 | SimpleModel("another name").save(db) 35 | 36 | val where = delete().where(SimpleModel_Table.name.`is`("name")) 37 | assertEquals("DELETE FROM `SimpleModel` WHERE `name`='name'", where.query.trim()) 38 | where.execute(db) 39 | 40 | assertEquals(1, (select from SimpleModel::class).queryList(db).size) 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sql/language/ExistenceOperatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sql.language 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.models.SimpleModel 5 | import com.dbflow5.models.SimpleModel_Table 6 | import com.dbflow5.query.ExistenceOperator 7 | import com.dbflow5.query.select 8 | import org.junit.Assert.assertEquals 9 | import org.junit.Test 10 | 11 | class ExistenceOperatorTest : BaseUnitTest() { 12 | 13 | 14 | @Test 15 | fun validateQuery() { 16 | assertEquals("EXISTS (SELECT * FROM `SimpleModel` WHERE `name`='name')", 17 | ExistenceOperator( 18 | (select from SimpleModel::class 19 | where SimpleModel_Table.name.eq("name"))) 20 | .query.trim()) 21 | } 22 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sql/language/FromTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sql.language 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.models.SimpleModel 5 | import com.dbflow5.models.SimpleModel_Table.name 6 | import com.dbflow5.models.TwoColumnModel 7 | import com.dbflow5.models.TwoColumnModel_Table 8 | import com.dbflow5.models.TwoColumnModel_Table.id 9 | import com.dbflow5.query.select 10 | import org.junit.Assert.assertEquals 11 | import org.junit.Assert.assertTrue 12 | import org.junit.Test 13 | 14 | class FromTest : BaseUnitTest() { 15 | 16 | @Test 17 | fun validateSimpleFrom() { 18 | assertEquals("SELECT * FROM `SimpleModel`", (select from SimpleModel::class).query.trim()) 19 | } 20 | 21 | @Test 22 | fun validateProjectionFrom() { 23 | assertEquals("SELECT `name` FROM `SimpleModel`", (select(name) from SimpleModel::class).query.trim()) 24 | } 25 | 26 | @Test 27 | fun validateMultipleProjection() { 28 | assertEquals("SELECT `name`,`name`,`id` FROM `SimpleModel`", 29 | (select(name, TwoColumnModel_Table.name, id) from SimpleModel::class).query.trim()) 30 | } 31 | 32 | @Test 33 | fun validateAlias() { 34 | assertEquals("SELECT * FROM `SimpleModel` AS `Simple`", (select from SimpleModel::class `as` "Simple").query.trim()) 35 | } 36 | 37 | @Test 38 | fun validateJoins() { 39 | val from = (select from SimpleModel::class 40 | innerJoin TwoColumnModel::class 41 | on name.eq(TwoColumnModel_Table.name.withTable())) 42 | assertEquals("SELECT * FROM `SimpleModel` INNER JOIN `TwoColumnModel` ON `name`=`TwoColumnModel`.`name`", 43 | from.query.trim()) 44 | assertTrue(from.associatedTables.isNotEmpty()) 45 | } 46 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sql/language/IndexTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sql.language 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.models.SimpleModel 5 | import com.dbflow5.models.SimpleModel_Table 6 | import com.dbflow5.query.indexOn 7 | import com.dbflow5.query.nameAlias 8 | import org.junit.Assert.assertEquals 9 | import org.junit.Test 10 | 11 | class IndexTest : BaseUnitTest() { 12 | 13 | @Test 14 | fun validateBasicIndex() { 15 | assertEquals("CREATE INDEX IF NOT EXISTS `index` ON `SimpleModel`(`name`)", 16 | indexOn("index", SimpleModel_Table.name).query) 17 | } 18 | 19 | @Test 20 | fun validateUniqueIndex() { 21 | assertEquals("CREATE UNIQUE INDEX IF NOT EXISTS `index` ON `SimpleModel`(`name`, `test`)", 22 | indexOn("index").unique(true).and(SimpleModel_Table.name) 23 | .and("test".nameAlias).query) 24 | } 25 | 26 | @Test 27 | fun validateBasicIndexNameAlias() { 28 | assertEquals("CREATE INDEX IF NOT EXISTS `index` ON `SimpleModel`(`name`, `test`)", 29 | indexOn("index", "name".nameAlias, "test".nameAlias).query) 30 | } 31 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sql/language/IndexedByTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sql.language 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.models.SimpleModel 5 | import com.dbflow5.models.SimpleModel_Table 6 | import com.dbflow5.query.property.IndexProperty 7 | import com.dbflow5.query.select 8 | import org.junit.Assert.assertEquals 9 | import org.junit.Test 10 | 11 | class IndexedByTest : BaseUnitTest() { 12 | 13 | @Test 14 | fun validateQuery() { 15 | val indexed = (select from SimpleModel::class) 16 | .indexedBy(IndexProperty("Index", false, SimpleModel::class.java, SimpleModel_Table.name)) 17 | assertEquals("SELECT * FROM `SimpleModel` INDEXED BY `Index`", indexed.query.trim()) 18 | } 19 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sql/language/NameAliasTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sql.language 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.query.NameAlias 5 | import com.dbflow5.query.`as` 6 | import com.dbflow5.query.nameAlias 7 | import org.junit.Assert.assertEquals 8 | import org.junit.Assert.assertFalse 9 | import org.junit.Test 10 | 11 | class NameAliasTest : BaseUnitTest() { 12 | 13 | @Test 14 | fun testSimpleCase() { 15 | assertEquals("`name`", "name".nameAlias.query) 16 | } 17 | 18 | @Test 19 | fun testAlias() { 20 | assertEquals("`name` AS `alias`", "name".`as`("alias").fullQuery) 21 | } 22 | 23 | @Test 24 | fun validateBuilder() { 25 | val nameAlias = NameAlias.builder("name") 26 | .keyword("DISTINCT") 27 | .`as`("Alias") 28 | .withTable("MyTable") 29 | .shouldAddIdentifierToAliasName(false) 30 | .shouldAddIdentifierToName(false) 31 | .shouldStripAliasName(false) 32 | .shouldStripIdentifier(false).build() 33 | assertEquals("DISTINCT", nameAlias.keyword) 34 | assertEquals("Alias", nameAlias.aliasName()) 35 | assertEquals("Alias", nameAlias.aliasNameRaw()) 36 | assertEquals("`MyTable`", nameAlias.tableName) 37 | assertFalse(nameAlias.shouldStripAliasName) 38 | assertFalse(nameAlias.shouldStripIdentifier) 39 | assertEquals("Alias", nameAlias.nameAsKey) 40 | assertEquals("DISTINCT `MyTable`.name AS Alias", nameAlias.fullQuery) 41 | } 42 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sql/language/OperatorGroupTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sql.language 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.assertEquals 5 | import com.dbflow5.models.TwoColumnModel_Table.id 6 | import com.dbflow5.models.TwoColumnModel_Table.name 7 | import com.dbflow5.query.OperatorGroup 8 | import com.dbflow5.query.and 9 | import com.dbflow5.query.andAll 10 | import com.dbflow5.query.or 11 | import com.dbflow5.query.orAll 12 | import org.junit.Test 13 | 14 | class OperatorGroupTest : BaseUnitTest() { 15 | 16 | 17 | @Test 18 | fun validateCommaSeparated() { 19 | "(`name`='name', `id`=0)".assertEquals(OperatorGroup.clause().setAllCommaSeparated(true).andAll(name.eq("name"), id.eq(0))) 20 | } 21 | 22 | @Test 23 | fun validateParanthesis() { 24 | "`name`='name'".assertEquals(OperatorGroup.nonGroupingClause(name.eq("name")).setUseParenthesis(false)) 25 | } 26 | 27 | @Test 28 | fun validateOr() { 29 | "(`name`='name' OR `id`=0)".assertEquals(name.eq("name") or id.eq(0)) 30 | } 31 | 32 | @Test 33 | fun validateOrAll() { 34 | "(`name`='name' OR `id`=0 OR `name`='test')".assertEquals(name.eq("name") orAll arrayListOf(id.eq(0), name.eq("test"))) 35 | } 36 | 37 | @Test 38 | 39 | fun validateAnd() { 40 | "(`name`='name' AND `id`=0)".assertEquals(name.eq("name") and id.eq(0)) 41 | } 42 | 43 | @Test 44 | fun validateAndAll() { 45 | "(`name`='name' AND `id`=0 AND `name`='test')".assertEquals(name.eq("name") andAll arrayListOf(id.eq(0), name.eq("test"))) 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sql/language/OrderByTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sql.language 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.annotation.Collate 5 | import com.dbflow5.assertEquals 6 | import com.dbflow5.models.SimpleModel_Table.name 7 | import com.dbflow5.query.OrderBy 8 | import com.dbflow5.query.nameAlias 9 | import org.junit.Test 10 | 11 | class OrderByTest : BaseUnitTest() { 12 | 13 | 14 | @Test 15 | fun validateBasicOrderBy() { 16 | "`name` ASC".assertEquals(OrderBy.fromProperty(name).ascending()) 17 | } 18 | 19 | @Test 20 | fun validateDescendingOrderBy() { 21 | "`name` DESC".assertEquals(OrderBy.fromNameAlias("name".nameAlias).descending()) 22 | } 23 | 24 | @Test 25 | fun validateCollate() { 26 | "`name` COLLATE RTRIM ASC".assertEquals(OrderBy.fromProperty(name).ascending() collate Collate.RTRIM) 27 | } 28 | 29 | @Test 30 | fun validateCustomOrdrBy() { 31 | "`name` ASC This is custom".assertEquals(OrderBy.fromString("`name` ASC This is custom")) 32 | } 33 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sql/language/SelectTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sql.language 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.assertEquals 5 | import com.dbflow5.models.SimpleModel 6 | import com.dbflow5.models.TwoColumnModel 7 | import com.dbflow5.models.TwoColumnModel_Table.id 8 | import com.dbflow5.models.TwoColumnModel_Table.name 9 | import com.dbflow5.query.select 10 | import org.junit.Test 11 | 12 | class SelectTest : BaseUnitTest() { 13 | 14 | @Test 15 | fun validateSelect() { 16 | "SELECT `name`,`id` FROM `TwoColumnModel`".assertEquals(select(name, id) from TwoColumnModel::class) 17 | } 18 | 19 | @Test 20 | fun validateSelectDistinct() { 21 | "SELECT DISTINCT `name` FROM `SimpleModel`".assertEquals(select(name).distinct() from SimpleModel::class) 22 | } 23 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sql/language/SetTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sql.language 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.assertEquals 5 | import com.dbflow5.models.SimpleModel 6 | import com.dbflow5.models.SimpleModel_Table.name 7 | import com.dbflow5.models.TwoColumnModel_Table.id 8 | import com.dbflow5.query.set 9 | import com.dbflow5.query.update 10 | import org.junit.Test 11 | 12 | class SetTest : BaseUnitTest() { 13 | 14 | @Test 15 | fun validateSetWithConditions() { 16 | "UPDATE `SimpleModel` SET `name`='name'".assertEquals(update() set name.`is`("name")) 17 | } 18 | 19 | @Test 20 | fun validateMultipleConditions() { 21 | "UPDATE `SimpleModel` SET `name`='name', `id`=0".assertEquals(update() set name.eq("name") and id.eq(0)) 22 | } 23 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sql/language/UnsafeStringOperatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sql.language 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.assertEquals 5 | import com.dbflow5.models.SimpleModel 6 | import com.dbflow5.query.UnSafeStringOperator 7 | import com.dbflow5.query.select 8 | import org.junit.Test 9 | 10 | class UnsafeStringOperatorTest : BaseUnitTest() { 11 | 12 | @Test 13 | fun testCanIncludeInQuery() { 14 | val op = UnSafeStringOperator("name = ?, id = ?, test = ?", arrayOf("'name'", "0", "'test'")) 15 | "name = 'name', id = 0, test = 'test'".assertEquals(op) 16 | "SELECT * FROM `SimpleModel` WHERE name = 'name', id = 0, test = 'test'".assertEquals(select from SimpleModel::class where op) 17 | } 18 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sql/language/UpdateTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sql.language 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.annotation.ConflictAction 5 | import com.dbflow5.assertEquals 6 | import com.dbflow5.models.NumberModel 7 | import com.dbflow5.models.NumberModel_Table.id 8 | import com.dbflow5.models.SimpleModel 9 | import com.dbflow5.models.SimpleModel_Table.name 10 | import com.dbflow5.query.property.Property 11 | import com.dbflow5.query.set 12 | import com.dbflow5.query.update 13 | import org.junit.Test 14 | 15 | class UpdateTest : BaseUnitTest() { 16 | 17 | @Test 18 | fun validateUpdateRollback() { 19 | "UPDATE OR ROLLBACK `SimpleModel`".assertEquals(update().orRollback()) 20 | } 21 | 22 | @Test 23 | fun validateUpdateFail() { 24 | "UPDATE OR FAIL `SimpleModel`".assertEquals(update().orFail()) 25 | } 26 | 27 | @Test 28 | fun validateUpdateIgnore() { 29 | "UPDATE OR IGNORE `SimpleModel`".assertEquals(update().orIgnore()) 30 | } 31 | 32 | @Test 33 | fun validateUpdateReplace() { 34 | "UPDATE OR REPLACE `SimpleModel`".assertEquals(update().orReplace()) 35 | } 36 | 37 | @Test 38 | fun validateUpdateAbort() { 39 | "UPDATE OR ABORT `SimpleModel`".assertEquals(update().orAbort()) 40 | } 41 | 42 | @Test 43 | fun validateSetQuery() { 44 | "UPDATE `SimpleModel` SET `name`='name'".assertEquals(update() set (name eq "name")) 45 | } 46 | 47 | @Test 48 | fun validateWildcardQuery() { 49 | "UPDATE OR FAIL `NumberModel` SET `id`=? WHERE `id`=?".assertEquals(update().or(ConflictAction.FAIL) 50 | .set(id.eq(Property.WILDCARD)) 51 | .where(id.eq(Property.WILDCARD))) 52 | } 53 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sql/language/property/IndexPropertyTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sql.language.property 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.config.databaseForTable 5 | import com.dbflow5.models.SimpleModel 6 | import com.dbflow5.models.SimpleModel_Table 7 | import com.dbflow5.query.property.IndexProperty 8 | import org.junit.Assert.assertEquals 9 | import org.junit.Test 10 | 11 | class IndexPropertyTest : BaseUnitTest() { 12 | 13 | 14 | @Test 15 | fun validateIndexProperty() { 16 | databaseForTable { db -> 17 | val prop = IndexProperty("Index", true, SimpleModel::class.java, 18 | SimpleModel_Table.name) 19 | prop.createIfNotExists(db) 20 | prop.drop(db) 21 | assertEquals("`Index`", prop.indexName) 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sql/language/property/PropertyFactoryTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sql.language.property 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.models.SimpleModel 5 | import com.dbflow5.query.property.property 6 | import com.dbflow5.query.property.propertyString 7 | import com.dbflow5.query.select 8 | import org.junit.Assert.assertEquals 9 | import org.junit.Test 10 | 11 | class PropertyFactoryTest : BaseUnitTest() { 12 | 13 | @Test 14 | fun testPrimitives() { 15 | assertEquals("'c'", 'c'.property.query) 16 | assertEquals("5", 5.property.query) 17 | assertEquals("5.0", 5.0.property.query) 18 | assertEquals("5.0", 5.0f.property.query) 19 | assertEquals("5", 5L.property.query) 20 | assertEquals("5", 5.toShort().property.query) 21 | assertEquals("5", 5.toByte().property.query) 22 | val nullable: Any? = null 23 | assertEquals("NULL", nullable.property.query) 24 | assertEquals("(SELECT * FROM `SimpleModel`)", (select from SimpleModel::class).property.query) 25 | assertEquals("SomethingCool", propertyString("SomethingCool").query) 26 | } 27 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sql/language/property/TypeConvertedPropertyTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sql.language.property 2 | 3 | import com.dbflow5.BaseUnitTest 4 | import com.dbflow5.converter.DateConverter 5 | import com.dbflow5.converter.TypeConverter 6 | import com.dbflow5.models.Difficulty 7 | import com.dbflow5.models.EnumTypeConverterModel_Table 8 | import com.dbflow5.models.SimpleModel 9 | import com.dbflow5.query.NameAlias 10 | import com.dbflow5.query.property.TypeConvertedProperty 11 | import org.junit.Assert.assertEquals 12 | import org.junit.Test 13 | import java.util.* 14 | 15 | class TypeConvertedPropertyTest : BaseUnitTest() { 16 | 17 | 18 | @Test 19 | fun testTypeConverter() { 20 | val property = TypeConvertedProperty(SimpleModel::class.java, "Prop", true, 21 | object : TypeConvertedProperty.TypeConverterGetter { 22 | override fun getTypeConverter(modelClass: Class<*>): TypeConverter<*, *> = DateConverter() 23 | }) 24 | assertEquals("`Prop`", property.toString()) 25 | 26 | val date = Date() 27 | assertEquals("`Prop`=${date.time}", property.eq(date).query) 28 | 29 | assertEquals("`SimpleModel`.`Prop`=${date.time}", property.withTable().eq(date).query) 30 | 31 | val inverted = property.invertProperty() 32 | assertEquals("`Prop`=5050505", inverted.eq(5050505).query) 33 | } 34 | 35 | @Test 36 | fun testCustomEnumTypeConverter() { 37 | 38 | assertEquals("`difficulty`='H'", EnumTypeConverterModel_Table.difficulty.eq(Difficulty.HARD).query) 39 | assertEquals("`EnumTypeConverterModel`.`difficulty`='H'", EnumTypeConverterModel_Table.difficulty.withTable().eq(Difficulty.HARD).query) 40 | assertEquals("`et`.`difficulty`='H'", EnumTypeConverterModel_Table.difficulty.withTable(NameAlias.tableNameBuilder("et").build()).eq(Difficulty.HARD).query) 41 | } 42 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sqlcipher/CipherDatabase.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sqlcipher 2 | 3 | import com.dbflow5.annotation.Database 4 | import com.dbflow5.config.DBFlowDatabase 5 | 6 | @Database(version = 1) 7 | abstract class CipherDatabase : DBFlowDatabase() -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sqlcipher/CipherTest.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sqlcipher 2 | 3 | import com.dbflow5.DBFlowInstrumentedTestRule 4 | import com.dbflow5.DemoApp 5 | import com.dbflow5.config.database 6 | import com.dbflow5.query.delete 7 | import com.dbflow5.query.select 8 | import org.junit.Assert.assertTrue 9 | import org.junit.Rule 10 | import org.junit.Test 11 | 12 | /** 13 | * Description: Ensures we can use SQLCipher 14 | */ 15 | class CipherTest { 16 | 17 | @JvmField 18 | @Rule 19 | var dblflowTestRule = DBFlowInstrumentedTestRule.create { 20 | database(openHelperCreator = SQLCipherOpenHelper.createHelperCreator(DemoApp.context, "dbflow-rules")) 21 | } 22 | 23 | @Test 24 | fun testCipherModel() { 25 | database { db -> 26 | (delete() from CipherModel::class).execute(db) 27 | val model = CipherModel(name = "name") 28 | model.save(db) 29 | assertTrue(model.exists(db)) 30 | 31 | val retrieval = (select from CipherModel::class 32 | where CipherModel_Table.name.eq("name")) 33 | .querySingle(db) 34 | assertTrue(retrieval!!.id == model.id) 35 | (delete() from CipherModel::class).execute(db) 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /tests/src/androidTest/java/com/dbflow5/sqlcipher/CipherTestObjects.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5.sqlcipher 2 | 3 | import android.content.Context 4 | import com.dbflow5.annotation.Column 5 | import com.dbflow5.annotation.PrimaryKey 6 | import com.dbflow5.annotation.Table 7 | import com.dbflow5.config.DBFlowDatabase 8 | import com.dbflow5.database.DatabaseCallback 9 | import com.dbflow5.structure.BaseModel 10 | 11 | class SQLCipherOpenHelperImpl(context: Context, 12 | databaseDefinition: DBFlowDatabase, 13 | callback: DatabaseCallback?) 14 | : SQLCipherOpenHelper(context, databaseDefinition, callback) { 15 | override var cipherSecret = "dbflow-rules" 16 | } 17 | 18 | @Table(database = CipherDatabase::class) 19 | class CipherModel(@PrimaryKey(autoincrement = true) var id: Long = 0, 20 | @Column var name: String? = null) : BaseModel() -------------------------------------------------------------------------------- /tests/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/src/main/assets/prepackaged.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agrosner/DBFlow/e1b6211dac6ddc0aa0c1c9a76a116478ccf92b86/tests/src/main/assets/prepackaged.db -------------------------------------------------------------------------------- /tests/src/main/assets/prepackaged_2.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agrosner/DBFlow/e1b6211dac6ddc0aa0c1c9a76a116478ccf92b86/tests/src/main/assets/prepackaged_2.db -------------------------------------------------------------------------------- /tests/src/main/java/com/dbflow5/DemoApp.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5 2 | 3 | import android.annotation.SuppressLint 4 | import android.app.Application 5 | import android.content.Context 6 | 7 | class DemoApp : Application() { 8 | 9 | companion object { 10 | @SuppressLint("StaticFieldLeak") 11 | lateinit var context: Context 12 | } 13 | 14 | override fun onCreate() { 15 | super.onCreate() 16 | context = this 17 | } 18 | } -------------------------------------------------------------------------------- /tests/src/main/java/com/dbflow5/StubContentProvider.kt: -------------------------------------------------------------------------------- 1 | package com.dbflow5 2 | 3 | import android.content.ContentProvider 4 | import android.content.ContentValues 5 | import android.database.Cursor 6 | import android.net.Uri 7 | 8 | /** 9 | * Description: Used as a stub, include this in order to work around Android O changes to [ContentProvider] 10 | */ 11 | open class StubContentProvider : ContentProvider() { 12 | 13 | override fun insert(uri: Uri?, values: ContentValues?): Uri { 14 | TODO("not implemented") 15 | } 16 | 17 | override fun query(uri: Uri?, projection: Array?, selection: String?, 18 | selectionArgs: Array?, sortOrder: String?): Cursor { 19 | TODO("not implemented") 20 | } 21 | 22 | override fun onCreate(): Boolean = true 23 | 24 | override fun update(uri: Uri?, values: ContentValues?, selection: String?, 25 | selectionArgs: Array?): Int { 26 | TODO("not implemented") 27 | } 28 | 29 | override fun delete(uri: Uri?, selection: String?, selectionArgs: Array?): Int { 30 | TODO("not implemented") 31 | } 32 | 33 | override fun getType(uri: Uri?): String { 34 | TODO("not implemented") 35 | } 36 | } -------------------------------------------------------------------------------- /tests/src/main/java/com/dbflow5/test/DemoActivity.java: -------------------------------------------------------------------------------- 1 | package com.dbflow5.test; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.view.Menu; 6 | import android.view.MenuItem; 7 | 8 | 9 | public class DemoActivity extends Activity { 10 | 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | setContentView(R.layout.activity_demo); 15 | } 16 | 17 | @Override 18 | public boolean onCreateOptionsMenu(Menu menu) { 19 | // Inflate the menu; this adds items to the action bar if it is present. 20 | getMenuInflater().inflate(R.menu.menu_demo, menu); 21 | return true; 22 | } 23 | 24 | @Override 25 | public boolean onOptionsItemSelected(MenuItem item) { 26 | // Handle action bar item clicks here. The action bar will 27 | // automatically handle clicks on the Home/Up button, so long 28 | // as you specify a parent activity in AndroidManifest.xml. 29 | int id = item.getItemId(); 30 | 31 | //noinspection SimplifiableIfStatement 32 | if (id == R.id.action_settings) { 33 | return true; 34 | } 35 | 36 | return super.onOptionsItemSelected(item); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/src/main/res/layout/activity_demo.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /tests/src/main/res/menu/menu_demo.xml: -------------------------------------------------------------------------------- 1 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /tests/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /tests/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /tests/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Hello world! 3 | Settings 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/src/test/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tests/src/test/assets/migrations/Migrations/0.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE MigrationModel 2 | ADD COLUMN addedColumn; 3 | 4 | -- This is a test -------------------------------------------------------------------------------- /tests/src/test/assets/testdb.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agrosner/DBFlow/e1b6211dac6ddc0aa0c1c9a76a116478ccf92b86/tests/src/test/assets/testdb.db -------------------------------------------------------------------------------- /tests/src/test/resources/com/android/tools/test_config.properties: -------------------------------------------------------------------------------- 1 | android_merged_manifest=./build/intermediates/manifests/full/debug/AndroidManifest.xml 2 | android_merged_resources=./build/intermediates/res/merged/debug 3 | android_merged_assets=./build/intermediates/assets/debug -------------------------------------------------------------------------------- /usage2/.gitignore: -------------------------------------------------------------------------------- 1 | # Node rules: 2 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 3 | .grunt 4 | 5 | ## Dependency directory 6 | ## Commenting this out is preferred by some people, see 7 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 8 | node_modules 9 | 10 | # Book build output 11 | _book 12 | 13 | # eBook build output 14 | *.epub 15 | *.mobi 16 | *.pdf -------------------------------------------------------------------------------- /usage2/advanced-usage/README.md: -------------------------------------------------------------------------------- 1 | # Advanced Usage 2 | 3 | This section details the more advanced usages of DBFlow. 4 | 5 | -------------------------------------------------------------------------------- /usage2/advanced-usage/multiplemodules.md: -------------------------------------------------------------------------------- 1 | # Multiple Modules 2 | 3 | In apps that want to share DBFlow across multiple modules or when developing a library module that uses DBFlow, we have to provide a little extra configuration to properly ensure that all database classes are accounted for. 4 | 5 | It's directly related to the fact that annotation processors are isolated between projects and are not shared. 6 | 7 | In order to add support for multiple modules, in each and every library/subproject that uses a DBFlow instance, you must add an annotation processing argument to its `build.gradle`: 8 | 9 | Using KAPT: 10 | 11 | ```java 12 | kapt { 13 | arguments { 14 | arg("targetModuleName", "SomeUniqueModuleName") 15 | } 16 | } 17 | ``` 18 | 19 | or if you use Android/Java: 20 | 21 | ```java 22 | // inside android -> defaultConfig 23 | javaCompileOptions { 24 | annotationProcessorOptions { 25 | arguments = ['library': 'true'] 26 | } 27 | } 28 | ``` 29 | 30 | By passing the targetModuleName, we append that to the `GeneratedDatabaseHolder` class name to create the `{targetModuleName}GeneratedDatabaseHolder` module. 31 | 32 | **Note**: Specifying this in code means you need to specify the module when initializing DBFlow: 33 | 34 | From previous sample code, we recommend initializing the specific module inside your library, to prevent developer error. **Note**: Multiple calls to `FlowManager` will not adversely affect DBFlow. If DBFlow is already initialized, we append the module to DBFlow if and only if it does not already exist. 35 | 36 | ```kotlin 37 | fun initialize(context: Context) { 38 | FlowManager.init(FlowConfig.builder(context) 39 | .addDatabaseHolder(SomeUniqueModuleNameGeneratedDatabaseHolder::class) 40 | .build()) 41 | } 42 | ``` 43 | 44 | -------------------------------------------------------------------------------- /usage2/advanced-usage/sqlciphersupport.md: -------------------------------------------------------------------------------- 1 | # SQLCipher 2 | 3 | As of 3.0.0-beta2+, DBFlow now supports [SQLCipher](https://www.zetetic.net/sqlcipher/) fairly easily. 4 | 5 | To add the library add the library to your `build.gradle` with same version you are using with the rest of the library. 6 | 7 | ```groovy 8 | dependencies { 9 | implementation "com.dbflow5:sqlcipher:${version}" 10 | implementation "net.zetetic:android-database-sqlcipher:${sqlcipher_version}" 11 | } 12 | ``` 13 | 14 | You also need to add the Proguard rule: 15 | 16 | ```text 17 | -keep class net.sqlcipher.** { *; } 18 | -dontwarn net.sqlcipher.** 19 | ``` 20 | 21 | Next, you need to subclass the provided `SQLCipherOpenHelper` \(taken from test files\): 22 | 23 | ```kotlin 24 | class SQLCipherOpenHelperImpl(context: Context, 25 | databaseDefinition: DBFlowDatabase, 26 | callback: DatabaseCallback?) 27 | : SQLCipherOpenHelper(context, databaseDefinition, callback) { 28 | override val cipherSecret get() = "dbflow-rules" 29 | } 30 | ``` 31 | 32 | _Note:_ that the constructor with `DatabaseDefinition` and `DatabaseHelperListener` is required. 33 | 34 | Then in your application class when initializing DBFlow: 35 | 36 | ```kotlin 37 | FlowManager.init(FlowConfig.Builder(context) 38 | .database( 39 | DatabaseConfig.Builder(CipherDatabase::class) { db, callback -> SQLCipherHelperImpl(context, databaseDefinition, callback)) 40 | .build()) 41 | .build()) 42 | ``` 43 | 44 | And that's it. You're all set to start using SQLCipher! 45 | 46 | -------------------------------------------------------------------------------- /usage2/book.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ "versions" ], 3 | "pluginsConfig": { 4 | "versions": { 5 | "type": "tags" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /usage2/livedata.md: -------------------------------------------------------------------------------- 1 | # Live Data 2 | 3 | The [LiveData](https://developer.android.com/topic/libraries/architecture/livedata#kotlin) artifact for DBFlow 4 | provides a simple way to extend the database `Transaction` into a `LiveData` object. 5 | 6 | ## How to Use 7 | 8 | Construct a database transaction and then utilize the Kotlin extension function `liveData { db, queriable -> }` 9 | to map it to a `LiveData instance`. 10 | 11 | ```kotlin 12 | 13 | @Table(database = TestDatabase::class) 14 | data class LiveDataModel(@PrimaryKey var id: String = "", 15 | var name: Int = 0) 16 | 17 | fun registerObserver(owner: LifecycleOwner) { 18 | val data: LiveData> = (select from LiveDataModel::class) 19 | .liveData { db, queriable -> queriable.queryList(db) } 20 | 21 | data.observe(owner) { list -> 22 | // called whenever the tables change. 23 | } 24 | 25 | database() 26 | .beginTransactionAsync { db -> 27 | (0..2).forEach { 28 | LiveDataModel(id = "$it", name = it).insert(db) 29 | } 30 | } 31 | .execute() 32 | // any modification to db using model objects or SQLite wrapper will trigger LiveData to update 33 | // and requery the DB. 34 | 35 | } 36 | 37 | ``` 38 | 39 | -------------------------------------------------------------------------------- /usage2/proguard.md: -------------------------------------------------------------------------------- 1 | # Proguard 2 | 3 | Since DBFlow uses annotation processing, which is run pre-proguard phase, the configuration is highly minimal. Also since we combine all generated files into the `GeneratedDatabaseHolder`, any other class generated can be obfuscated. 4 | 5 | ```text 6 | -keep class * extends com.dbflow5.config.DatabaseHolder { *; } 7 | ``` 8 | 9 | This also works on modules from other library projects that use DBFlow. 10 | 11 | --------------------------------------------------------------------------------