diff --git a/README.md b/README.md index d114fc4f3..1c6cc009a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![Image](https://github.com/agrosner/DBFlow/blob/develop/dbflow_banner.png?raw=true) -[![JitPack.io](https://img.shields.io/badge/JitPack.io-4.0.5-red.svg?style=flat)](https://jitpack.io/#Raizlabs/DBFlow) [![Android Weekly](http://img.shields.io/badge/Android%20Weekly-%23129-2CB3E5.svg?style=flat)](http://androidweekly.net/issues/issue-129) [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-DBFlow-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/1134) +[![JitPack.io](https://img.shields.io/badge/JitPack.io-4.1.0-red.svg?style=flat)](https://jitpack.io/#Raizlabs/DBFlow) [![Android Weekly](http://img.shields.io/badge/Android%20Weekly-%23129-2CB3E5.svg?style=flat)](http://androidweekly.net/issues/issue-129) [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-DBFlow-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/1134) A robust, powerful, and very simple ORM android database library with **annotation processing**. @@ -41,14 +41,18 @@ Add the library to the project-level build.gradle, using the apt plugin to enabl ```groovy - def dbflow_version = "4.0.5" + apply plugin: 'kotlin-kapt' // required for kotlin. + + def dbflow_version = "4.1.0" // or dbflow_version = "develop-SNAPSHOT" for grabbing latest dependency in your project on the develop branch // or 10-digit short-hash of a specific commit. (Useful for bugs fixed in develop, but not in a release yet) dependencies { + + // if Java use this. If using Kotlin do NOT use this. annotationProcessor "com.github.Raizlabs.DBFlow:dbflow-processor:${dbflow_version}" - // use kapt for kotlin apt if you're a Kotlin user + // Use if Kotlin user. kapt "com.github.Raizlabs.DBFlow:dbflow-processor:${dbflow_version}" compile "com.github.Raizlabs.DBFlow:dbflow-core:${dbflow_version}" @@ -75,10 +79,6 @@ Add the library to the project-level build.gradle, using the apt plugin to enabl } -// if you're building with Kotlin - kapt { - generateStubs = true - } ``` # Pull Requests diff --git a/build.gradle b/build.gradle index dc4b32b1e..b22d45ba4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,13 @@ buildscript { - ext.kotlin_version = '1.1.3-2' + ext.kotlin_version = '1.1.4-2' repositories { jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.3' + classpath 'com.android.tools.build:gradle:3.0.0-beta2' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' - classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.6.2' + classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.7.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -14,6 +15,7 @@ buildscript { allprojects { repositories { jcenter() + google() maven { url "https://www.jitpack.io" } } } diff --git a/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/ColumnMap.java b/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/ColumnMap.java new file mode 100644 index 000000000..95524fca7 --- /dev/null +++ b/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/ColumnMap.java @@ -0,0 +1,22 @@ +package com.raizlabs.android.dbflow.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Description: Maps an arbitrary object and its corresponding fields into a set of columns. It is similar + * to {@link ForeignKey} except it's not represented in the DB hierarchy. + */ +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.FIELD) +public @interface ColumnMap { + + /** + * Defines explicit references for a composite {@link ColumnMap} definition. + * + * @return override explicit usage of all fields and provide custom references. + */ + ColumnMapReference[] references() default {}; +} diff --git a/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/ColumnMapReference.java b/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/ColumnMapReference.java new file mode 100644 index 000000000..c944d5be4 --- /dev/null +++ b/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/ColumnMapReference.java @@ -0,0 +1,30 @@ +package com.raizlabs.android.dbflow.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Description: Allows a {@link ColumnMap} to specify a reference override for its fields. Anything not + * defined here will not be used. + */ +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.FIELD) +public @interface ColumnMapReference { + + /** + * @return The local column name that will be referenced in the DB + */ + String columnName(); + + /** + * @return The column name in the referenced table + */ + String columnMapFieldName(); + + /** + * @return Specify the {@link NotNull} annotation here and it will get pasted into the reference definition. + */ + NotNull notNull() default @NotNull(onNullConflict = ConflictAction.NONE); +} diff --git a/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/Database.java b/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/Database.java index b8d9c07ed..293edacb0 100644 --- a/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/Database.java +++ b/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/Database.java @@ -26,15 +26,23 @@ int version(); /** - * @return The name of the DB. Optional as it will default to the class name. + * @deprecated use DatabaseConfig.databaseName() to change the name. */ + @Deprecated String name() default ""; /** - * @return Specify the extension of the file name : {fileName}.{extension}. Default is ".db" + * @deprecated use DatabaseConfig.extension() to change the extension. */ + @Deprecated String databaseExtension() default ""; + /** + * @deprecated use DatabaseConfig.inMemoryBuilder() instead. + */ + @Deprecated + boolean inMemory() default false; + /** * @return If true, SQLite will throw exceptions when {@link ForeignKey} constraints are not respected. * Default is false and will not throw exceptions. @@ -52,11 +60,6 @@ */ boolean backupEnabled() default false; - /** - * @return true if you want it to be in-memory, false if not. - */ - boolean inMemory() default false; - /** * @return Global default insert conflict that can be applied to any table when it leaves * its {@link ConflictAction} as NONE. @@ -72,6 +75,8 @@ /** * @return Marks all generated classes within this database with this character. For example * "TestTable" becomes "TestTable$Table" for a "$" separator. + * @deprecated Generated class files will become '_' only in next major release. */ + @Deprecated String generatedClassSeparator() default "_"; } diff --git a/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/ForeignKeyReference.java b/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/ForeignKeyReference.java index 064bd6b93..7cb343b33 100644 --- a/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/ForeignKeyReference.java +++ b/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/ForeignKeyReference.java @@ -24,4 +24,8 @@ */ String foreignKeyColumnName(); + /** + * @return Specify the {@link NotNull} annotation here and it will get pasted into the reference definition. + */ + NotNull notNull() default @NotNull(onNullConflict = ConflictAction.NONE); } diff --git a/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/OneToMany.java b/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/OneToMany.java index e200b5dff..175a8cadf 100644 --- a/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/OneToMany.java +++ b/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/OneToMany.java @@ -55,7 +55,9 @@ enum Method { /** * @return If true, the underlying variable that we use is private, requiring us to provide * a setter for it. + * @deprecated has no effect on the visibility of the call since we now autodetect visibility. */ + @Deprecated boolean isVariablePrivate() default false; /** diff --git a/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/Table.java b/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/Table.java index b8e8944b1..106e37aed 100644 --- a/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/Table.java +++ b/dbflow-core/src/main/java/com/raizlabs/android/dbflow/annotation/Table.java @@ -73,6 +73,12 @@ */ boolean assignDefaultValuesFromCursor() default true; + /** + * @return When false, this table gets generated and associated with database, however it will not immediately + * get created upon startup. This is useful for keeping around legacy tables for migrations. + */ + boolean createWithDatabase() default true; + /** * @return The cache size for this Table. */ diff --git a/dbflow-kotlinextensions/build.gradle b/dbflow-kotlinextensions/build.gradle index b97b0c384..4de4f19a1 100644 --- a/dbflow-kotlinextensions/build.gradle +++ b/dbflow-kotlinextensions/build.gradle @@ -26,12 +26,9 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - testCompile 'junit:junit:4.12' - compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - - compile project("${dbflow_project_prefix}dbflow-core") - compile project("${dbflow_project_prefix}dbflow") + api "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + api project("${dbflow_project_prefix}dbflow-core") + api project("${dbflow_project_prefix}dbflow") } apply from: '../kotlin-artifacts.gradle' diff --git a/dbflow-kotlinextensions/src/main/java/com/raizlabs/android/dbflow/kotlinextensions/OneToManyExtensions.kt b/dbflow-kotlinextensions/src/main/java/com/raizlabs/android/dbflow/kotlinextensions/OneToManyExtensions.kt new file mode 100644 index 000000000..dd591c448 --- /dev/null +++ b/dbflow-kotlinextensions/src/main/java/com/raizlabs/android/dbflow/kotlinextensions/OneToManyExtensions.kt @@ -0,0 +1,27 @@ +package com.raizlabs.android.dbflow.kotlinextensions + +import com.raizlabs.android.dbflow.sql.queriable.ModelQueriable +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty + + +fun oneToMany(query: () -> ModelQueriable) = OneToMany(query) + +/** + * Description: Wraps a [OneToMany] annotation getter into a concise property setter. + */ +class OneToMany(private val query: () -> ModelQueriable) : ReadWriteProperty?> { + + private var list: List? = null + + override fun getValue(thisRef: Any, property: KProperty<*>): List? { + if (list?.isEmpty() ?: true) { + list = query().list + } + return list + } + + override fun setValue(thisRef: Any, property: KProperty<*>, value: List?) { + list = value + } +} \ No newline at end of file diff --git a/dbflow-kotlinextensions/src/main/java/com/raizlabs/android/dbflow/kotlinextensions/PropertyMethodExtensions.kt b/dbflow-kotlinextensions/src/main/java/com/raizlabs/android/dbflow/kotlinextensions/PropertyMethodExtensions.kt index 37930eea1..31b3d8bff 100644 --- a/dbflow-kotlinextensions/src/main/java/com/raizlabs/android/dbflow/kotlinextensions/PropertyMethodExtensions.kt +++ b/dbflow-kotlinextensions/src/main/java/com/raizlabs/android/dbflow/kotlinextensions/PropertyMethodExtensions.kt @@ -10,13 +10,13 @@ import com.raizlabs.android.dbflow.sql.language.property.Property * Description: Provides property methods in via infix functions. */ -infix fun Property.eq(value: T) = this.eq(value) +infix fun Property.eq(value: T?) = this.eq(value) -infix fun Property.`is`(value: T) = this.`is`(value) +infix fun Property.`is`(value: T?) = this.`is`(value) -infix fun Property.isNot(value: T) = this.isNot(value) +infix fun Property.isNot(value: T?) = this.isNot(value) -infix fun Property.notEq(value: T) = this.notEq(value) +infix fun Property.notEq(value: T?) = this.notEq(value) infix fun Property.like(value: String) = this.like(value) diff --git a/dbflow-kotlinextensions/src/main/java/com/raizlabs/android/dbflow/kotlinextensions/QueryExtensions.kt b/dbflow-kotlinextensions/src/main/java/com/raizlabs/android/dbflow/kotlinextensions/QueryExtensions.kt index 094abdc57..a4a84ee10 100644 --- a/dbflow-kotlinextensions/src/main/java/com/raizlabs/android/dbflow/kotlinextensions/QueryExtensions.kt +++ b/dbflow-kotlinextensions/src/main/java/com/raizlabs/android/dbflow/kotlinextensions/QueryExtensions.kt @@ -2,8 +2,26 @@ package com.raizlabs.android.dbflow.kotlinextensions import com.raizlabs.android.dbflow.annotation.Collate import com.raizlabs.android.dbflow.sql.Query -import com.raizlabs.android.dbflow.sql.language.* +import com.raizlabs.android.dbflow.sql.language.BaseModelQueriable +import com.raizlabs.android.dbflow.sql.language.Case +import com.raizlabs.android.dbflow.sql.language.CaseCondition +import com.raizlabs.android.dbflow.sql.language.CompletedTrigger +import com.raizlabs.android.dbflow.sql.language.CursorResult +import com.raizlabs.android.dbflow.sql.language.From +import com.raizlabs.android.dbflow.sql.language.Index +import com.raizlabs.android.dbflow.sql.language.Insert +import com.raizlabs.android.dbflow.sql.language.Join +import com.raizlabs.android.dbflow.sql.language.NameAlias +import com.raizlabs.android.dbflow.sql.language.OrderBy +import com.raizlabs.android.dbflow.sql.language.SQLOperator +import com.raizlabs.android.dbflow.sql.language.SQLite +import com.raizlabs.android.dbflow.sql.language.Select import com.raizlabs.android.dbflow.sql.language.Set +import com.raizlabs.android.dbflow.sql.language.Transformable +import com.raizlabs.android.dbflow.sql.language.Trigger +import com.raizlabs.android.dbflow.sql.language.TriggerMethod +import com.raizlabs.android.dbflow.sql.language.Update +import com.raizlabs.android.dbflow.sql.language.Where import com.raizlabs.android.dbflow.sql.language.property.IProperty import com.raizlabs.android.dbflow.sql.queriable.AsyncQuery import com.raizlabs.android.dbflow.sql.queriable.ModelQueriable @@ -85,6 +103,12 @@ inline val ModelQueriable.result inline val ModelQueriable.cursorResult get() = queryResults() +inline val ModelQueriable.flowQueryList + get() = flowQueryList() + +inline val ModelQueriable.cursorList + get() = cursorList() + // cursor result extensions inline fun CursorResult<*>.toCustomList() = toCustomList(T::class.java) @@ -100,16 +124,16 @@ inline val ModelQueriable.async get() = async() infix inline fun AsyncQuery.list(crossinline callback: (QueryTransaction<*>, MutableList) -> Unit) - = queryListResultCallback { queryTransaction, mutableList -> callback(queryTransaction, mutableList) } - .execute() + = queryListResultCallback { queryTransaction, mutableList -> callback(queryTransaction, mutableList) } + .execute() infix inline fun AsyncQuery.result(crossinline callback: (QueryTransaction<*>, T?) -> Unit) - = querySingleResultCallback { queryTransaction, model -> callback(queryTransaction, model) } - .execute() + = querySingleResultCallback { queryTransaction, model -> callback(queryTransaction, model) } + .execute() infix inline fun AsyncQuery.cursorResult(crossinline callback: (QueryTransaction<*>, CursorResult) -> Unit) - = queryResultCallback { queryTransaction, cursorResult -> callback(queryTransaction, cursorResult) } - .execute() + = queryResultCallback { queryTransaction, cursorResult -> callback(queryTransaction, cursorResult) } + .execute() inline val Model.async get() = async() @@ -163,7 +187,7 @@ infix fun Update.set(sqlOperator: SQLOperator) = set(sqlOperator) inline fun delete() = SQLite.delete(T::class.java) inline fun delete(deleteClause: From.() -> BaseModelQueriable) - = deleteClause(SQLite.delete(T::class.java)) + = deleteClause(SQLite.delete(T::class.java)) // insert methods diff --git a/dbflow-processor/build.gradle b/dbflow-processor/build.gradle index 2cabdbc5e..dc9975440 100644 --- a/dbflow-processor/build.gradle +++ b/dbflow-processor/build.gradle @@ -7,13 +7,14 @@ targetCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8 dependencies { - compile project("${dbflow_project_prefix}dbflow-core") - compile 'com.squareup:javapoet:1.8.0' - compile 'com.github.agrosner:KPoet:1.0.0' - compile 'com.google.auto.service:auto-service:1.0-rc2' - compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" + implementation project("${dbflow_project_prefix}dbflow-core") + implementation 'com.squareup:javapoet:1.9.0' + implementation 'com.github.agrosner:KPoet:1.0.0' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" - testCompile 'junit:junit:4.12' + compileOnly 'org.glassfish:javax.annotation:10.0-b28' + + testImplementation 'junit:junit:4.12' } diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/ClassNames.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/ClassNames.kt index 84c426763..409802bf2 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/ClassNames.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/ClassNames.kt @@ -50,7 +50,7 @@ object ClassNames { val TYPE_CONVERTER = ClassName.get(CONVERTER, "TypeConverter") val TYPE_CONVERTER_GETTER: ClassName = ClassName.get(PROPERTY_PACKAGE, - "TypeConvertedProperty.TypeConverterGetter") + "TypeConvertedProperty.TypeConverterGetter") val MIGRATION = ClassName.get(MIGRATION_PACKAGE, "Migration") @@ -87,9 +87,13 @@ object ClassNames { val SQLITE = ClassName.get(LANGUAGE, "SQLite") val CACHEABLE_LIST_MODEL_SAVER = ClassName.get(SAVEABLE, "CacheableListModelSaver") + val SINGLE_MODEL_SAVER = ClassName.get(SAVEABLE, "ModelSaver") + val AUTOINCREMENT_MODEL_SAVER = ClassName.get(SAVEABLE, "AutoIncrementModelSaver") val SINGLE_KEY_CACHEABLE_MODEL_LOADER = ClassName.get(QUERIABLE, "SingleKeyCacheableModelLoader") val SINGLE_KEY_CACHEABLE_LIST_MODEL_LOADER = ClassName.get(QUERIABLE, "SingleKeyCacheableListModelLoader") val NON_NULL = ClassName.get("android.support.annotation", "NonNull") + + val GENERATED = ClassName.get("javax.annotation", "Generated") } diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/DBFlowProcessor.java b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/DBFlowProcessor.java deleted file mode 100644 index d1aff5f2e..000000000 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/DBFlowProcessor.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.raizlabs.android.dbflow.processor; - -import com.google.auto.service.AutoService; -import com.raizlabs.android.dbflow.annotation.Column; -import com.raizlabs.android.dbflow.annotation.ColumnIgnore; -import com.raizlabs.android.dbflow.annotation.Migration; -import com.raizlabs.android.dbflow.annotation.ModelView; -import com.raizlabs.android.dbflow.annotation.QueryModel; -import com.raizlabs.android.dbflow.annotation.Table; -import com.raizlabs.android.dbflow.annotation.TypeConverter; -import com.raizlabs.android.dbflow.annotation.provider.ContentProvider; -import com.raizlabs.android.dbflow.annotation.provider.TableEndpoint; -import com.raizlabs.android.dbflow.processor.definition.DatabaseHolderDefinition; - -import java.util.LinkedHashSet; -import java.util.Set; - -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.ProcessingEnvironment; -import javax.annotation.processing.Processor; -import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.TypeElement; - -@AutoService(Processor.class) -public class DBFlowProcessor extends AbstractProcessor { - - private ProcessorManager manager; - - /** - * If the processor class is annotated with {@link - * javax.annotation.processing.SupportedAnnotationTypes}, return an unmodifiable set with the - * same set of strings as the annotation. If the class is not so - * annotated, an empty set is returned. - * - * @return the names of the annotation types supported by this - * processor, or an empty set if none - */ - @Override - public Set getSupportedAnnotationTypes() { - Set supportedTypes = new LinkedHashSet<>(); - supportedTypes.add(Table.class.getCanonicalName()); - supportedTypes.add(Column.class.getCanonicalName()); - supportedTypes.add(TypeConverter.class.getCanonicalName()); - supportedTypes.add(ModelView.class.getCanonicalName()); - supportedTypes.add(Migration.class.getCanonicalName()); - supportedTypes.add(ContentProvider.class.getCanonicalName()); - supportedTypes.add(TableEndpoint.class.getCanonicalName()); - supportedTypes.add(ColumnIgnore.class.getCanonicalName()); - supportedTypes.add(QueryModel.class.getCanonicalName()); - return supportedTypes; - } - - @Override - public Set getSupportedOptions() { - Set supportedOptions = new LinkedHashSet<>(); - supportedOptions.add(DatabaseHolderDefinition.OPTION_TARGET_MODULE_NAME); - return supportedOptions; - } - - /** - * If the processor class is annotated with {@link - * javax.annotation.processing.SupportedSourceVersion}, return the source version in the - * annotation. If the class is not so annotated, {@link - * javax.lang.model.SourceVersion#RELEASE_6} is returned. - * - * @return the latest source version supported by this processor - */ - @Override - public SourceVersion getSupportedSourceVersion() { - return SourceVersion.latestSupported(); - } - - @Override - public synchronized void init(ProcessingEnvironment processingEnv) { - super.init(processingEnv); - manager = new ProcessorManager(processingEnv); - manager.addHandlers( - new MigrationHandler(), - new TypeConverterHandler(), - new DatabaseHandler(), - new TableHandler(), - new QueryModelHandler(), - new ModelViewHandler(), - new ContentProviderHandler(), - new TableEndpointHandler()); - } - - @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { - - manager.handle(manager, roundEnv); - - // return true if we successfully processed the Annotation. - return true; - } - -} diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/DBFlowProcessor.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/DBFlowProcessor.kt new file mode 100644 index 000000000..c3b7581a7 --- /dev/null +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/DBFlowProcessor.kt @@ -0,0 +1,73 @@ +package com.raizlabs.android.dbflow.processor + +import com.raizlabs.android.dbflow.annotation.Column +import com.raizlabs.android.dbflow.annotation.ColumnIgnore +import com.raizlabs.android.dbflow.annotation.Migration +import com.raizlabs.android.dbflow.annotation.ModelView +import com.raizlabs.android.dbflow.annotation.QueryModel +import com.raizlabs.android.dbflow.annotation.Table +import com.raizlabs.android.dbflow.annotation.TypeConverter +import com.raizlabs.android.dbflow.annotation.provider.ContentProvider +import com.raizlabs.android.dbflow.annotation.provider.TableEndpoint +import com.raizlabs.android.dbflow.processor.definition.DatabaseHolderDefinition +import javax.annotation.processing.AbstractProcessor +import javax.annotation.processing.ProcessingEnvironment +import javax.annotation.processing.RoundEnvironment +import javax.lang.model.SourceVersion +import javax.lang.model.element.TypeElement + +class DBFlowProcessor : AbstractProcessor() { + + private lateinit var manager: ProcessorManager + + /** + * If the processor class is annotated with [ ], return an unmodifiable set with the + * same set of strings as the annotation. If the class is not so + * annotated, an empty set is returned. + + * @return the names of the annotation types supported by this + * * processor, or an empty set if none + */ + override fun getSupportedAnnotationTypes() + = linkedSetOf(Table::class.java.canonicalName, + Column::class.java.canonicalName, + TypeConverter::class.java.canonicalName, + ModelView::class.java.canonicalName, + Migration::class.java.canonicalName, + ContentProvider::class.java.canonicalName, + TableEndpoint::class.java.canonicalName, + ColumnIgnore::class.java.canonicalName, + QueryModel::class.java.canonicalName + ) + + override fun getSupportedOptions() = linkedSetOf(DatabaseHolderDefinition.OPTION_TARGET_MODULE_NAME) + + /** + * If the processor class is annotated with [ ], return the source version in the + * annotation. If the class is not so annotated, [ ][javax.lang.model.SourceVersion.RELEASE_6] is returned. + + * @return the latest source version supported by this processor + */ + override fun getSupportedSourceVersion(): SourceVersion = SourceVersion.latestSupported() + + @Synchronized override fun init(processingEnv: ProcessingEnvironment) { + super.init(processingEnv) + manager = ProcessorManager(processingEnv) + manager.addHandlers(MigrationHandler(), + TypeConverterHandler(), + DatabaseHandler(), + TableHandler(), + QueryModelHandler(), + ModelViewHandler(), + ContentProviderHandler(), + TableEndpointHandler()) + } + + override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { + manager.handle(manager, roundEnv) + + // return true if we successfully processed the Annotation. + return true + } + +} diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/Handlers.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/Handlers.kt index 17f40c672..c15468258 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/Handlers.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/Handlers.kt @@ -1,12 +1,32 @@ package com.raizlabs.android.dbflow.processor -import com.google.common.collect.Sets -import com.raizlabs.android.dbflow.annotation.* +import com.raizlabs.android.dbflow.annotation.Database +import com.raizlabs.android.dbflow.annotation.ManyToMany +import com.raizlabs.android.dbflow.annotation.Migration +import com.raizlabs.android.dbflow.annotation.ModelView +import com.raizlabs.android.dbflow.annotation.MultipleManyToMany +import com.raizlabs.android.dbflow.annotation.QueryModel +import com.raizlabs.android.dbflow.annotation.Table import com.raizlabs.android.dbflow.annotation.TypeConverter import com.raizlabs.android.dbflow.annotation.provider.ContentProvider import com.raizlabs.android.dbflow.annotation.provider.TableEndpoint -import com.raizlabs.android.dbflow.converter.* -import com.raizlabs.android.dbflow.processor.definition.* +import com.raizlabs.android.dbflow.converter.BigDecimalConverter +import com.raizlabs.android.dbflow.converter.BigIntegerConverter +import com.raizlabs.android.dbflow.converter.BooleanConverter +import com.raizlabs.android.dbflow.converter.CalendarConverter +import com.raizlabs.android.dbflow.converter.CharConverter +import com.raizlabs.android.dbflow.converter.DateConverter +import com.raizlabs.android.dbflow.converter.SqlDateConverter +import com.raizlabs.android.dbflow.converter.UUIDConverter +import com.raizlabs.android.dbflow.processor.definition.ContentProviderDefinition +import com.raizlabs.android.dbflow.processor.definition.DatabaseDefinition +import com.raizlabs.android.dbflow.processor.definition.ManyToManyDefinition +import com.raizlabs.android.dbflow.processor.definition.MigrationDefinition +import com.raizlabs.android.dbflow.processor.definition.ModelViewDefinition +import com.raizlabs.android.dbflow.processor.definition.QueryModelDefinition +import com.raizlabs.android.dbflow.processor.definition.TableDefinition +import com.raizlabs.android.dbflow.processor.definition.TableEndpointDefinition +import com.raizlabs.android.dbflow.processor.definition.TypeConverterDefinition import com.raizlabs.android.dbflow.processor.utils.annotation import javax.annotation.processing.RoundEnvironment import javax.lang.model.element.Element @@ -168,7 +188,7 @@ class TypeConverterHandler : BaseContainerHandler() { abstract class BaseContainerHandler : Handler { override fun handle(processorManager: ProcessorManager, roundEnvironment: RoundEnvironment) { - val annotatedElements = Sets.newLinkedHashSet(roundEnvironment.getElementsAnnotatedWith(annotationClass)) + val annotatedElements = roundEnvironment.getElementsAnnotatedWith(annotationClass).toMutableSet() processElements(processorManager, annotatedElements) if (annotatedElements.size > 0) { annotatedElements.forEach { onProcessElement(processorManager, it) } diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/ProcessorManager.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/ProcessorManager.kt index 1c046e5ee..4f93685e6 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/ProcessorManager.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/ProcessorManager.kt @@ -1,8 +1,5 @@ package com.raizlabs.android.dbflow.processor -import com.google.common.collect.Lists -import com.google.common.collect.Maps -import com.google.common.collect.Sets import com.raizlabs.android.dbflow.processor.definition.BaseTableDefinition import com.raizlabs.android.dbflow.processor.definition.ContentProviderDefinition import com.raizlabs.android.dbflow.processor.definition.DatabaseDefinition @@ -90,7 +87,7 @@ class ProcessorManager internal constructor(val processingEnvironment: Processin modelToDatabaseMap.put(modelType, databaseName) } - fun getDatabaseName(databaseTypeName: TypeName?) = getOrPutDatabase(databaseTypeName)?.databaseDefinition?.databaseName ?: "" + fun getDatabaseName(databaseTypeName: TypeName?) = getOrPutDatabase(databaseTypeName)?.databaseDefinition?.databaseClassName ?: "" fun addQueryModelDefinition(queryModelDefinition: QueryModelDefinition) { queryModelDefinition.elementClassName?.let { @@ -106,7 +103,7 @@ class ProcessorManager internal constructor(val processingEnvironment: Processin holderDefinition?.tableNameMap?.let { if (holderDefinition.tableNameMap.containsKey(tableDefinition.tableName)) { logError("Found duplicate table ${tableDefinition.tableName} " + - "for database ${holderDefinition.databaseDefinition?.databaseName}") + "for database ${holderDefinition.databaseDefinition?.databaseClassName}") } else tableDefinition.tableName?.let { holderDefinition.tableNameMap.put(it, tableDefinition) } @@ -134,18 +131,33 @@ class ProcessorManager internal constructor(val processingEnvironment: Processin return getOrPutDatabase(databaseName)?.tableDefinitionMap?.get(typeName) } + fun getQueryModelDefinition(databaseName: TypeName?, typeName: TypeName?): QueryModelDefinition? { + return getOrPutDatabase(databaseName)?.queryModelDefinitionMap?.get(typeName) + } + + fun getModelViewDefinition(databaseName: TypeName?, typeName: TypeName?): ModelViewDefinition? { + return getOrPutDatabase(databaseName)?.modelViewDefinitionMap?.get(typeName) + } + + fun getReferenceDefinition(databaseName: TypeName?, typeName: TypeName?): BaseTableDefinition? { + return getTableDefinition(databaseName, typeName) + ?: getQueryModelDefinition(databaseName, typeName) + ?: getModelViewDefinition(databaseName, typeName) + } + fun addModelViewDefinition(modelViewDefinition: ModelViewDefinition) { modelViewDefinition.elementClassName?.let { - getOrPutDatabase(modelViewDefinition.databaseName)?. + getOrPutDatabase(modelViewDefinition.databaseTypeName)?. modelViewDefinitionMap?.put(it, modelViewDefinition) } } - fun getTypeConverters() = Sets.newLinkedHashSet(typeConverters.values).sortedBy { it.modelTypeName?.toString() } + fun getTypeConverters() = typeConverters.values.toHashSet().sortedBy { it.modelTypeName?.toString() } fun getTableDefinitions(databaseName: TypeName): List { val databaseHolderDefinition = getOrPutDatabase(databaseName) - return Sets.newHashSet(databaseHolderDefinition?.tableDefinitionMap?.values ?: arrayListOf()) + return (databaseHolderDefinition?.tableDefinitionMap?.values ?: arrayListOf()) + .toHashSet() .sortedBy { it.outputClassName?.simpleName() } } @@ -156,8 +168,10 @@ class ProcessorManager internal constructor(val processingEnvironment: Processin fun getModelViewDefinitions(databaseName: TypeName): List { val databaseDefinition = getOrPutDatabase(databaseName) - return Sets.newHashSet(databaseDefinition?.modelViewDefinitionMap?.values ?: arrayListOf()) + return (databaseDefinition?.modelViewDefinitionMap?.values ?: arrayListOf()) + .toHashSet() .sortedBy { it.outputClassName?.simpleName() } + .sortedByDescending { it.priority } } fun setModelViewDefinitions(modelViewDefinitionMap: MutableMap, elementClassName: ClassName) { @@ -167,24 +181,25 @@ class ProcessorManager internal constructor(val processingEnvironment: Processin fun getQueryModelDefinitions(databaseName: TypeName): List { val databaseDefinition = getOrPutDatabase(databaseName) - return Sets.newHashSet(databaseDefinition?.queryModelDefinitionMap?.values ?: arrayListOf()) + return (databaseDefinition?.queryModelDefinitionMap?.values ?: arrayListOf()) + .toHashSet() .sortedBy { it.outputClassName?.simpleName() } } fun addMigrationDefinition(migrationDefinition: MigrationDefinition) { var migrationDefinitionMap: MutableMap>? = migrations[migrationDefinition.databaseName] if (migrationDefinitionMap == null) { - migrationDefinitionMap = Maps.newHashMap>() + migrationDefinitionMap = hashMapOf() migrations.put(migrationDefinition.databaseName, migrationDefinitionMap) } - var migrationDefinitions: MutableList? = migrationDefinitionMap!![migrationDefinition.version] + var migrationDefinitions: MutableList? = migrationDefinitionMap[migrationDefinition.version] if (migrationDefinitions == null) { - migrationDefinitions = Lists.newArrayList() + migrationDefinitions = arrayListOf() migrationDefinitionMap.put(migrationDefinition.version, migrationDefinitions) } - if (!migrationDefinitions!!.contains(migrationDefinition)) { + if (!migrationDefinitions.contains(migrationDefinition)) { migrationDefinitions.add(migrationDefinition) } } @@ -193,7 +208,7 @@ class ProcessorManager internal constructor(val processingEnvironment: Processin fun addContentProviderDefinition(contentProviderDefinition: ContentProviderDefinition) { contentProviderDefinition.elementTypeName?.let { - val holderDefinition = getOrPutDatabase(contentProviderDefinition.databaseName) + val holderDefinition = getOrPutDatabase(contentProviderDefinition.databaseTypeName) holderDefinition?.providerMap?.put(it, contentProviderDefinition) providerMap.put(it, contentProviderDefinition) } @@ -246,9 +261,7 @@ class ProcessorManager internal constructor(val processingEnvironment: Processin try { if (databaseHolderDefinition.databaseDefinition == null) { - manager.logError("Found cannot find referenced db with: ${databaseHolderDefinition.tableNameMap.values.size} tables," + - " ${databaseHolderDefinition.modelViewDefinitionMap.values.size} modelviews. ") - manager.logError("Found tables: " + databaseHolderDefinition.tableNameMap.values) + manager.logError(databaseHolderDefinition.getMissingDBRefs().joinToString("\n")) continue } @@ -295,9 +308,10 @@ class ProcessorManager internal constructor(val processingEnvironment: Processin tableDefinitions.forEach { WriterUtils.writeBaseDefinition(it, processorManager) } - val modelViewDefinitions = ArrayList(databaseHolderDefinition.modelViewDefinitionMap.values) - Collections.sort(modelViewDefinitions) - modelViewDefinitions.forEach { WriterUtils.writeBaseDefinition(it, processorManager) } + val modelViewDefinitions = databaseHolderDefinition.modelViewDefinitionMap.values + modelViewDefinitions + .sortedByDescending { it.priority } + .forEach { WriterUtils.writeBaseDefinition(it, processorManager) } val queryModelDefinitions = databaseHolderDefinition.queryModelDefinitionMap.values .sortedBy { it.outputClassName?.simpleName() } diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/Validators.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/Validators.kt index 6ad56f0ad..eff4f295c 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/Validators.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/Validators.kt @@ -3,7 +3,7 @@ package com.raizlabs.android.dbflow.processor import com.raizlabs.android.dbflow.processor.definition.* import com.raizlabs.android.dbflow.processor.definition.column.ColumnDefinition import com.raizlabs.android.dbflow.processor.definition.column.EnumColumnAccessor -import com.raizlabs.android.dbflow.processor.definition.column.ForeignKeyColumnDefinition +import com.raizlabs.android.dbflow.processor.definition.column.ReferenceColumnDefinition import com.raizlabs.android.dbflow.processor.definition.column.PrivateScopeColumnAccessor import com.raizlabs.android.dbflow.processor.utils.isNullOrEmpty @@ -57,7 +57,7 @@ class ColumnValidator : Validator { if (!validatorDefinition.defaultValue.isNullOrEmpty()) { val typeName = validatorDefinition.elementTypeName - if (validatorDefinition is ForeignKeyColumnDefinition && validatorDefinition.isReferencingTableObject) { + if (validatorDefinition is ReferenceColumnDefinition && validatorDefinition.isReferencingTableObject) { processorManager.logError(ColumnValidator::class, "Default values cannot be specified for model fields") } else if (typeName != null && typeName.isPrimitive) { processorManager.logWarning(ColumnValidator::class.java, "Primitive column types will not respect default values") @@ -76,14 +76,14 @@ class ColumnValidator : Validator { success = false processorManager.logError("Enums cannot be primary keys. Column: ${validatorDefinition.columnName}" + " and type: ${validatorDefinition.elementTypeName}") - } else if (validatorDefinition is ForeignKeyColumnDefinition) { + } else if (validatorDefinition is ReferenceColumnDefinition) { success = false processorManager.logError("Enums cannot be foreign keys. Column: ${validatorDefinition.columnName}" + " and type: ${validatorDefinition.elementTypeName}") } } - if (validatorDefinition is ForeignKeyColumnDefinition) { + if (validatorDefinition is ReferenceColumnDefinition) { validatorDefinition.column?.let { if (it.name.isNotEmpty()) { success = false diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/BaseDefinition.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/BaseDefinition.kt index 944637507..c9fc808e4 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/BaseDefinition.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/BaseDefinition.kt @@ -1,8 +1,18 @@ package com.raizlabs.android.dbflow.processor.definition -import com.grosner.kpoet.* +import com.grosner.kpoet.S +import com.grosner.kpoet.`@` +import com.grosner.kpoet.`public final class` +import com.grosner.kpoet.extends +import com.grosner.kpoet.implements +import com.grosner.kpoet.javadoc +import com.grosner.kpoet.typeName +import com.raizlabs.android.dbflow.processor.ClassNames +import com.raizlabs.android.dbflow.processor.DBFlowProcessor import com.raizlabs.android.dbflow.processor.ProcessorManager import com.raizlabs.android.dbflow.processor.utils.ElementUtility +import com.raizlabs.android.dbflow.processor.utils.hasJavaX +import com.raizlabs.android.dbflow.processor.utils.toTypeElement import com.squareup.javapoet.ClassName import com.squareup.javapoet.ParameterizedTypeName import com.squareup.javapoet.TypeName @@ -78,6 +88,8 @@ abstract class BaseDefinition : TypeDefinition { if (element is TypeElement) { typeElement = element + } else { + typeElement = element.toTypeElement() } } @@ -123,7 +135,15 @@ abstract class BaseDefinition : TypeDefinition { override val typeSpec: TypeSpec get() { + if (outputClassName == null) { + manager.logError("Found error for ${elementTypeName} ${outputClassName} ${(this as QueryModelDefinition).databaseTypeName}") + } return `public final class`(outputClassName?.simpleName() ?: "") { + if (hasJavaX()) { + addAnnotation(`@`(ClassNames.GENERATED, { + this["value"] = DBFlowProcessor::class.java.canonicalName.toString().S + }).build()) + } extendsClass?.let { extends(it) } implementsClasses.forEach { implements(it) } javadoc("This is generated code. Please do not modify") diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/BaseTableDefinition.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/BaseTableDefinition.kt index 16a8d953d..f7cdd1131 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/BaseTableDefinition.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/BaseTableDefinition.kt @@ -1,14 +1,29 @@ package com.raizlabs.android.dbflow.processor.definition -import com.google.common.collect.Lists -import com.grosner.kpoet.* +import com.grosner.kpoet.`public static final` +import com.grosner.kpoet.`return` +import com.grosner.kpoet.code +import com.grosner.kpoet.constructor +import com.grosner.kpoet.final +import com.grosner.kpoet.modifiers +import com.grosner.kpoet.param +import com.grosner.kpoet.public +import com.grosner.kpoet.statement import com.raizlabs.android.dbflow.processor.ClassNames import com.raizlabs.android.dbflow.processor.ProcessorManager import com.raizlabs.android.dbflow.processor.definition.column.ColumnDefinition -import com.raizlabs.android.dbflow.processor.definition.column.ForeignKeyColumnDefinition import com.raizlabs.android.dbflow.processor.definition.column.PackagePrivateScopeColumnAccessor -import com.raizlabs.android.dbflow.processor.utils.* -import com.squareup.javapoet.* +import com.raizlabs.android.dbflow.processor.definition.column.ReferenceColumnDefinition +import com.raizlabs.android.dbflow.processor.utils.ElementUtility +import com.raizlabs.android.dbflow.processor.utils.ModelUtils +import com.raizlabs.android.dbflow.processor.utils.`override fun` +import com.raizlabs.android.dbflow.processor.utils.getPackage +import com.raizlabs.android.dbflow.processor.utils.toClassName +import com.squareup.javapoet.ClassName +import com.squareup.javapoet.JavaFile +import com.squareup.javapoet.ParameterizedTypeName +import com.squareup.javapoet.TypeName +import com.squareup.javapoet.TypeSpec import java.io.IOException import java.util.* import javax.annotation.processing.ProcessingEnvironment @@ -31,10 +46,9 @@ abstract class BaseTableDefinition(typeElement: Element, processorManager: Proce var autoIncrementColumn: ColumnDefinition? = null - var associatedTypeConverters: MutableMap> = HashMap() - var globalTypeConverters: MutableMap> = HashMap() - val packagePrivateList: MutableList = - Lists.newArrayList() + var associatedTypeConverters = hashMapOf>() + var globalTypeConverters = hashMapOf>() + val packagePrivateList = arrayListOf() var orderedCursorLookUp: Boolean = false var assignDefaultValuesFromCursor = true @@ -44,6 +58,8 @@ abstract class BaseTableDefinition(typeElement: Element, processorManager: Proce val modelClassName = typeElement.simpleName.toString() var databaseDefinition: DatabaseDefinition? = null + var databaseTypeName: TypeName? = null + val hasGlobalTypeConverters get() = globalTypeConverters.isNotEmpty() @@ -119,8 +135,8 @@ abstract class BaseTableDefinition(typeElement: Element, processorManager: Proce for (columnDefinition in packagePrivateList) { var helperClassName = "${columnDefinition.element.getPackage()}.${columnDefinition.element.enclosingElement.toClassName().simpleName()}${classSeparator}Helper" - if (columnDefinition is ForeignKeyColumnDefinition) { - val tableDefinition: TableDefinition? = databaseDefinition?.objectHolder?.tableDefinitionMap?.get(columnDefinition.referencedTableClassName as TypeName) + if (columnDefinition is ReferenceColumnDefinition) { + val tableDefinition: TableDefinition? = databaseDefinition?.objectHolder?.tableDefinitionMap?.get(columnDefinition.referencedClassName as TypeName) if (tableDefinition != null) { helperClassName = "${tableDefinition.element.getPackage()}.${ClassName.get(tableDefinition.element as TypeElement).simpleName()}${classSeparator}Helper" } diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/ContentProvider.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/ContentProvider.kt index 3e543ddb5..b66d3245b 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/ContentProvider.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/ContentProvider.kt @@ -1,7 +1,19 @@ package com.raizlabs.android.dbflow.processor.definition -import com.google.common.collect.Lists -import com.grosner.kpoet.* +import com.grosner.kpoet.L +import com.grosner.kpoet.`=` +import com.grosner.kpoet.`break` +import com.grosner.kpoet.`private final field` +import com.grosner.kpoet.`private static final field` +import com.grosner.kpoet.`return` +import com.grosner.kpoet.case +import com.grosner.kpoet.code +import com.grosner.kpoet.final +import com.grosner.kpoet.modifiers +import com.grosner.kpoet.param +import com.grosner.kpoet.parameterized +import com.grosner.kpoet.public +import com.grosner.kpoet.statement import com.raizlabs.android.dbflow.annotation.provider.ContentProvider import com.raizlabs.android.dbflow.annotation.provider.ContentUri import com.raizlabs.android.dbflow.annotation.provider.Notify @@ -13,15 +25,24 @@ import com.raizlabs.android.dbflow.processor.utils.`override fun` import com.raizlabs.android.dbflow.processor.utils.annotation import com.raizlabs.android.dbflow.processor.utils.controlFlow import com.raizlabs.android.dbflow.processor.utils.isNullOrEmpty -import com.squareup.javapoet.* -import javax.lang.model.element.* +import com.squareup.javapoet.ArrayTypeName +import com.squareup.javapoet.ClassName +import com.squareup.javapoet.CodeBlock +import com.squareup.javapoet.MethodSpec +import com.squareup.javapoet.TypeName +import com.squareup.javapoet.TypeSpec +import javax.lang.model.element.Element +import javax.lang.model.element.ExecutableElement +import javax.lang.model.element.Modifier +import javax.lang.model.element.TypeElement +import javax.lang.model.element.VariableElement import javax.lang.model.type.MirroredTypeException internal fun appendDefault(code: CodeBlock.Builder) { code.beginControlFlow("default:") - .addStatement("throw new \$T(\$S + \$L)", - ClassName.get(IllegalArgumentException::class.java), "Unknown URI", Constants.PARAM_URI) - .endControlFlow() + .addStatement("throw new \$T(\$S + \$L)", + ClassName.get(IllegalArgumentException::class.java), "Unknown URI", Constants.PARAM_URI) + .endControlFlow() } object Constants { @@ -37,7 +58,7 @@ object Constants { internal fun ContentUriDefinition.getSegmentsPreparation() = code { if (segments.isNotEmpty()) { statement("\$T segments = uri.getPathSegments()", - parameterized(List::class)) + parameterized(List::class)) } this } @@ -51,7 +72,7 @@ internal fun ContentUriDefinition.getSelectionAndSelectionArgs(): CodeBlock { } else { val selectionBuilder = CodeBlock.builder().add("\$T.concatenateWhere(selection, \"", ClassNames.DATABASE_UTILS) val selectionArgsBuilder = CodeBlock.builder().add("\$T.appendSelectionArgs(selectionArgs, new \$T[] {", - ClassNames.DATABASE_UTILS, String::class.java) + ClassNames.DATABASE_UTILS, String::class.java) var isFirst = true for (segment in segments) { if (!isFirst) { @@ -87,10 +108,9 @@ class DeleteMethod(private val contentProviderDefinition: ContentProviderDefinit code.apply { case(uriDefinition.name.L) { add(uriDefinition.getSegmentsPreparation()) - add("long count = \$T.getDatabase(\$S).getWritableDatabase().delete(\$S, ", - ClassNames.FLOW_MANAGER, - manager.getDatabaseName(contentProviderDefinition.databaseName), - it.tableName) + add("long count = \$T.getDatabase(\$T.class).getWritableDatabase().delete(\$S, ", + ClassNames.FLOW_MANAGER, contentProviderDefinition.databaseTypeName, + it.tableName) add(uriDefinition.getSelectionAndSelectionArgs()) add(");\n") @@ -107,12 +127,12 @@ class DeleteMethod(private val contentProviderDefinition: ContentProviderDefinit code.endControlFlow() return MethodSpec.methodBuilder("delete") - .addAnnotation(Override::class.java) - .addModifiers(Modifier.PUBLIC, Modifier.FINAL) - .addParameter(ClassNames.URI, PARAM_URI) - .addParameter(ClassName.get(String::class.java), PARAM_SELECTION) - .addParameter(ArrayTypeName.of(String::class.java), PARAM_SELECTION_ARGS) - .addCode(code.build()).returns(TypeName.INT).build() + .addAnnotation(Override::class.java) + .addModifiers(Modifier.PUBLIC, Modifier.FINAL) + .addParameter(ClassNames.URI, PARAM_URI) + .addParameter(ClassName.get(String::class.java), PARAM_SELECTION) + .addParameter(ArrayTypeName.of(String::class.java), PARAM_SELECTION_ARGS) + .addCode(code.build()).returns(TypeName.INT).build() } companion object { @@ -140,13 +160,15 @@ class InsertMethod(private val contentProviderDefinition: ContentProviderDefinit if (uriDefinition.insertEnabled) { code.apply { beginControlFlow("case \$L:", uriDefinition.name) - addStatement("\$T adapter = \$T.getModelAdapter(\$T.getTableClassForName(\$S, \$S))", - ClassNames.MODEL_ADAPTER, ClassNames.FLOW_MANAGER, ClassNames.FLOW_MANAGER, - contentProviderDefinition.databaseNameString, it.tableName) + addStatement("\$T adapter = \$T.getModelAdapter(\$T.getTableClassForName(\$T.class, \$S))", + ClassNames.MODEL_ADAPTER, ClassNames.FLOW_MANAGER, ClassNames.FLOW_MANAGER, + contentProviderDefinition.databaseTypeName, it.tableName) - add("final long id = FlowManager.getDatabase(\$S).getWritableDatabase()", - contentProviderDefinition.databaseNameString).add(".insertWithOnConflict(\$S, null, values, " + "\$T.getSQLiteDatabaseAlgorithmInt(adapter.getInsertOnConflictAction()));\n", it.tableName, - ClassNames.CONFLICT_ACTION) + add("final long id = FlowManager.getDatabase(\$T.class).getWritableDatabase()", + contentProviderDefinition.databaseTypeName).add( + ".insertWithOnConflict(\$S, null, values, " + + "\$T.getSQLiteDatabaseAlgorithmInt(adapter.getInsertOnConflictAction()));\n", it.tableName, + ClassNames.CONFLICT_ACTION) NotifyMethod(it, uriDefinition, Notify.Method.INSERT).addCode(this) @@ -164,10 +186,10 @@ class InsertMethod(private val contentProviderDefinition: ContentProviderDefinit appendDefault(code) code.endControlFlow() return MethodSpec.methodBuilder(if (isBulk) "bulkInsert" else "insert") - .addAnnotation(Override::class.java).addParameter(ClassNames.URI, Constants.PARAM_URI) - .addParameter(ClassNames.CONTENT_VALUES, Constants.PARAM_CONTENT_VALUES) - .addModifiers(if (isBulk) Modifier.PROTECTED else Modifier.PUBLIC, Modifier.FINAL) - .addCode(code.build()).returns(if (isBulk) TypeName.INT else ClassNames.URI).build() + .addAnnotation(Override::class.java).addParameter(ClassNames.URI, Constants.PARAM_URI) + .addParameter(ClassNames.CONTENT_VALUES, Constants.PARAM_CONTENT_VALUES) + .addModifiers(if (isBulk) Modifier.PROTECTED else Modifier.PUBLIC, Modifier.FINAL) + .addCode(code.build()).returns(if (isBulk) TypeName.INT else ClassNames.URI).build() } } @@ -188,16 +210,16 @@ class NotifyMethod(private val tableEndpointDefinition: TableEndpointDefinition, val notifyDefinition = notifyDefinitionList[i] if (notifyDefinition.returnsArray) { code.addStatement("\$T[] notifyUris\$L = \$L.\$L(\$L)", ClassNames.URI, - notifyDefinition.methodName, notifyDefinition.parent, - notifyDefinition.methodName, notifyDefinition.params) + notifyDefinition.methodName, notifyDefinition.parent, + notifyDefinition.methodName, notifyDefinition.params) code.beginControlFlow("for (\$T notifyUri: notifyUris\$L)", ClassNames.URI, notifyDefinition.methodName) } else { code.addStatement("\$T notifyUri\$L = \$L.\$L(\$L)", ClassNames.URI, - notifyDefinition.methodName, notifyDefinition.parent, - notifyDefinition.methodName, notifyDefinition.params) + notifyDefinition.methodName, notifyDefinition.parent, + notifyDefinition.methodName, notifyDefinition.params) } code.addStatement("getContext().getContentResolver().notifyChange(notifyUri\$L, null)", - if (notifyDefinition.returnsArray) "" else notifyDefinition.methodName) + if (notifyDefinition.returnsArray) "" else notifyDefinition.methodName) if (notifyDefinition.returnsArray) { code.endControlFlow() } @@ -233,14 +255,14 @@ class QueryMethod(private val contentProviderDefinition: ContentProviderDefiniti override val methodSpec: MethodSpec? get() { val method = MethodSpec.methodBuilder("query") - .addAnnotation(Override::class.java) - .addModifiers(Modifier.PUBLIC, Modifier.FINAL) - .addParameter(ClassNames.URI, "uri") - .addParameter(ArrayTypeName.of(String::class.java), "projection") - .addParameter(ClassName.get(String::class.java), "selection") - .addParameter(ArrayTypeName.of(String::class.java), "selectionArgs") - .addParameter(ClassName.get(String::class.java), "sortOrder") - .returns(ClassNames.CURSOR) + .addAnnotation(Override::class.java) + .addModifiers(Modifier.PUBLIC, Modifier.FINAL) + .addParameter(ClassNames.URI, "uri") + .addParameter(ArrayTypeName.of(String::class.java), "projection") + .addParameter(ClassName.get(String::class.java), "selection") + .addParameter(ArrayTypeName.of(String::class.java), "selectionArgs") + .addParameter(ClassName.get(String::class.java), "sortOrder") + .returns(ClassNames.CURSOR) method.addStatement("\$L cursor = null", ClassNames.CURSOR) method.beginControlFlow("switch(\$L.match(uri))", ContentProviderDefinition.URI_MATCHER) @@ -250,10 +272,9 @@ class QueryMethod(private val contentProviderDefinition: ContentProviderDefiniti method.apply { beginControlFlow("case \$L:", uriDefinition.name) addCode(uriDefinition.getSegmentsPreparation()) - addCode("cursor = \$T.getDatabase(\$S).getWritableDatabase().query(\$S, projection, ", - ClassNames.FLOW_MANAGER, - manager.getDatabaseName(contentProviderDefinition.databaseName), - tableEndpointDefinition.tableName) + addCode("cursor = \$T.getDatabase(\$T.class).getWritableDatabase().query(\$S, projection, ", + ClassNames.FLOW_MANAGER, contentProviderDefinition.databaseTypeName, + tableEndpointDefinition.tableName) addCode(uriDefinition.getSelectionAndSelectionArgs()) addCode(", null, null, sortOrder);\n") addStatement("break") @@ -282,13 +303,13 @@ class UpdateMethod(private val contentProviderDefinition: ContentProviderDefinit override val methodSpec: MethodSpec? get() { val method = MethodSpec.methodBuilder("update") - .addAnnotation(Override::class.java) - .addModifiers(Modifier.PUBLIC) - .addParameter(ClassNames.URI, Constants.PARAM_URI) - .addParameter(ClassNames.CONTENT_VALUES, Constants.PARAM_CONTENT_VALUES) - .addParameter(ClassName.get(String::class.java), "selection") - .addParameter(ArrayTypeName.of(String::class.java), "selectionArgs") - .returns(TypeName.INT) + .addAnnotation(Override::class.java) + .addModifiers(Modifier.PUBLIC) + .addParameter(ClassNames.URI, Constants.PARAM_URI) + .addParameter(ClassNames.CONTENT_VALUES, Constants.PARAM_CONTENT_VALUES) + .addParameter(ClassName.get(String::class.java), "selection") + .addParameter(ArrayTypeName.of(String::class.java), "selectionArgs") + .returns(TypeName.INT) method.beginControlFlow("switch(MATCHER.match(\$L))", Constants.PARAM_URI) for (tableEndpointDefinition in contentProviderDefinition.endpointDefinitions) { @@ -296,25 +317,24 @@ class UpdateMethod(private val contentProviderDefinition: ContentProviderDefinit if (uriDefinition.updateEnabled) { method.apply { beginControlFlow("case \$L:", uriDefinition.name) - addStatement("\$T adapter = \$T.getModelAdapter(\$T.getTableClassForName(\$S, \$S))", - ClassNames.MODEL_ADAPTER, ClassNames.FLOW_MANAGER, ClassNames.FLOW_MANAGER, - contentProviderDefinition.databaseNameString, - tableEndpointDefinition.tableName) + addStatement("\$T adapter = \$T.getModelAdapter(\$T.getTableClassForName(\$T.class, \$S))", + ClassNames.MODEL_ADAPTER, ClassNames.FLOW_MANAGER, ClassNames.FLOW_MANAGER, + contentProviderDefinition.databaseTypeName, + tableEndpointDefinition.tableName) addCode(uriDefinition.getSegmentsPreparation()) addCode( - "long count = \$T.getDatabase(\$S).getWritableDatabase().updateWithOnConflict(\$S, \$L, ", - ClassNames.FLOW_MANAGER, - manager.getDatabaseName(contentProviderDefinition.databaseName), - tableEndpointDefinition.tableName, - Constants.PARAM_CONTENT_VALUES) + "long count = \$T.getDatabase(\$T.class).getWritableDatabase().updateWithOnConflict(\$S, \$L, ", + ClassNames.FLOW_MANAGER, contentProviderDefinition.databaseTypeName, + tableEndpointDefinition.tableName, + Constants.PARAM_CONTENT_VALUES) addCode(uriDefinition.getSelectionAndSelectionArgs()) addCode( - ", \$T.getSQLiteDatabaseAlgorithmInt(adapter.getUpdateOnConflictAction()));\n", - ClassNames.CONFLICT_ACTION) + ", \$T.getSQLiteDatabaseAlgorithmInt(adapter.getUpdateOnConflictAction()));\n", + ClassNames.CONFLICT_ACTION) val code = CodeBlock.builder() NotifyMethod(tableEndpointDefinition, uriDefinition, - Notify.Method.UPDATE).addCode(code) + Notify.Method.UPDATE).addCode(code) addCode(code.build()) addStatement("return (int) count") @@ -341,18 +361,17 @@ class UpdateMethod(private val contentProviderDefinition: ContentProviderDefinit class ContentProviderDefinition(typeElement: Element, processorManager: ProcessorManager) : BaseDefinition(typeElement, processorManager) { - var databaseName: TypeName? = null - var databaseNameString: String = "" + var databaseTypeName: TypeName? = null var authority: String = "" - var endpointDefinitions: MutableList = Lists.newArrayList() + var endpointDefinitions = arrayListOf() private val methods: Array = arrayOf(QueryMethod(this, manager), - InsertMethod(this, false), - InsertMethod(this, true), - DeleteMethod(this, manager), - UpdateMethod(this, manager)) + InsertMethod(this, false), + InsertMethod(this, true), + DeleteMethod(this, manager), + UpdateMethod(this, manager)) init { @@ -361,7 +380,7 @@ class ContentProviderDefinition(typeElement: Element, processorManager: Processo try { provider.database } catch (mte: MirroredTypeException) { - databaseName = TypeName.get(mte.typeMirror) + databaseTypeName = TypeName.get(mte.typeMirror) } authority = provider.authority @@ -385,8 +404,7 @@ class ContentProviderDefinition(typeElement: Element, processorManager: Processo get() = ClassNames.BASE_CONTENT_PROVIDER fun prepareForWrite() { - val databaseDefinition = manager.getDatabaseHolderDefinition(databaseName)!!.databaseDefinition - databaseNameString = databaseDefinition?.databaseName ?: "" + val databaseDefinition = manager.getDatabaseHolderDefinition(databaseTypeName)!!.databaseDefinition setOutputClassName(databaseDefinition?.classSeparator + DEFINITION_NAME) } @@ -406,10 +424,10 @@ class ContentProviderDefinition(typeElement: Element, processorManager: Processo `override fun`(TypeName.BOOLEAN, "onCreate") { modifiers(public, final) addStatement("final \$T $AUTHORITY = \$L", String::class.java, - if (authority.contains("R.string.")) - "getContext().getString($authority)" - else - "\"$authority\"") + if (authority.contains("R.string.")) + "getContext().getString($authority)" + else + "\"$authority\"") for (endpointDefinition in endpointDefinitions) { endpointDefinition.contentUriDefinitions.forEach { @@ -418,7 +436,7 @@ class ContentProviderDefinition(typeElement: Element, processorManager: Processo path = "\"" + it.path + "\"" } else { path = CodeBlock.builder().add("\$L.\$L.getPath()", it.elementClassName, - it.name).build().toString() + it.name).build().toString() } addStatement("\$L.addURI(\$L, \$L, \$L)", URI_MATCHER, AUTHORITY, path, it.name) } @@ -429,7 +447,7 @@ class ContentProviderDefinition(typeElement: Element, processorManager: Processo `override fun`(String::class, "getDatabaseName") { modifiers(public, final) - `return`(databaseNameString.S) + `return`("\$T.getDatabaseName(\$T.class)", ClassNames.FLOW_MANAGER, databaseTypeName) } `override fun`(String::class, "getType", param(ClassNames.URI, "uri")) { @@ -438,12 +456,12 @@ class ContentProviderDefinition(typeElement: Element, processorManager: Processo statement("\$T type = null", ClassName.get(String::class.java)) controlFlow("switch(\$L.match(uri))", URI_MATCHER) { endpointDefinitions.flatMap { it.contentUriDefinitions } - .forEach { uri -> - controlFlow("case \$L:", uri.name) { - statement("type = \$S", uri.type) - `break`() - } + .forEach { uri -> + controlFlow("case \$L:", uri.name) { + statement("type = \$S", uri.type) + `break`() } + } appendDefault(this) } `return`("type") @@ -452,7 +470,7 @@ class ContentProviderDefinition(typeElement: Element, processorManager: Processo } methods.mapNotNull { it.methodSpec } - .forEach { typeBuilder.addMethod(it) } + .forEach { typeBuilder.addMethod(it) } } companion object { diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/DatabaseDefinition.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/DatabaseDefinition.kt index 7f305cbe4..c669a37a7 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/DatabaseDefinition.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/DatabaseDefinition.kt @@ -1,6 +1,14 @@ package com.raizlabs.android.dbflow.processor.definition -import com.grosner.kpoet.* +import com.grosner.kpoet.L +import com.grosner.kpoet.S +import com.grosner.kpoet.`return` +import com.grosner.kpoet.constructor +import com.grosner.kpoet.final +import com.grosner.kpoet.modifiers +import com.grosner.kpoet.param +import com.grosner.kpoet.public +import com.grosner.kpoet.statement import com.raizlabs.android.dbflow.annotation.ConflictAction import com.raizlabs.android.dbflow.annotation.Database import com.raizlabs.android.dbflow.processor.ClassNames @@ -9,8 +17,11 @@ import com.raizlabs.android.dbflow.processor.ProcessorManager import com.raizlabs.android.dbflow.processor.TableValidator import com.raizlabs.android.dbflow.processor.utils.`override fun` import com.raizlabs.android.dbflow.processor.utils.annotation -import com.raizlabs.android.dbflow.processor.utils.isNullOrEmpty -import com.squareup.javapoet.* +import com.squareup.javapoet.ClassName +import com.squareup.javapoet.ParameterizedTypeName +import com.squareup.javapoet.TypeName +import com.squareup.javapoet.TypeSpec +import com.squareup.javapoet.WildcardTypeName import java.util.* import java.util.regex.Pattern import javax.lang.model.element.Element @@ -21,7 +32,7 @@ import javax.lang.model.element.Element */ class DatabaseDefinition(manager: ProcessorManager, element: Element) : BaseDefinition(element, manager), TypeDefinition { - var databaseName: String? = null + var databaseClassName: String? = null var databaseVersion: Int = 0 @@ -38,40 +49,35 @@ class DatabaseDefinition(manager: ProcessorManager, element: Element) : BaseDefi var classSeparator: String = "" var fieldRefSeparator: String = "" // safe field for javapoet - var isInMemory: Boolean = false - var objectHolder: DatabaseObjectHolder? = null var databaseExtensionName = "" + var databaseName = "" + + var inMemory = false + init { packageName = ClassNames.FLOW_MANAGER_PACKAGE element.annotation()?.let { database -> databaseName = database.name databaseExtensionName = database.databaseExtension - if (databaseName.isNullOrEmpty()) { - databaseName = element.simpleName.toString() - } - if (!isValidDatabaseName(databaseName)) { - throw Error("Database name [ " + databaseName + " ] is not valid. It must pass [A-Za-z_$]+[a-zA-Z0-9_$]* " + - "regex so it can't start with a number or contain any special character except '$'. Especially a dot character is not allowed!") - } - + inMemory = database.inMemory + databaseClassName = element.simpleName.toString() consistencyChecksEnabled = database.consistencyCheckEnabled backupEnabled = database.backupEnabled classSeparator = database.generatedClassSeparator fieldRefSeparator = classSeparator - setOutputClassName(databaseName + classSeparator + "Database") + setOutputClassName(databaseClassName + classSeparator + "Database") databaseVersion = database.version foreignKeysSupported = database.foreignKeyConstraintsEnforced insertConflict = database.insertConflict updateConflict = database.updateConflict - isInMemory = database.inMemory } } @@ -143,19 +149,15 @@ class DatabaseDefinition(manager: ProcessorManager, element: Element) : BaseDefi } val migrationDefinitionMap = manager.getMigrationsForDatabase(elementClassName) - if (!migrationDefinitionMap.isEmpty()) { - val versionSet = ArrayList(migrationDefinitionMap.keys) - Collections.sort(versionSet) - for (version in versionSet) { - val migrationDefinitions = migrationDefinitionMap[version] - migrationDefinitions?.let { - Collections.sort(migrationDefinitions, { o1, o2 -> Integer.valueOf(o2.priority)!!.compareTo(o1.priority) }) - for (migrationDefinition in migrationDefinitions) { + migrationDefinitionMap.keys + .sortedByDescending { it } + .forEach { version -> + migrationDefinitionMap[version] + ?.sortedBy { it.priority } + ?.forEach { migrationDefinition -> statement("addMigration($version, new \$T${migrationDefinition.constructorName})", migrationDefinition.elementClassName) } - } } - } } this } @@ -173,10 +175,6 @@ class DatabaseDefinition(manager: ProcessorManager, element: Element) : BaseDefi modifiers(public, final) `return`(foreignKeysSupported.L) } - `override fun`(TypeName.BOOLEAN, "isInMemory") { - modifiers(public, final) - `return`(isInMemory.L) - } `override fun`(TypeName.BOOLEAN, "backupEnabled") { modifiers(public, final) `return`(backupEnabled.L) @@ -189,16 +187,24 @@ class DatabaseDefinition(manager: ProcessorManager, element: Element) : BaseDefi modifiers(public, final) `return`(databaseVersion.L) } - `override fun`(String::class, "getDatabaseName") { - modifiers(public, final) - `return`(databaseName.S) - } if (!databaseExtensionName.isNullOrBlank()) { `override fun`(String::class, "getDatabaseExtensionName") { modifiers(public, final) `return`(databaseExtensionName.S) } } + if (!databaseName.isNullOrBlank()) { + `override fun`(String::class, "getDatabaseName") { + modifiers(public, final) + `return`(databaseName.S) + } + } + if (inMemory) { + `override fun`(TypeName.BOOLEAN, "isInMemory") { + modifiers(public, final) + `return`(true.L) + } + } } } diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/DatabaseObjectHolder.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/DatabaseObjectHolder.kt index d6451eb09..fb1035341 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/DatabaseObjectHolder.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/DatabaseObjectHolder.kt @@ -1,7 +1,5 @@ package com.raizlabs.android.dbflow.processor.definition -import com.google.common.collect.Maps -import com.raizlabs.android.dbflow.processor.definition.* import com.squareup.javapoet.TypeName import java.util.* @@ -23,5 +21,30 @@ class DatabaseObjectHolder { var queryModelDefinitionMap: MutableMap = HashMap() var modelViewDefinitionMap: MutableMap = HashMap() var manyToManyDefinitionMap: MutableMap> = HashMap() - var providerMap: MutableMap = Maps.newHashMap() + var providerMap = hashMapOf() + + /** + * Retrieve what database class they're trying to reference. + */ + fun getMissingDBRefs(): List { + if (databaseDefinition == null) { + val list = mutableListOf() + tableDefinitionMap.values.forEach { + list += "Database ${it.databaseTypeName} not found for Table ${it.tableName}" + } + queryModelDefinitionMap.values.forEach { + list += "Database ${it.databaseTypeName} not found for QueryModel ${it.elementName}" + } + modelViewDefinitionMap.values.forEach { + list += "Database ${it.databaseTypeName} not found for ModelView ${it.elementName}" + } + providerMap.values.forEach { + list += "Database ${it.databaseTypeName} not found for ContentProvider ${it.elementName}" + } + return list + + } else { + return listOf() + } + } } diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/Methods.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/Methods.kt index d2427450b..48ab60d03 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/Methods.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/Methods.kt @@ -233,15 +233,15 @@ class CreationQueryMethod(private val tableDefinition: TableDefinition) : Method foreignKeyBlocks.add(foreignKeyBuilder.apply { add(", FOREIGN KEY(") - add(fk._foreignKeyReferenceDefinitionList.joinToString { QueryBuilder.quote(it.columnName) }) + add(fk._referenceDefinitionList.joinToString { QueryBuilder.quote(it.columnName) }) add(") REFERENCES ") }.build()) - tableNameBlocks.add(codeBlock { add("\$T.getTableName(\$T.class)", ClassNames.FLOW_MANAGER, fk.referencedTableClassName) }) + tableNameBlocks.add(codeBlock { add("\$T.getTableName(\$T.class)", ClassNames.FLOW_MANAGER, fk.referencedClassName) }) referenceKeyBlocks.add(referenceBuilder.apply { add("(") - add(fk._foreignKeyReferenceDefinitionList.joinToString { QueryBuilder.quote(it.foreignColumnName) }) + add(fk._referenceDefinitionList.joinToString { QueryBuilder.quote(it.foreignColumnName) }) add(") ON UPDATE ${fk.onUpdate.name.replace("_", " ")} ON DELETE ${fk.onDelete.name.replace("_", " ")}") if (fk.deferred) { add(" DEFERRABLE INITIALLY DEFERRED") diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/ModelViewDefinition.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/ModelViewDefinition.kt index d949d28c3..d5d6eabfc 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/ModelViewDefinition.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/ModelViewDefinition.kt @@ -1,15 +1,29 @@ package com.raizlabs.android.dbflow.processor.definition -import com.grosner.kpoet.* +import com.grosner.kpoet.S +import com.grosner.kpoet.`=` +import com.grosner.kpoet.`public static final field` +import com.grosner.kpoet.`return` +import com.grosner.kpoet.final +import com.grosner.kpoet.modifiers +import com.grosner.kpoet.public import com.raizlabs.android.dbflow.annotation.Column +import com.raizlabs.android.dbflow.annotation.ColumnMap import com.raizlabs.android.dbflow.annotation.ModelView import com.raizlabs.android.dbflow.annotation.ModelViewQuery import com.raizlabs.android.dbflow.processor.ClassNames import com.raizlabs.android.dbflow.processor.ColumnValidator import com.raizlabs.android.dbflow.processor.ProcessorManager import com.raizlabs.android.dbflow.processor.definition.column.ColumnDefinition -import com.raizlabs.android.dbflow.processor.definition.column.ForeignKeyColumnDefinition -import com.raizlabs.android.dbflow.processor.utils.* +import com.raizlabs.android.dbflow.processor.definition.column.ReferenceColumnDefinition +import com.raizlabs.android.dbflow.processor.utils.ElementUtility +import com.raizlabs.android.dbflow.processor.utils.`override fun` +import com.raizlabs.android.dbflow.processor.utils.annotation +import com.raizlabs.android.dbflow.processor.utils.ensureVisibleStatic +import com.raizlabs.android.dbflow.processor.utils.implementsClass +import com.raizlabs.android.dbflow.processor.utils.isNullOrEmpty +import com.raizlabs.android.dbflow.processor.utils.simpleString +import com.raizlabs.android.dbflow.processor.utils.toTypeErasedElement import com.squareup.javapoet.ParameterizedTypeName import com.squareup.javapoet.TypeName import com.squareup.javapoet.TypeSpec @@ -20,18 +34,16 @@ import javax.lang.model.type.MirroredTypeException /** * Description: Used in writing ModelViewAdapters */ -class ModelViewDefinition(manager: ProcessorManager, element: Element) : BaseTableDefinition(element, manager), Comparable { +class ModelViewDefinition(manager: ProcessorManager, element: Element) : BaseTableDefinition(element, manager) { internal val implementsLoadFromCursorListener: Boolean - var databaseName: TypeName? = null - private var queryFieldName: String? = null private var name: String? = null private val methods: Array = - arrayOf(LoadFromCursorMethod(this), ExistenceMethod(this), PrimaryConditionMethod(this)) + arrayOf(LoadFromCursorMethod(this), ExistenceMethod(this), PrimaryConditionMethod(this)) var allFields: Boolean = false @@ -43,7 +55,7 @@ class ModelViewDefinition(manager: ProcessorManager, element: Element) : BaseTab try { modelView.database } catch (mte: MirroredTypeException) { - this.databaseName = TypeName.get(mte.typeMirror) + this.databaseTypeName = TypeName.get(mte.typeMirror) } allFields = modelView.allFields @@ -57,7 +69,7 @@ class ModelViewDefinition(manager: ProcessorManager, element: Element) : BaseTab if (element is TypeElement) { implementsLoadFromCursorListener = element.implementsClass(manager.processingEnvironment, - ClassNames.LOAD_FROM_CURSOR_LISTENER) + ClassNames.LOAD_FROM_CURSOR_LISTENER) } else { implementsLoadFromCursorListener = false } @@ -71,7 +83,7 @@ class ModelViewDefinition(manager: ProcessorManager, element: Element) : BaseTab val modelView = element.getAnnotation(ModelView::class.java) if (modelView != null) { - databaseDefinition = manager.getDatabaseHolderDefinition(databaseName)?.databaseDefinition + databaseDefinition = manager.getDatabaseHolderDefinition(databaseTypeName)?.databaseDefinition setOutputClassName("${databaseDefinition?.classSeparator}ViewTable") typeElement?.let { createColumnDefinitions(it) } @@ -91,8 +103,10 @@ class ModelViewDefinition(manager: ProcessorManager, element: Element) : BaseTab for (variableElement in variableElements) { val isValidAllFields = ElementUtility.isValidAllFields(allFields, variableElement) + val isColumnMap = variableElement.annotation() != null - if (variableElement.annotation() != null || isValidAllFields) { + if (variableElement.annotation() != null || isValidAllFields + || isColumnMap) { // package private, will generate helper val isPackagePrivate = ElementUtility.isPackagePrivate(variableElement) @@ -100,7 +114,11 @@ class ModelViewDefinition(manager: ProcessorManager, element: Element) : BaseTab if (checkInheritancePackagePrivate(isPackagePrivateNotInSamePackage, variableElement)) return - val columnDefinition = ColumnDefinition(manager, variableElement, this, isPackagePrivateNotInSamePackage) + val columnDefinition = if (isColumnMap) { + ReferenceColumnDefinition(manager, this, variableElement, isPackagePrivateNotInSamePackage) + } else { + ColumnDefinition(manager, variableElement, this, isPackagePrivateNotInSamePackage) + } if (columnValidator.validate(manager, columnDefinition)) { columnDefinitions.add(columnDefinition) if (isPackagePrivate) { @@ -108,9 +126,8 @@ class ModelViewDefinition(manager: ProcessorManager, element: Element) : BaseTab } } - if (columnDefinition.isPrimaryKey || columnDefinition is ForeignKeyColumnDefinition - || columnDefinition.isPrimaryKeyAutoIncrement || columnDefinition.isRowId) { - manager.logError("ModelViews cannot have primary or foreign keys") + if (columnDefinition.isPrimaryKey || columnDefinition.isPrimaryKeyAutoIncrement || columnDefinition.isRowId) { + manager.logError("ModelView $elementName cannot have primary keys") } } else if (variableElement.annotation() != null) { if (!queryFieldName.isNullOrEmpty()) { @@ -166,10 +183,7 @@ class ModelViewDefinition(manager: ProcessorManager, element: Element) : BaseTab } methods.mapNotNull { it.methodSpec } - .forEach { typeBuilder.addMethod(it) } + .forEach { typeBuilder.addMethod(it) } } - override fun compareTo(other: ModelViewDefinition): Int { - return Integer.valueOf(priority)!!.compareTo(other.priority) - } } \ No newline at end of file diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/OneToManyDefinition.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/OneToManyDefinition.kt index 95a409d01..90cf24ffa 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/OneToManyDefinition.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/OneToManyDefinition.kt @@ -1,20 +1,43 @@ package com.raizlabs.android.dbflow.processor.definition -import com.grosner.kpoet.* +import com.grosner.kpoet.`for` +import com.grosner.kpoet.`if` +import com.grosner.kpoet.end +import com.grosner.kpoet.statement +import com.grosner.kpoet.typeName import com.raizlabs.android.dbflow.annotation.OneToMany import com.raizlabs.android.dbflow.processor.ClassNames import com.raizlabs.android.dbflow.processor.ProcessorManager -import com.raizlabs.android.dbflow.processor.definition.column.* -import com.raizlabs.android.dbflow.processor.utils.* -import com.squareup.javapoet.* +import com.raizlabs.android.dbflow.processor.definition.column.ColumnAccessor +import com.raizlabs.android.dbflow.processor.definition.column.GetterSetter +import com.raizlabs.android.dbflow.processor.definition.column.PrivateScopeColumnAccessor +import com.raizlabs.android.dbflow.processor.definition.column.VisibleScopeColumnAccessor +import com.raizlabs.android.dbflow.processor.definition.column.modelBlock +import com.raizlabs.android.dbflow.processor.definition.column.wrapperCommaIfBaseModel +import com.raizlabs.android.dbflow.processor.definition.column.wrapperIfBaseModel +import com.raizlabs.android.dbflow.processor.utils.ModelUtils +import com.raizlabs.android.dbflow.processor.utils.annotation +import com.raizlabs.android.dbflow.processor.utils.isSubclass +import com.raizlabs.android.dbflow.processor.utils.simpleString +import com.raizlabs.android.dbflow.processor.utils.statement +import com.raizlabs.android.dbflow.processor.utils.toTypeElement +import com.squareup.javapoet.ClassName +import com.squareup.javapoet.CodeBlock +import com.squareup.javapoet.MethodSpec +import com.squareup.javapoet.ParameterizedTypeName +import com.squareup.javapoet.TypeName +import com.squareup.javapoet.WildcardTypeName +import javax.lang.model.element.Element import javax.lang.model.element.ExecutableElement +import javax.lang.model.element.Modifier import javax.lang.model.element.TypeElement /** * Description: Represents the [OneToMany] annotation. */ class OneToManyDefinition(executableElement: ExecutableElement, - processorManager: ProcessorManager) : BaseDefinition(executableElement, processorManager) { + processorManager: ProcessorManager, + parentElements: Collection) : BaseDefinition(executableElement, processorManager) { private var _methodName: String @@ -55,6 +78,26 @@ class OneToManyDefinition(executableElement: ExecutableElement, _variableName = _methodName.replace("get", "") _variableName = _variableName.substring(0, 1).toLowerCase() + _variableName.substring(1) } + + val privateAccessor = PrivateScopeColumnAccessor(_variableName, object : GetterSetter { + override val getterName: String = "" + override val setterName: String = "" + }, optionalGetterParam = if (hasWrapper) ModelUtils.wrapper else "") + + var isVariablePrivate = false + val referencedElement = parentElements.firstOrNull { it.simpleString == _variableName } + if (referencedElement == null) { + // check on setter. if setter exists, we can reference it safely since a getter has already been defined. + if (!parentElements.any { it.simpleString == privateAccessor.setterNameElement }) { + manager.logError(OneToManyDefinition::class, + "@OneToMany definition $elementName Cannot find referenced variable $_variableName.") + } else { + isVariablePrivate = true + } + } else { + isVariablePrivate = referencedElement.modifiers.contains(Modifier.PRIVATE) + } + methods.addAll(oneToMany.methods) val parameters = executableElement.parameters @@ -72,11 +115,8 @@ class OneToManyDefinition(executableElement: ExecutableElement, } } - if (oneToMany.isVariablePrivate) { - columnAccessor = PrivateScopeColumnAccessor(_variableName, object : GetterSetter { - override val getterName: String = "" - override val setterName: String = "" - }, optionalGetterParam = if (hasWrapper) ModelUtils.wrapper else "") + if (isVariablePrivate) { + columnAccessor = privateAccessor } else { columnAccessor = VisibleScopeColumnAccessor(_variableName) } @@ -103,7 +143,7 @@ class OneToManyDefinition(executableElement: ExecutableElement, fun writeWrapperStatement(method: MethodSpec.Builder) { method.statement("\$T ${ModelUtils.wrapper} = \$T.getWritableDatabaseForTable(\$T.class)", - ClassNames.DATABASE_WRAPPER, ClassNames.FLOW_MANAGER, referencedTableType) + ClassNames.DATABASE_WRAPPER, ClassNames.FLOW_MANAGER, referencedTableType) } /** @@ -144,8 +184,8 @@ class OneToManyDefinition(executableElement: ExecutableElement, // need to load adapter for non-model classes if (!extendsModel || efficientCodeMethods) { statement("\$T adapter = \$T.getModelAdapter(\$T.class)", - ParameterizedTypeName.get(ClassNames.MODEL_ADAPTER, referencedTableType), - ClassNames.FLOW_MANAGER, referencedTableType) + ParameterizedTypeName.get(ClassNames.MODEL_ADAPTER, referencedTableType), + ClassNames.FLOW_MANAGER, referencedTableType) } if (efficientCodeMethods) { diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/QueryModelDefinition.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/QueryModelDefinition.kt index 9b2a11a5a..fee449d55 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/QueryModelDefinition.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/QueryModelDefinition.kt @@ -5,11 +5,13 @@ import com.grosner.kpoet.final import com.grosner.kpoet.modifiers import com.grosner.kpoet.public import com.raizlabs.android.dbflow.annotation.Column +import com.raizlabs.android.dbflow.annotation.ColumnMap import com.raizlabs.android.dbflow.annotation.QueryModel import com.raizlabs.android.dbflow.processor.ClassNames import com.raizlabs.android.dbflow.processor.ColumnValidator import com.raizlabs.android.dbflow.processor.ProcessorManager import com.raizlabs.android.dbflow.processor.definition.column.ColumnDefinition +import com.raizlabs.android.dbflow.processor.definition.column.ReferenceColumnDefinition import com.raizlabs.android.dbflow.processor.utils.ElementUtility import com.raizlabs.android.dbflow.processor.utils.`override fun` import com.raizlabs.android.dbflow.processor.utils.annotation @@ -28,8 +30,6 @@ import javax.lang.model.type.MirroredTypeException class QueryModelDefinition(typeElement: Element, processorManager: ProcessorManager) : BaseTableDefinition(typeElement, processorManager) { - var databaseTypeName: TypeName? = null - var allFields: Boolean = false var implementsLoadFromCursorListener = false @@ -46,7 +46,7 @@ class QueryModelDefinition(typeElement: Element, processorManager: ProcessorMana } } - elementClassName?.let { databaseTypeName?.let { it1 -> processorManager.addModelToDatabase(it, it1) } } + elementClassName?.let { elementClassName -> databaseTypeName?.let { processorManager.addModelToDatabase(elementClassName, it) } } if (element is TypeElement) { implementsLoadFromCursorListener = @@ -63,13 +63,17 @@ class QueryModelDefinition(typeElement: Element, processorManager: ProcessorMana columnDefinitions.clear() packagePrivateList.clear() - typeElement.annotation()?.let { queryModel -> - databaseDefinition = manager.getDatabaseHolderDefinition(databaseTypeName)?.databaseDefinition - setOutputClassName("${databaseDefinition?.classSeparator}QueryTable") + val queryModel = typeElement.annotation() + if (queryModel != null) { allFields = queryModel.allFields - - typeElement?.let { createColumnDefinitions(it) } + } else { + allFields = true } + + databaseDefinition = manager.getDatabaseHolderDefinition(databaseTypeName)?.databaseDefinition + setOutputClassName("${databaseDefinition?.classSeparator}QueryTable") + + typeElement?.let { createColumnDefinitions(it) } } override val extendsClass: TypeName? @@ -108,13 +112,17 @@ class QueryModelDefinition(typeElement: Element, processorManager: ProcessorMana // package private, will generate helper val isPackagePrivate = ElementUtility.isPackagePrivate(variableElement) val isPackagePrivateNotInSamePackage = isPackagePrivate && !ElementUtility.isInSamePackage(manager, variableElement, this.element) + val isColumnMap = variableElement.annotation() != null - - if (variableElement.annotation() != null || isAllFields) { + if (variableElement.annotation() != null || isAllFields || isColumnMap) { if (checkInheritancePackagePrivate(isPackagePrivateNotInSamePackage, variableElement)) return - val columnDefinition = ColumnDefinition(manager, variableElement, this, isPackagePrivateNotInSamePackage) + val columnDefinition = if (isColumnMap) { + ReferenceColumnDefinition(manager, this, variableElement, isPackagePrivateNotInSamePackage) + } else { + ColumnDefinition(manager, variableElement, this, isPackagePrivateNotInSamePackage) + } if (columnValidator.validate(manager, columnDefinition)) { columnDefinitions.add(columnDefinition) @@ -122,6 +130,10 @@ class QueryModelDefinition(typeElement: Element, processorManager: ProcessorMana packagePrivateList.add(columnDefinition) } } + + if (columnDefinition.isPrimaryKey || columnDefinition.isPrimaryKeyAutoIncrement || columnDefinition.isRowId) { + manager.logError("QueryModel $elementName cannot have primary keys") + } } } } diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/TableDefinition.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/TableDefinition.kt index afbbbf9c8..30000f270 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/TableDefinition.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/TableDefinition.kt @@ -1,23 +1,61 @@ package com.raizlabs.android.dbflow.processor.definition -import com.google.common.collect.Lists -import com.grosner.kpoet.* -import com.raizlabs.android.dbflow.annotation.* +import com.grosner.kpoet.L +import com.grosner.kpoet.S +import com.grosner.kpoet.`=` +import com.grosner.kpoet.`public static final field` +import com.grosner.kpoet.`return` +import com.grosner.kpoet.`throw new` +import com.grosner.kpoet.code +import com.grosner.kpoet.default +import com.grosner.kpoet.final +import com.grosner.kpoet.modifiers +import com.grosner.kpoet.param +import com.grosner.kpoet.protected +import com.grosner.kpoet.public +import com.grosner.kpoet.statement +import com.grosner.kpoet.switch +import com.raizlabs.android.dbflow.annotation.Column +import com.raizlabs.android.dbflow.annotation.ColumnMap +import com.raizlabs.android.dbflow.annotation.ConflictAction +import com.raizlabs.android.dbflow.annotation.ForeignKey +import com.raizlabs.android.dbflow.annotation.InheritedColumn +import com.raizlabs.android.dbflow.annotation.InheritedPrimaryKey +import com.raizlabs.android.dbflow.annotation.ModelCacheField +import com.raizlabs.android.dbflow.annotation.MultiCacheField +import com.raizlabs.android.dbflow.annotation.OneToMany +import com.raizlabs.android.dbflow.annotation.PrimaryKey +import com.raizlabs.android.dbflow.annotation.Table import com.raizlabs.android.dbflow.processor.ClassNames import com.raizlabs.android.dbflow.processor.ColumnValidator import com.raizlabs.android.dbflow.processor.OneToManyValidator import com.raizlabs.android.dbflow.processor.ProcessorManager -import com.raizlabs.android.dbflow.processor.definition.BindToStatementMethod.Mode.* +import com.raizlabs.android.dbflow.processor.definition.BindToStatementMethod.Mode.DELETE +import com.raizlabs.android.dbflow.processor.definition.BindToStatementMethod.Mode.INSERT +import com.raizlabs.android.dbflow.processor.definition.BindToStatementMethod.Mode.NON_INSERT +import com.raizlabs.android.dbflow.processor.definition.BindToStatementMethod.Mode.UPDATE import com.raizlabs.android.dbflow.processor.definition.column.ColumnDefinition import com.raizlabs.android.dbflow.processor.definition.column.DefinitionUtils -import com.raizlabs.android.dbflow.processor.definition.column.ForeignKeyColumnDefinition -import com.raizlabs.android.dbflow.processor.utils.* +import com.raizlabs.android.dbflow.processor.definition.column.ReferenceColumnDefinition +import com.raizlabs.android.dbflow.processor.utils.ElementUtility +import com.raizlabs.android.dbflow.processor.utils.ModelUtils import com.raizlabs.android.dbflow.processor.utils.ModelUtils.wrapper +import com.raizlabs.android.dbflow.processor.utils.`override fun` +import com.raizlabs.android.dbflow.processor.utils.annotation +import com.raizlabs.android.dbflow.processor.utils.ensureVisibleStatic +import com.raizlabs.android.dbflow.processor.utils.implementsClass +import com.raizlabs.android.dbflow.processor.utils.isNullOrEmpty import com.raizlabs.android.dbflow.sql.QueryBuilder -import com.squareup.javapoet.* +import com.squareup.javapoet.ArrayTypeName +import com.squareup.javapoet.ClassName +import com.squareup.javapoet.CodeBlock +import com.squareup.javapoet.NameAllocator +import com.squareup.javapoet.ParameterizedTypeName +import com.squareup.javapoet.TypeName +import com.squareup.javapoet.TypeSpec +import com.squareup.javapoet.WildcardTypeName import java.util.* import java.util.concurrent.atomic.AtomicInteger -import javax.lang.model.element.Element import javax.lang.model.element.ExecutableElement import javax.lang.model.element.Modifier import javax.lang.model.element.TypeElement @@ -30,8 +68,6 @@ class TableDefinition(manager: ProcessorManager, element: TypeElement) : BaseTab var tableName: String? = null - var databaseTypeName: TypeName? = null - var insertConflictActionName: String = "" var updateConflictActionName: String = "" @@ -39,7 +75,7 @@ class TableDefinition(manager: ProcessorManager, element: TypeElement) : BaseTab var primaryKeyConflictActionName: String = "" val _primaryColumnDefinitions = mutableListOf() - val foreignKeyDefinitions = mutableListOf() + val foreignKeyDefinitions = mutableListOf() val uniqueGroupsDefinitions = mutableListOf() val indexGroupsDefinitions = mutableListOf() @@ -56,6 +92,8 @@ class TableDefinition(manager: ProcessorManager, element: TypeElement) : BaseTab var customCacheFieldName: String? = null var customMultiCacheFieldName: String? = null + var createWithDatabase = true + var allFields = false var useIsForPrivateBooleans: Boolean = false @@ -92,6 +130,8 @@ class TableDefinition(manager: ProcessorManager, element: TypeElement) : BaseTab orderedCursorLookUp = table.orderedCursorLookUp assignDefaultValuesFromCursor = table.assignDefaultValuesFromCursor + createWithDatabase = table.createWithDatabase + allFields = table.allFields useIsForPrivateBooleans = table.useBooleanGetterSetters @@ -244,25 +284,25 @@ class TableDefinition(manager: ProcessorManager, element: TypeElement) : BaseTab val isPrimary = element.annotation() != null val isInherited = inheritedColumnMap.containsKey(element.simpleName.toString()) val isInheritedPrimaryKey = inheritedPrimaryKeyMap.containsKey(element.simpleName.toString()) + val isColumnMap = element.annotation() != null if (element.annotation() != null || isForeign || isPrimary - || isAllFields || isInherited || isInheritedPrimaryKey) { + || isAllFields || isInherited || isInheritedPrimaryKey || isColumnMap) { if (checkInheritancePackagePrivate(isPackagePrivateNotInSamePackage, element)) return - val columnDefinition: ColumnDefinition - if (isInheritedPrimaryKey) { + val columnDefinition = if (isInheritedPrimaryKey) { val inherited = inheritedPrimaryKeyMap[element.simpleName.toString()] - columnDefinition = ColumnDefinition(manager, element, this, isPackagePrivateNotInSamePackage, + ColumnDefinition(manager, element, this, isPackagePrivateNotInSamePackage, inherited?.column, inherited?.primaryKey) } else if (isInherited) { val inherited = inheritedColumnMap[element.simpleName.toString()] - columnDefinition = ColumnDefinition(manager, element, this, isPackagePrivateNotInSamePackage, + ColumnDefinition(manager, element, this, isPackagePrivateNotInSamePackage, inherited?.column, null, inherited?.nonNullConflict ?: ConflictAction.NONE) - } else if (isForeign) { - columnDefinition = ForeignKeyColumnDefinition(manager, this, + } else if (isForeign || isColumnMap) { + ReferenceColumnDefinition(manager, this, element, isPackagePrivateNotInSamePackage) } else { - columnDefinition = ColumnDefinition(manager, element, + ColumnDefinition(manager, element, this, isPackagePrivateNotInSamePackage) } @@ -279,7 +319,7 @@ class TableDefinition(manager: ProcessorManager, element: TypeElement) : BaseTab hasRowID = true } - if (columnDefinition is ForeignKeyColumnDefinition) { + if (columnDefinition is ReferenceColumnDefinition && !columnDefinition.isColumnMap) { foreignKeyDefinitions.add(columnDefinition) } @@ -300,7 +340,7 @@ class TableDefinition(manager: ProcessorManager, element: TypeElement) : BaseTab } } } else if (element.annotation() != null) { - val oneToManyDefinition = OneToManyDefinition(element as ExecutableElement, manager) + val oneToManyDefinition = OneToManyDefinition(element as ExecutableElement, manager, elements) if (oneToManyValidator.validate(manager, oneToManyDefinition)) { oneToManyDefinitions.add(oneToManyDefinition) } @@ -323,11 +363,7 @@ class TableDefinition(manager: ProcessorManager, element: TypeElement) : BaseTab } override val primaryColumnDefinitions: List - get() = if (autoIncrementColumn != null) { - Lists.newArrayList(autoIncrementColumn!!) - } else { - _primaryColumnDefinitions - } + get() = autoIncrementColumn?.let { arrayListOf(it) } ?: _primaryColumnDefinitions override val extendsClass: TypeName? get() = ParameterizedTypeName.get(ClassNames.MODEL_ADAPTER, elementClassName) @@ -415,12 +451,17 @@ class TableDefinition(manager: ProcessorManager, element: TypeElement) : BaseTab modifiers(public, final) `return`(QueryBuilder.stripQuotes(autoIncrement.columnName).S) } + + `override fun`(ParameterizedTypeName.get(ClassNames.SINGLE_MODEL_SAVER, elementClassName!!), "createSingleModelSaver") { + modifiers(public, final) + `return`("new \$T<>()", ClassNames.AUTOINCREMENT_MODEL_SAVER) + } } } val saveForeignKeyFields = columnDefinitions - .filter { (it is ForeignKeyColumnDefinition) && it.saveForeignKeyModel } - .map { it as ForeignKeyColumnDefinition } + .filter { (it is ReferenceColumnDefinition) && it.saveForeignKeyModel } + .map { it as ReferenceColumnDefinition } if (saveForeignKeyFields.isNotEmpty()) { val code = CodeBlock.builder() saveForeignKeyFields.forEach { it.appendSaveMethod(code) } @@ -433,8 +474,8 @@ class TableDefinition(manager: ProcessorManager, element: TypeElement) : BaseTab } val deleteForeignKeyFields = columnDefinitions - .filter { (it is ForeignKeyColumnDefinition) && it.deleteForeignKeyModel } - .map { it as ForeignKeyColumnDefinition } + .filter { (it is ReferenceColumnDefinition) && it.deleteForeignKeyModel } + .map { it as ReferenceColumnDefinition } if (deleteForeignKeyFields.isNotEmpty()) { val code = CodeBlock.builder() deleteForeignKeyFields.forEach { it.appendDeleteMethod(code) } @@ -451,6 +492,13 @@ class TableDefinition(manager: ProcessorManager, element: TypeElement) : BaseTab `return`("ALL_COLUMN_PROPERTIES") } + if (!createWithDatabase) { + `override fun`(TypeName.BOOLEAN, "createWithDatabase") { + modifiers(public, final) + `return`(false.L) + } + } + if (cachingEnabled) { val singlePrimaryKey = primaryColumnDefinitions.size == 1 diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/UniqueGroupsDefinition.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/UniqueGroupsDefinition.kt index 90ad0edb0..eebeffd9a 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/UniqueGroupsDefinition.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/UniqueGroupsDefinition.kt @@ -3,7 +3,7 @@ package com.raizlabs.android.dbflow.processor.definition import com.raizlabs.android.dbflow.annotation.ConflictAction import com.raizlabs.android.dbflow.annotation.UniqueGroup import com.raizlabs.android.dbflow.processor.definition.column.ColumnDefinition -import com.raizlabs.android.dbflow.processor.definition.column.ForeignKeyColumnDefinition +import com.raizlabs.android.dbflow.processor.definition.column.ReferenceColumnDefinition import com.raizlabs.android.dbflow.sql.QueryBuilder import com.squareup.javapoet.CodeBlock import java.util.* @@ -31,8 +31,8 @@ class UniqueGroupsDefinition(uniqueGroup: UniqueGroup) { if (count > 0) { codeBuilder.add(",") } - if (it is ForeignKeyColumnDefinition) { - for (reference in it._foreignKeyReferenceDefinitionList) { + if (it is ReferenceColumnDefinition) { + for (reference in it._referenceDefinitionList) { codeBuilder.add(QueryBuilder.quote(reference.columnName)) } } else { diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ColumnAccessor.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ColumnAccessor.kt index 6872ef07f..fc148e86b 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ColumnAccessor.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ColumnAccessor.kt @@ -1,6 +1,5 @@ package com.raizlabs.android.dbflow.processor.definition.column -import com.google.common.collect.Maps import com.grosner.kpoet.code import com.raizlabs.android.dbflow.data.Blob import com.raizlabs.android.dbflow.processor.utils.capitalizeFirstLetter @@ -158,7 +157,7 @@ class PackagePrivateScopeColumnAccessor( val classSuffix = "Helper" - private val methodWrittenMap = Maps.newHashMap>() + private val methodWrittenMap = hashMapOf>() fun containsColumn(className: ClassName, columnName: String): Boolean { return methodWrittenMap[className]?.contains(columnName) ?: false diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ColumnDefinition.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ColumnDefinition.kt index 78a3580f8..2042762ab 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ColumnDefinition.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ColumnDefinition.kt @@ -1,7 +1,14 @@ package com.raizlabs.android.dbflow.processor.definition.column import com.grosner.kpoet.code -import com.raizlabs.android.dbflow.annotation.* +import com.raizlabs.android.dbflow.annotation.Collate +import com.raizlabs.android.dbflow.annotation.Column +import com.raizlabs.android.dbflow.annotation.ConflictAction +import com.raizlabs.android.dbflow.annotation.Index +import com.raizlabs.android.dbflow.annotation.IndexGroup +import com.raizlabs.android.dbflow.annotation.NotNull +import com.raizlabs.android.dbflow.annotation.PrimaryKey +import com.raizlabs.android.dbflow.annotation.Unique import com.raizlabs.android.dbflow.data.Blob import com.raizlabs.android.dbflow.processor.ClassNames import com.raizlabs.android.dbflow.processor.ProcessorManager @@ -9,9 +16,22 @@ import com.raizlabs.android.dbflow.processor.definition.BaseDefinition import com.raizlabs.android.dbflow.processor.definition.BaseTableDefinition import com.raizlabs.android.dbflow.processor.definition.TableDefinition import com.raizlabs.android.dbflow.processor.definition.TypeConverterDefinition -import com.raizlabs.android.dbflow.processor.utils.* +import com.raizlabs.android.dbflow.processor.utils.annotation +import com.raizlabs.android.dbflow.processor.utils.fromTypeMirror +import com.raizlabs.android.dbflow.processor.utils.getTypeElement +import com.raizlabs.android.dbflow.processor.utils.isNullOrEmpty +import com.raizlabs.android.dbflow.processor.utils.toClassName +import com.raizlabs.android.dbflow.processor.utils.toTypeElement import com.raizlabs.android.dbflow.sql.QueryBuilder -import com.squareup.javapoet.* +import com.squareup.javapoet.ArrayTypeName +import com.squareup.javapoet.ClassName +import com.squareup.javapoet.CodeBlock +import com.squareup.javapoet.FieldSpec +import com.squareup.javapoet.MethodSpec +import com.squareup.javapoet.NameAllocator +import com.squareup.javapoet.ParameterizedTypeName +import com.squareup.javapoet.TypeName +import com.squareup.javapoet.TypeSpec import java.util.* import java.util.concurrent.atomic.AtomicInteger import java.util.regex.Pattern @@ -99,7 +119,7 @@ constructor(processorManager: ProcessorManager, element: Element, } element.annotationMirrors - .find { it.annotationType.toTypeElement().toClassName() == ClassNames.NON_NULL }?.let { + .find { it.annotationType.toTypeElement().toClassName() == ClassNames.NON_NULL }?.let { isNotNullType = true } @@ -124,13 +144,13 @@ constructor(processorManager: ProcessorManager, element: Element, val isString = (elementTypeName == ClassName.get(String::class.java)) if (defaultValue != null - && isString - && !QUOTE_PATTERN.matcher(defaultValue).find()) { + && isString + && !QUOTE_PATTERN.matcher(defaultValue).find()) { defaultValue = "\"" + defaultValue + "\"" } if (isNotNullType && defaultValue == null - && isString) { + && isString) { defaultValue = "\"\"" } @@ -139,19 +159,19 @@ constructor(processorManager: ProcessorManager, element: Element, if (isPackagePrivate) { columnAccessor = PackagePrivateScopeColumnAccessor(elementName, packageName, - baseTableDefinition.databaseDefinition?.classSeparator, - ClassName.get(element.enclosingElement as TypeElement).simpleName()) + baseTableDefinition.databaseDefinition?.classSeparator, + ClassName.get(element.enclosingElement as TypeElement).simpleName()) PackagePrivateScopeColumnAccessor.putElement( - (columnAccessor as PackagePrivateScopeColumnAccessor).helperClassName, - columnName) + (columnAccessor as PackagePrivateScopeColumnAccessor).helperClassName, + columnName) } else { val isPrivate = element.modifiers.contains(Modifier.PRIVATE) if (isPrivate) { val isBoolean = elementTypeName?.box() == TypeName.BOOLEAN.box() val useIs = isBoolean - && baseTableDefinition is TableDefinition && (baseTableDefinition as TableDefinition).useIsForPrivateBooleans + && baseTableDefinition is TableDefinition && (baseTableDefinition as TableDefinition).useIsForPrivateBooleans columnAccessor = PrivateScopeColumnAccessor(elementName, object : GetterSetter { override val getterName: String = column?.getterName ?: "" override val setterName: String = column?.setterName ?: "" @@ -200,7 +220,7 @@ constructor(processorManager: ProcessorManager, element: Element, hasCustomConverter = false if (typeConverterClassName != null && typeMirror != null && - typeConverterClassName != ClassNames.TYPE_CONVERTER) { + typeConverterClassName != ClassNames.TYPE_CONVERTER) { typeConverterDefinition = TypeConverterDefinition(typeConverterClassName, typeMirror, manager) evaluateTypeConverter(typeConverterDefinition, true) } @@ -218,7 +238,7 @@ constructor(processorManager: ProcessorManager, element: Element, // do nothing, for now. } else if (elementTypeName is ArrayTypeName) { processorManager.messager.printMessage(Diagnostic.Kind.ERROR, - "Columns cannot be of array type.") + "Columns cannot be of array type.") } else { if (elementTypeName == TypeName.BOOLEAN) { wrapperAccessor = BooleanColumnAccessor() @@ -238,7 +258,7 @@ constructor(processorManager: ProcessorManager, element: Element, } combiner = Combiner(columnAccessor, elementTypeName!!, wrapperAccessor, wrapperTypeName, - subWrapperAccessor) + subWrapperAccessor) } private fun evaluateTypeConverter(typeConverterDefinition: TypeConverterDefinition?, @@ -248,7 +268,7 @@ constructor(processorManager: ProcessorManager, element: Element, if (it.modelTypeName != elementTypeName) { manager.logError("The specified custom TypeConverter's Model Value ${it.modelTypeName}" + - " from ${it.className} must match the type of the column $elementTypeName. ") + " from ${it.className} must match the type of the column $elementTypeName. ") } else { hasTypeConverter = true hasCustomConverter = isCustom @@ -275,7 +295,7 @@ constructor(processorManager: ProcessorManager, element: Element, if (tableDef is TableDefinition) { tableName = tableDef.tableName ?: "" } - return "${baseTableDefinition.databaseDefinition?.databaseName}.$tableName.${QueryBuilder.quote(columnName)}" + return "${baseTableDefinition.databaseDefinition?.databaseClassName}.$tableName.${QueryBuilder.quote(columnName)}" } open fun addPropertyDefinition(typeBuilder: TypeSpec.Builder, tableClass: TypeName) { @@ -292,21 +312,21 @@ constructor(processorManager: ProcessorManager, element: Element, } val fieldBuilder = FieldSpec.builder(propParam, - propertyFieldName, Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) + propertyFieldName, Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) if (isNonPrimitiveTypeConverter) { val codeBlock = CodeBlock.builder() codeBlock.add("new \$T(\$T.class, \$S, true,", propParam, tableClass, columnName) codeBlock.add("\nnew \$T() {" + - "\n@Override" + - "\npublic \$T getTypeConverter(Class modelClass) {" + - "\n \$T adapter = (\$T) \$T.getInstanceAdapter(modelClass);" + - "\nreturn adapter.\$L;" + - "\n}" + - "\n})", ClassNames.TYPE_CONVERTER_GETTER, ClassNames.TYPE_CONVERTER, - baseTableDefinition.outputClassName, baseTableDefinition.outputClassName, - ClassNames.FLOW_MANAGER, - (wrapperAccessor as TypeConverterScopeColumnAccessor).typeConverterFieldName) + "\n@Override" + + "\npublic \$T getTypeConverter(Class modelClass) {" + + "\n \$T adapter = (\$T) \$T.getInstanceAdapter(modelClass);" + + "\nreturn adapter.\$L;" + + "\n}" + + "\n})", ClassNames.TYPE_CONVERTER_GETTER, ClassNames.TYPE_CONVERTER, + baseTableDefinition.outputClassName, baseTableDefinition.outputClassName, + ClassNames.FLOW_MANAGER, + (wrapperAccessor as TypeConverterScopeColumnAccessor).typeConverterFieldName) fieldBuilder.initializer(codeBlock.build()) } else { fieldBuilder.initializer("new \$T(\$T.class, \$S)", propParam, tableClass, columnName) @@ -355,7 +375,7 @@ constructor(processorManager: ProcessorManager, element: Element, defineProperty: Boolean = true) = code { SqliteStatementAccessCombiner(combiner).apply { addCode(if (useStart) "start" else "", getDefaultValueBlock(), index.get(), modelBlock, - defineProperty) + defineProperty) } this } @@ -370,8 +390,8 @@ constructor(processorManager: ProcessorManager, element: Element, } LoadFromCursorAccessCombiner(combiner, defaultValue != null, - nameAllocator, baseTableDefinition.orderedCursorLookUp, - assignDefaultValue).apply { + nameAllocator, baseTableDefinition.orderedCursorLookUp, + assignDefaultValue).apply { addCode(columnName, getDefaultValueBlock(), index.get(), modelBlock) } this @@ -406,10 +426,10 @@ constructor(processorManager: ProcessorManager, element: Element, open fun appendExistenceMethod(codeBuilder: CodeBlock.Builder) { ExistenceAccessCombiner(combiner, isRowId || isPrimaryKeyAutoIncrement, - isQuickCheckPrimaryKeyAutoIncrement, baseTableDefinition.elementClassName!!) - .apply { - codeBuilder.addCode(columnName, getDefaultValueBlock(), 0, modelBlock) - } + isQuickCheckPrimaryKeyAutoIncrement, baseTableDefinition.elementClassName!!) + .apply { + codeBuilder.addCode(columnName, getDefaultValueBlock(), 0, modelBlock) + } } open fun appendPropertyComparisonAccessStatement(codeBuilder: CodeBlock.Builder) { @@ -426,9 +446,9 @@ constructor(processorManager: ProcessorManager, element: Element, codeBlockBuilder.add(" PRIMARY KEY ") if (baseTableDefinition is TableDefinition && - !(baseTableDefinition as TableDefinition).primaryKeyConflictActionName.isNullOrEmpty()) { + !(baseTableDefinition as TableDefinition).primaryKeyConflictActionName.isNullOrEmpty()) { codeBlockBuilder.add("ON CONFLICT \$L ", - (baseTableDefinition as TableDefinition).primaryKeyConflictActionName) + (baseTableDefinition as TableDefinition).primaryKeyConflictActionName) } codeBlockBuilder.add("AUTOINCREMENT") @@ -446,9 +466,8 @@ constructor(processorManager: ProcessorManager, element: Element, codeBlockBuilder.add(" UNIQUE ON CONFLICT \$L", onUniqueConflict) } - if (notNull) { - codeBlockBuilder.add(" NOT NULL") + codeBlockBuilder.add(" NOT NULL ON CONFLICT \$L", onNullConflict) } return codeBlockBuilder.build() @@ -465,8 +484,8 @@ constructor(processorManager: ProcessorManager, element: Element, if (elementTypeName == TypeName.BOOLEAN) { defaultValue = "false" } else if (elementTypeName == TypeName.BYTE || elementTypeName == TypeName.INT - || elementTypeName == TypeName.DOUBLE || elementTypeName == TypeName.FLOAT - || elementTypeName == TypeName.LONG || elementTypeName == TypeName.SHORT) { + || elementTypeName == TypeName.DOUBLE || elementTypeName == TypeName.FLOAT + || elementTypeName == TypeName.LONG || elementTypeName == TypeName.SHORT) { defaultValue = "($elementTypeName) 0" } else if (elementTypeName == TypeName.CHAR) { defaultValue = "'\\u0000'" diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ForeignKeyColumnDefinition.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ReferenceColumnDefinition.kt similarity index 54% rename from dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ForeignKeyColumnDefinition.kt rename to dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ReferenceColumnDefinition.kt index d60cfe79c..0dc5676a7 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ForeignKeyColumnDefinition.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ReferenceColumnDefinition.kt @@ -3,16 +3,34 @@ package com.raizlabs.android.dbflow.processor.definition.column import com.grosner.kpoet.S import com.grosner.kpoet.`return` import com.grosner.kpoet.case +import com.raizlabs.android.dbflow.annotation.ColumnMap +import com.raizlabs.android.dbflow.annotation.ConflictAction import com.raizlabs.android.dbflow.annotation.ForeignKey import com.raizlabs.android.dbflow.annotation.ForeignKeyAction import com.raizlabs.android.dbflow.annotation.ForeignKeyReference +import com.raizlabs.android.dbflow.annotation.QueryModel import com.raizlabs.android.dbflow.annotation.Table import com.raizlabs.android.dbflow.processor.ClassNames import com.raizlabs.android.dbflow.processor.ProcessorManager +import com.raizlabs.android.dbflow.processor.definition.BaseTableDefinition +import com.raizlabs.android.dbflow.processor.definition.QueryModelDefinition import com.raizlabs.android.dbflow.processor.definition.TableDefinition -import com.raizlabs.android.dbflow.processor.utils.* +import com.raizlabs.android.dbflow.processor.utils.annotation +import com.raizlabs.android.dbflow.processor.utils.fromTypeMirror +import com.raizlabs.android.dbflow.processor.utils.implementsClass +import com.raizlabs.android.dbflow.processor.utils.isNullOrEmpty +import com.raizlabs.android.dbflow.processor.utils.isSubclass +import com.raizlabs.android.dbflow.processor.utils.toTypeElement +import com.raizlabs.android.dbflow.processor.utils.toTypeErasedElement import com.raizlabs.android.dbflow.sql.QueryBuilder -import com.squareup.javapoet.* +import com.squareup.javapoet.ClassName +import com.squareup.javapoet.CodeBlock +import com.squareup.javapoet.FieldSpec +import com.squareup.javapoet.MethodSpec +import com.squareup.javapoet.NameAllocator +import com.squareup.javapoet.ParameterizedTypeName +import com.squareup.javapoet.TypeName +import com.squareup.javapoet.TypeSpec import java.util.* import java.util.concurrent.atomic.AtomicInteger import javax.lang.model.element.Element @@ -20,15 +38,16 @@ import javax.lang.model.element.Modifier import javax.lang.model.type.MirroredTypeException /** - * Description: + * Description: Represents both a [ForeignKey] and [ColumnMap]. Builds up the model of fields + * required to generate definitions. */ -class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: TableDefinition, - element: Element, isPackagePrivate: Boolean) +class ReferenceColumnDefinition(manager: ProcessorManager, tableDefinition: BaseTableDefinition, + element: Element, isPackagePrivate: Boolean) : ColumnDefinition(manager, element, tableDefinition, isPackagePrivate) { - val _foreignKeyReferenceDefinitionList: MutableList = ArrayList() + val _referenceDefinitionList: MutableList = ArrayList() - var referencedTableClassName: ClassName? = null + var referencedClassName: ClassName? = null var onDelete = ForeignKeyAction.NO_ACTION var onUpdate = ForeignKeyAction.NO_ACTION @@ -39,7 +58,7 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab var implementsModel = false var extendsBaseModel = false - var references: List? = null + var references: List? = null var nonModelColumn: Boolean = false @@ -50,12 +69,37 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab var deferred = false + var isColumnMap = false + override val typeConverterElementNames: List - get() = _foreignKeyReferenceDefinitionList.filter { it.hasTypeConverter }.map { it.columnClassName } + get() = _referenceDefinitionList.filter { it.hasTypeConverter }.map { it.columnClassName } init { + element.annotation()?.let { + isColumnMap = true + // column map is stubbed + isStubbedRelationship = true + findReferencedClassName(manager) + + typeElement?.let { typeElement -> + QueryModelDefinition(typeElement, manager).apply { + databaseTypeName = tableDefinition.databaseTypeName + manager.addQueryModelDefinition(this) + } + } + + references = it.references.map { + ReferenceSpecificationDefinition(columnName = it.columnName, + referenceName = it.columnMapFieldName, + onNullConflictAction = it.notNull.onNullConflict) + } + } + element.annotation()?.let { foreignKey -> + if (tableDefinition !is TableDefinition) { + manager.logError("Class $elementName cannot declare a @ForeignKey. Use @ColumnMap instead.") + } onUpdate = foreignKey.onUpdate onDelete = foreignKey.onDelete @@ -65,26 +109,17 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab try { foreignKey.tableClass } catch (mte: MirroredTypeException) { - referencedTableClassName = fromTypeMirror(mte.typeMirror, manager) + referencedClassName = fromTypeMirror(mte.typeMirror, manager) } val erasedElement = element.toTypeErasedElement() // hopefully intentionally left blank - if (referencedTableClassName == TypeName.OBJECT) { - if (elementTypeName is ParameterizedTypeName) { - val args = (elementTypeName as ParameterizedTypeName).typeArguments - if (args.size > 0) { - referencedTableClassName = ClassName.get(args[0].toTypeElement(manager)) - } - } else { - if (referencedTableClassName == null || referencedTableClassName == ClassName.OBJECT) { - referencedTableClassName = ClassName.get(elementTypeName.toTypeElement()) - } - } + if (referencedClassName == TypeName.OBJECT) { + findReferencedClassName(manager) } - if (referencedTableClassName == null) { + if (referencedClassName == null) { manager.logError("Referenced was null for $element within $elementTypeName") } @@ -97,18 +132,35 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab saveForeignKeyModel = foreignKey.saveForeignKeyModel deleteForeignKeyModel = foreignKey.deleteForeignKeyModel - references = foreignKey.references.asList() + references = foreignKey.references.map { + ReferenceSpecificationDefinition(columnName = it.columnName, + referenceName = it.foreignKeyColumnName, + onNullConflictAction = it.notNull.onNullConflict) + } } if (isNotNullType) { manager.logError("Foreign Keys must be nullable. Please remove the non-null annotation if using " + - "Java, or add ? to the type for Kotlin.") + "Java, or add ? to the type for Kotlin.") + } + } + + private fun findReferencedClassName(manager: ProcessorManager) { + if (elementTypeName is ParameterizedTypeName) { + val args = (elementTypeName as ParameterizedTypeName).typeArguments + if (args.size > 0) { + referencedClassName = ClassName.get(args[0].toTypeElement(manager)) + } + } else { + if (referencedClassName == null || referencedClassName == ClassName.OBJECT) { + referencedClassName = elementTypeName.toTypeElement()?.let { ClassName.get(it) } + } } } override fun addPropertyDefinition(typeBuilder: TypeSpec.Builder, tableClass: TypeName) { checkNeedsReferences() - _foreignKeyReferenceDefinitionList.forEach { + _referenceDefinitionList.forEach { var propParam: TypeName? = null val colClassName = it.columnClassName colClassName?.let { @@ -116,18 +168,18 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab } if (it.columnName.isNullOrEmpty()) { manager.logError("Found empty reference name at ${it.foreignColumnName}" + - " from table ${baseTableDefinition.elementName}") + " from table ${baseTableDefinition.elementName}") } typeBuilder.addField(FieldSpec.builder(propParam, it.columnName, - Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) - .initializer("new \$T(\$T.class, \$S)", propParam, tableClass, it.columnName) - .addJavadoc("Foreign Key" + if (isPrimaryKey) " / Primary Key" else "").build()) + Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) + .initializer("new \$T(\$T.class, \$S)", propParam, tableClass, it.columnName) + .addJavadoc(if (isColumnMap) "Column Mapped Field" else ("Foreign Key" + if (isPrimaryKey) " / Primary Key" else "")).build()) } } override fun addPropertyCase(methodBuilder: MethodSpec.Builder) { checkNeedsReferences() - _foreignKeyReferenceDefinitionList.forEach { + _referenceDefinitionList.forEach { methodBuilder.case(QueryBuilder.quoteIfNeeded(it.columnName).S) { `return`(it.columnName) } @@ -139,7 +191,7 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab super.appendIndexInitializer(initializer, index) } else { checkNeedsReferences() - _foreignKeyReferenceDefinitionList.forEach { + _referenceDefinitionList.forEach { if (index.get() > 0) { initializer.add(", ") } @@ -151,8 +203,8 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab override fun addColumnName(codeBuilder: CodeBlock.Builder) { checkNeedsReferences() - for (i in _foreignKeyReferenceDefinitionList.indices) { - val reference = _foreignKeyReferenceDefinitionList[i] + for (i in _referenceDefinitionList.indices) { + val reference = _referenceDefinitionList[i] if (i > 0) { codeBuilder.add(",") } @@ -164,11 +216,11 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab get() { checkNeedsReferences() val builder = CodeBlock.builder() - _foreignKeyReferenceDefinitionList.indices.forEach { i -> + _referenceDefinitionList.indices.forEach { i -> if (i > 0) { builder.add(",") } - val referenceDefinition = _foreignKeyReferenceDefinitionList[i] + val referenceDefinition = _referenceDefinitionList[i] builder.add(CodeBlock.of("${QueryBuilder.quote(referenceDefinition.columnName)}=?")) } return builder.build() @@ -178,11 +230,11 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab get() { checkNeedsReferences() val builder = CodeBlock.builder() - _foreignKeyReferenceDefinitionList.indices.forEach { i -> + _referenceDefinitionList.indices.forEach { i -> if (i > 0) { builder.add(",") } - val referenceDefinition = _foreignKeyReferenceDefinitionList[i] + val referenceDefinition = _referenceDefinitionList[i] builder.add(QueryBuilder.quote(referenceDefinition.columnName)) } return builder.build() @@ -192,7 +244,7 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab get() { checkNeedsReferences() val builder = CodeBlock.builder() - _foreignKeyReferenceDefinitionList.indices.forEach { i -> + _referenceDefinitionList.indices.forEach { i -> if (i > 0) { builder.add(",") } @@ -205,12 +257,16 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab get() { checkNeedsReferences() val builder = CodeBlock.builder() - _foreignKeyReferenceDefinitionList.indices.forEach { i -> + _referenceDefinitionList.indices.forEach { i -> if (i > 0) { builder.add(" ,") } - val referenceDefinition = _foreignKeyReferenceDefinitionList[i] + val referenceDefinition = _referenceDefinitionList[i] builder.add(referenceDefinition.creationStatement) + + if (referenceDefinition.notNull) { + builder.add(" NOT NULL ON CONFLICT \$L", referenceDefinition.onNullConflict) + } } return builder.build() } @@ -219,11 +275,11 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab get() { checkNeedsReferences() val builder = CodeBlock.builder() - _foreignKeyReferenceDefinitionList.indices.forEach { i -> + _referenceDefinitionList.indices.forEach { i -> if (i > 0) { builder.add(" ,") } - val referenceDefinition = _foreignKeyReferenceDefinitionList[i] + val referenceDefinition = _referenceDefinitionList[i] builder.add(referenceDefinition.primaryKeyName) } return builder.build().toString() @@ -235,9 +291,9 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab } else { checkNeedsReferences() val codeBuilder = CodeBlock.builder() - referencedTableClassName?.let { + referencedClassName?.let { val foreignKeyCombiner = ForeignKeyAccessCombiner(columnAccessor) - _foreignKeyReferenceDefinitionList.forEach { + _referenceDefinitionList.forEach { foreignKeyCombiner.fieldAccesses += it.contentValuesField } foreignKeyCombiner.addCode(codeBuilder, AtomicInteger(0)) @@ -252,9 +308,9 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab } else { checkNeedsReferences() val codeBuilder = CodeBlock.builder() - referencedTableClassName?.let { + referencedClassName?.let { val foreignKeyCombiner = ForeignKeyAccessCombiner(columnAccessor) - _foreignKeyReferenceDefinitionList.forEach { + _referenceDefinitionList.forEach { foreignKeyCombiner.fieldAccesses += it.sqliteStatementField } foreignKeyCombiner.addCode(codeBuilder, index, useStart, defineProperty) @@ -270,15 +326,15 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab checkNeedsReferences() val code = CodeBlock.builder() - referencedTableClassName?.let { referencedTableClassName -> + referencedClassName?.let { referencedTableClassName -> - val tableDefinition = manager.getTableDefinition(baseTableDefinition.databaseDefinition?.elementTypeName, - referencedTableClassName) + val tableDefinition = manager.getReferenceDefinition( + baseTableDefinition.databaseDefinition?.elementTypeName, referencedTableClassName) val outputClassName = tableDefinition?.outputClassName outputClassName?.let { val foreignKeyCombiner = ForeignKeyLoadFromCursorCombiner(columnAccessor, - referencedTableClassName, outputClassName, isStubbedRelationship, nameAllocator) - _foreignKeyReferenceDefinitionList.forEach { + referencedTableClassName, outputClassName, isStubbedRelationship, nameAllocator) + _referenceDefinitionList.forEach { foreignKeyCombiner.fieldAccesses += it.partialAccessor } foreignKeyCombiner.addCode(code, index) @@ -293,9 +349,9 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab super.appendPropertyComparisonAccessStatement(codeBuilder) } else { - referencedTableClassName?.let { + referencedClassName?.let { val foreignKeyCombiner = ForeignKeyAccessCombiner(columnAccessor) - _foreignKeyReferenceDefinitionList.forEach { + _referenceDefinitionList.forEach { foreignKeyCombiner.fieldAccesses += it.primaryReferenceField } foreignKeyCombiner.addCode(codeBuilder, AtomicInteger(0)) @@ -305,10 +361,10 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab fun appendSaveMethod(codeBuilder: CodeBlock.Builder) { if (!nonModelColumn && columnAccessor !is TypeConverterScopeColumnAccessor) { - referencedTableClassName?.let { referencedTableClassName -> + referencedClassName?.let { referencedTableClassName -> val saveAccessor = ForeignKeyAccessField(columnName, - SaveModelAccessCombiner(Combiner(columnAccessor, referencedTableClassName, wrapperAccessor, - wrapperTypeName, subWrapperAccessor), implementsModel, extendsBaseModel)) + SaveModelAccessCombiner(Combiner(columnAccessor, referencedTableClassName, wrapperAccessor, + wrapperTypeName, subWrapperAccessor), implementsModel, extendsBaseModel)) saveAccessor.addCode(codeBuilder, 0, modelBlock) } } @@ -316,10 +372,10 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab fun appendDeleteMethod(codeBuilder: CodeBlock.Builder) { if (!nonModelColumn && columnAccessor !is TypeConverterScopeColumnAccessor) { - referencedTableClassName?.let { referencedTableClassName -> + referencedClassName?.let { referencedTableClassName -> val deleteAccessor = ForeignKeyAccessField(columnName, - DeleteModelAccessCombiner(Combiner(columnAccessor, referencedTableClassName, wrapperAccessor, - wrapperTypeName, subWrapperAccessor), implementsModel, extendsBaseModel)) + DeleteModelAccessCombiner(Combiner(columnAccessor, referencedTableClassName, wrapperAccessor, + wrapperTypeName, subWrapperAccessor), implementsModel, extendsBaseModel)) deleteAccessor.addCode(codeBuilder, 0, modelBlock) } } @@ -330,43 +386,52 @@ class ForeignKeyColumnDefinition(manager: ProcessorManager, tableDefinition: Tab * table. We do this post-evaluation so all of the [TableDefinition] can be generated. */ fun checkNeedsReferences() { - val tableDefinition = (baseTableDefinition as TableDefinition) - val referencedTableDefinition = manager.getTableDefinition( - tableDefinition.databaseTypeName, referencedTableClassName) + val tableDefinition = baseTableDefinition + val referencedTableDefinition = manager.getReferenceDefinition(tableDefinition.databaseTypeName, referencedClassName) if (referencedTableDefinition == null) { - manager.logError(ForeignKeyColumnDefinition::class, - "Could not find the referenced table definition $referencedTableClassName" + - " from ${tableDefinition.tableName}. " + - "Ensure it exists in the samedatabase ${tableDefinition.databaseTypeName}") + manager.logError(ReferenceColumnDefinition::class, + "Could not find the referenced ${Table::class.java.simpleName} " + + "or ${QueryModel::class.java.simpleName} definition $referencedClassName" + + " from ${tableDefinition.elementName}. " + + "Ensure it exists in the same database as ${tableDefinition.databaseTypeName}") } else if (needsReferences) { - val primaryColumns = referencedTableDefinition.primaryColumnDefinitions + val primaryColumns = + if (isColumnMap) referencedTableDefinition.columnDefinitions + else referencedTableDefinition.primaryColumnDefinitions if (references?.isEmpty() ?: true) { primaryColumns.forEach { - val foreignKeyReferenceDefinition = ForeignKeyReferenceDefinition(manager, - elementName, it.elementName, it, this, primaryColumns.size) - _foreignKeyReferenceDefinitionList.add(foreignKeyReferenceDefinition) + val foreignKeyReferenceDefinition = ReferenceDefinition(manager, + elementName, it.elementName, it, this, primaryColumns.size, + if (isColumnMap) it.elementName else "") + _referenceDefinitionList.add(foreignKeyReferenceDefinition) } needsReferences = false } else { references?.forEach { reference -> - val foundDefinition = primaryColumns.find { it.columnName == reference.foreignKeyColumnName } + val foundDefinition = primaryColumns.find { it.columnName == reference.referenceName } if (foundDefinition == null) { - manager.logError(ForeignKeyColumnDefinition::class, - "Could not find referenced column ${reference.foreignKeyColumnName} " + - "from reference named ${reference.columnName}") + manager.logError(ReferenceColumnDefinition::class, + "Could not find referenced column ${reference.referenceName} " + + "from reference named ${reference.columnName}") } else { - _foreignKeyReferenceDefinitionList.add( - ForeignKeyReferenceDefinition(manager, elementName, - foundDefinition.elementName, foundDefinition, this, - primaryColumns.size, reference.columnName)) + _referenceDefinitionList.add( + ReferenceDefinition(manager, elementName, + foundDefinition.elementName, foundDefinition, this, + primaryColumns.size, reference.columnName, + reference.onNullConflictAction)) } } needsReferences = false } - if (nonModelColumn && _foreignKeyReferenceDefinitionList.size == 1) { - columnName = _foreignKeyReferenceDefinitionList[0].columnName + if (nonModelColumn && _referenceDefinitionList.size == 1) { + columnName = _referenceDefinitionList[0].columnName } } } } + +/** + * Description: defines a ForeignKeyReference or ColumnMapReference. + */ +class ReferenceSpecificationDefinition(val columnName: String, val referenceName: String, val onNullConflictAction: ConflictAction) \ No newline at end of file diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ForeignKeyReferenceDefinition.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ReferenceDefinition.kt similarity index 70% rename from dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ForeignKeyReferenceDefinition.kt rename to dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ReferenceDefinition.kt index 6b3387916..bf69f6104 100644 --- a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ForeignKeyReferenceDefinition.kt +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/definition/column/ReferenceDefinition.kt @@ -1,5 +1,6 @@ package com.raizlabs.android.dbflow.processor.definition.column +import com.raizlabs.android.dbflow.annotation.ConflictAction import com.raizlabs.android.dbflow.data.Blob import com.raizlabs.android.dbflow.processor.ProcessorManager import com.raizlabs.android.dbflow.processor.definition.TypeConverterDefinition @@ -14,16 +15,19 @@ import javax.lang.model.element.TypeElement /** * Description: */ -class ForeignKeyReferenceDefinition(private val manager: ProcessorManager, - foreignKeyFieldName: String, - foreignKeyElementName: String, referencedColumn: ColumnDefinition, - private val foreignKeyColumnDefinition: ForeignKeyColumnDefinition, - referenceCount: Int, localColumnName: String = "") { +class ReferenceDefinition(private val manager: ProcessorManager, + foreignKeyFieldName: String, + foreignKeyElementName: String, referencedColumn: ColumnDefinition, + private val referenceColumnDefinition: ReferenceColumnDefinition, + referenceCount: Int, localColumnName: String = "", + var onNullConflict: ConflictAction = ConflictAction.NONE) { val columnName: String val foreignColumnName: String val columnClassName: TypeName? + var notNull = false + var hasTypeConverter: Boolean = false internal val creationStatement: CodeBlock @@ -45,34 +49,34 @@ class ForeignKeyReferenceDefinition(private val manager: ProcessorManager, lateinit var contentValuesField: ForeignKeyAccessField lateinit var sqliteStatementField: ForeignKeyAccessField - private fun createScopes(foreignKeyColumnDefinition: ForeignKeyColumnDefinition, + private fun createScopes(referenceColumnDefinition: ReferenceColumnDefinition, foreignKeyFieldName: String, getterSetter: GetterSetter, name: String, packageName: String) { if (isReferencedFieldPrivate) { columnAccessor = PrivateScopeColumnAccessor(foreignKeyFieldName, getterSetter, false) } else if (isReferencedFieldPackagePrivate) { columnAccessor = PackagePrivateScopeColumnAccessor(foreignKeyFieldName, packageName, - foreignKeyColumnDefinition.baseTableDefinition.databaseDefinition?.classSeparator, - name) + referenceColumnDefinition.baseTableDefinition.databaseDefinition?.classSeparator, + name) PackagePrivateScopeColumnAccessor.putElement( - (columnAccessor as PackagePrivateScopeColumnAccessor).helperClassName, - foreignKeyFieldName) + (columnAccessor as PackagePrivateScopeColumnAccessor).helperClassName, + foreignKeyFieldName) } else { columnAccessor = VisibleScopeColumnAccessor(foreignKeyFieldName) } } - private fun createForeignKeyFields(columnClassName: TypeName?, foreignKeyColumnDefinition: ForeignKeyColumnDefinition, manager: ProcessorManager) { + private fun createForeignKeyFields(columnClassName: TypeName?, referenceColumnDefinition: ReferenceColumnDefinition, manager: ProcessorManager) { val typeConverterDefinition = columnClassName?.let { manager.getTypeConverterDefinition(it) } evaluateTypeConverter(typeConverterDefinition) val combiner = Combiner(columnAccessor, columnClassName!!, wrapperAccessor, - wrapperTypeName, subWrapperAccessor, foreignKeyColumnDefinition.elementName) + wrapperTypeName, subWrapperAccessor, referenceColumnDefinition.elementName) partialAccessor = PartialLoadFromCursorAccessCombiner(columnName, foreignColumnName, - columnClassName, foreignKeyColumnDefinition.baseTableDefinition.orderedCursorLookUp, - columnAccessor, wrapperAccessor, wrapperTypeName) + columnClassName, referenceColumnDefinition.baseTableDefinition.orderedCursorLookUp, + columnAccessor, wrapperAccessor, wrapperTypeName) primaryReferenceField = ForeignKeyAccessField(columnName, PrimaryReferenceAccessCombiner(combiner)) @@ -88,12 +92,12 @@ class ForeignKeyReferenceDefinition(private val manager: ProcessorManager, if (it.modelTypeName != columnClassName) { manager.logError("The specified custom TypeConverter's Model Value %1s from %1s must match the type of the column %1s. ", - it.modelTypeName, it.className, columnClassName) + it.modelTypeName, it.className, columnClassName) } else { hasTypeConverter = true - val fieldName = foreignKeyColumnDefinition.baseTableDefinition - .addColumnForTypeConverter(foreignKeyColumnDefinition, it.className) + val fieldName = referenceColumnDefinition.baseTableDefinition + .addColumnForTypeConverter(referenceColumnDefinition, it.className) wrapperAccessor = TypeConverterScopeColumnAccessor(fieldName) wrapperTypeName = it.dbTypeName @@ -108,9 +112,9 @@ class ForeignKeyReferenceDefinition(private val manager: ProcessorManager, init { if (!localColumnName.isNullOrEmpty()) { this.columnName = localColumnName - } else if (!foreignKeyColumnDefinition.isPrimaryKey && !foreignKeyColumnDefinition.isPrimaryKeyAutoIncrement - && !foreignKeyColumnDefinition.isRowId || referenceCount > 0) { - this.columnName = foreignKeyFieldName + "_" + referencedColumn.columnName + } else if (!referenceColumnDefinition.isPrimaryKey && !referenceColumnDefinition.isPrimaryKeyAutoIncrement + && !referenceColumnDefinition.isRowId || referenceCount > 0) { + this.columnName = "${foreignKeyFieldName}_${referencedColumn.columnName}" } else { this.columnName = foreignKeyFieldName } @@ -120,16 +124,18 @@ class ForeignKeyReferenceDefinition(private val manager: ProcessorManager, isReferencedFieldPackagePrivate = referencedColumn.columnAccessor is PackagePrivateScopeColumnAccessor val isPackagePrivate = ElementUtility.isPackagePrivate(referencedColumn.element) val isPackagePrivateNotInSamePackage = isPackagePrivate && - !ElementUtility.isInSamePackage(manager, referencedColumn.element, - foreignKeyColumnDefinition.element) + !ElementUtility.isInSamePackage(manager, referencedColumn.element, + referenceColumnDefinition.element) isReferencedFieldPackagePrivate = isReferencedFieldPackagePrivate || isPackagePrivateNotInSamePackage val packageName = referencedColumn.packageName val name = ClassName.get(referencedColumn.element.enclosingElement as TypeElement).simpleName() - createScopes(foreignKeyColumnDefinition, foreignKeyElementName, object : GetterSetter { + createScopes(referenceColumnDefinition, foreignKeyElementName, object : GetterSetter { override val getterName: String = referencedColumn.column?.getterName ?: "" override val setterName: String = referencedColumn.column?.setterName ?: "" }, name, packageName) - createForeignKeyFields(columnClassName, foreignKeyColumnDefinition, manager) + createForeignKeyFields(columnClassName, referenceColumnDefinition, manager) + + notNull = onNullConflict != ConflictAction.NONE } diff --git a/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/utils/DependencyUtils.kt b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/utils/DependencyUtils.kt new file mode 100644 index 000000000..20d449c8a --- /dev/null +++ b/dbflow-processor/src/main/java/com/raizlabs/android/dbflow/processor/utils/DependencyUtils.kt @@ -0,0 +1,8 @@ +package com.raizlabs.android.dbflow.processor.utils + +import com.raizlabs.android.dbflow.processor.ProcessorManager + +/** + * Used to check if class exists on class path, if so, we add the annotation to generated class files. + */ +fun hasJavaX() = ProcessorManager.manager.elements.getTypeElement("javax.annotation.Generated") != null \ No newline at end of file diff --git a/dbflow-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/dbflow-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 000000000..0d2dfaf75 --- /dev/null +++ b/dbflow-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +com.raizlabs.android.dbflow.processor.DBFlowProcessor \ No newline at end of file diff --git a/dbflow-rx-kotlinextensions/build.gradle b/dbflow-rx-kotlinextensions/build.gradle index 2639eee94..225aeaadc 100644 --- a/dbflow-rx-kotlinextensions/build.gradle +++ b/dbflow-rx-kotlinextensions/build.gradle @@ -14,9 +14,9 @@ android { } dependencies { - compile project("${dbflow_project_prefix}dbflow") - compile project("${dbflow_project_prefix}dbflow-rx") - compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" + api project("${dbflow_project_prefix}dbflow") + api project("${dbflow_project_prefix}dbflow-rx") + api "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" } apply from: '../kotlin-artifacts.gradle' diff --git a/dbflow-rx/build.gradle b/dbflow-rx/build.gradle index 04eb99e43..ef9aeeb3a 100644 --- a/dbflow-rx/build.gradle +++ b/dbflow-rx/build.gradle @@ -18,8 +18,8 @@ android { } dependencies { - compile project("${dbflow_project_prefix}dbflow") - compile 'io.reactivex:rxjava:1.2.7' + api project("${dbflow_project_prefix}dbflow") + api 'io.reactivex:rxjava:1.2.7' } apply from: '../android-artifacts.gradle' diff --git a/dbflow-rx/src/main/java/com/raizlabs/android/dbflow/rx/language/RXQueriable.java b/dbflow-rx/src/main/java/com/raizlabs/android/dbflow/rx/language/RXQueriable.java index 4de14bcbe..4c86a2e77 100644 --- a/dbflow-rx/src/main/java/com/raizlabs/android/dbflow/rx/language/RXQueriable.java +++ b/dbflow-rx/src/main/java/com/raizlabs/android/dbflow/rx/language/RXQueriable.java @@ -2,7 +2,6 @@ import android.database.Cursor; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import com.raizlabs.android.dbflow.sql.language.Delete; import com.raizlabs.android.dbflow.sql.language.Insert; @@ -50,14 +49,28 @@ public interface RXQueriable { /** * @return the count of the results of the query. + * @deprecated use {@link #longValue()} */ @NonNull Single count(); + /** + * @return the long value of this query. + **/ + @NonNull + Single longValue(); + + /** + * @return the long value of this query. + **/ + @NonNull + Single longValue(DatabaseWrapper databaseWrapper); + /** * Allows you to pass in a {@link DatabaseWrapper} manually. * * @return the count of the results of the query. + * @deprecated use {@link #longValue(DatabaseWrapper)} */ @NonNull Single count(DatabaseWrapper databaseWrapper); diff --git a/dbflow-rx/src/main/java/com/raizlabs/android/dbflow/rx/language/RXQueriableImpl.java b/dbflow-rx/src/main/java/com/raizlabs/android/dbflow/rx/language/RXQueriableImpl.java index 431a5fa69..e50e73f12 100644 --- a/dbflow-rx/src/main/java/com/raizlabs/android/dbflow/rx/language/RXQueriableImpl.java +++ b/dbflow-rx/src/main/java/com/raizlabs/android/dbflow/rx/language/RXQueriableImpl.java @@ -98,6 +98,28 @@ public Long call() throws Exception { }); } + @NonNull + @Override + public Single longValue() { + return fromCallable(new Callable() { + @Override + public Long call() throws Exception { + return getInnerQueriable().longValue(); + } + }); + } + + @NonNull + @Override + public Single longValue(final DatabaseWrapper databaseWrapper) { + return fromCallable(new Callable() { + @Override + public Long call() throws Exception { + return getInnerQueriable().longValue(databaseWrapper); + } + }); + } + @NonNull @Override public Single executeInsert() { diff --git a/dbflow-rx2-kotlinextensions/build.gradle b/dbflow-rx2-kotlinextensions/build.gradle index 229098257..415af0113 100644 --- a/dbflow-rx2-kotlinextensions/build.gradle +++ b/dbflow-rx2-kotlinextensions/build.gradle @@ -14,9 +14,9 @@ android { } dependencies { - compile project("${dbflow_project_prefix}dbflow") - compile project("${dbflow_project_prefix}dbflow-rx2") - compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" + api project("${dbflow_project_prefix}dbflow") + api project("${dbflow_project_prefix}dbflow-rx2") + api "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" } apply from: '../kotlin-artifacts.gradle' diff --git a/dbflow-rx2/build.gradle b/dbflow-rx2/build.gradle index 6d62b0a13..1fb162c01 100644 --- a/dbflow-rx2/build.gradle +++ b/dbflow-rx2/build.gradle @@ -18,8 +18,8 @@ android { } dependencies { - compile project("${dbflow_project_prefix}dbflow") - compile 'io.reactivex.rxjava2:rxjava:2.0.7' + api project("${dbflow_project_prefix}dbflow") + api 'io.reactivex.rxjava2:rxjava:2.1.3' } apply from: '../android-artifacts.gradle' diff --git a/dbflow-rx2/src/main/java/com/raizlabs/android/dbflow/rx2/language/RXQueriable.java b/dbflow-rx2/src/main/java/com/raizlabs/android/dbflow/rx2/language/RXQueriable.java index 6557d3739..e2c121101 100644 --- a/dbflow-rx2/src/main/java/com/raizlabs/android/dbflow/rx2/language/RXQueriable.java +++ b/dbflow-rx2/src/main/java/com/raizlabs/android/dbflow/rx2/language/RXQueriable.java @@ -51,6 +51,7 @@ public interface RXQueriable { /** * @return the count of the results of the query. + * @deprecated use {@link #longValue()} */ @NonNull Single count(); @@ -59,10 +60,23 @@ public interface RXQueriable { * Allows you to pass in a {@link DatabaseWrapper} manually. * * @return the count of the results of the query. + * @deprecated use {@link #longValue(DatabaseWrapper)} */ @NonNull Single count(DatabaseWrapper databaseWrapper); + /** + * @return the long value of this query. + **/ + @NonNull + Single longValue(); + + /** + * @return the long value of this query. + **/ + @NonNull + Single longValue(DatabaseWrapper databaseWrapper); + /** * @return This may return the number of rows affected from a {@link Insert} statement. * If not, returns {@link Model#INVALID_ROW_ID} diff --git a/dbflow-rx2/src/main/java/com/raizlabs/android/dbflow/rx2/language/RXQueriableImpl.java b/dbflow-rx2/src/main/java/com/raizlabs/android/dbflow/rx2/language/RXQueriableImpl.java index ca517012a..a33c8acf9 100644 --- a/dbflow-rx2/src/main/java/com/raizlabs/android/dbflow/rx2/language/RXQueriableImpl.java +++ b/dbflow-rx2/src/main/java/com/raizlabs/android/dbflow/rx2/language/RXQueriableImpl.java @@ -101,6 +101,28 @@ public Long call() throws Exception { }); } + @NonNull + @Override + public Single longValue() { + return fromCallable(new Callable() { + @Override + public Long call() throws Exception { + return getInnerQueriable().longValue(); + } + }); + } + + @NonNull + @Override + public Single longValue(final DatabaseWrapper databaseWrapper) { + return fromCallable(new Callable() { + @Override + public Long call() throws Exception { + return getInnerQueriable().longValue(databaseWrapper); + } + }); + } + @NonNull @Override public Single executeInsert() { diff --git a/dbflow-sqlcipher/build.gradle b/dbflow-sqlcipher/build.gradle index f89b43544..74428766d 100644 --- a/dbflow-sqlcipher/build.gradle +++ b/dbflow-sqlcipher/build.gradle @@ -3,12 +3,12 @@ apply plugin: 'com.android.library' project.ext.artifactId = bt_name android { - compileSdkVersion 25 + compileSdkVersion 26 buildToolsVersion dbflow_build_tools_version defaultConfig { minSdkVersion 7 - targetSdkVersion 25 + targetSdkVersion 26 versionCode = version_code } @@ -23,8 +23,8 @@ android { } dependencies { - compile "net.zetetic:android-database-sqlcipher:3.5.7@aar" - compile project("${dbflow_project_prefix}dbflow") + api "net.zetetic:android-database-sqlcipher:3.5.7@aar" + api project("${dbflow_project_prefix}dbflow") } apply from: '../android-artifacts.gradle' diff --git a/dbflow-tests/build.gradle b/dbflow-tests/build.gradle index 9b17a7161..d1ec2f4d7 100644 --- a/dbflow-tests/build.gradle +++ b/dbflow-tests/build.gradle @@ -7,7 +7,7 @@ android { useLibrary 'org.apache.http.legacy' - compileSdkVersion 25 + compileSdkVersion 26 buildToolsVersion dbflow_build_tools_version compileOptions { @@ -17,7 +17,7 @@ android { defaultConfig { minSdkVersion 15 - targetSdkVersion 25 + targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" @@ -35,39 +35,47 @@ android { sourceSets { main.java.srcDirs += 'src/main/kotlin' } + testOptions { + unitTests { + includeAndroidResources true + } + } } dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" kapt project("${dbflow_project_prefix}dbflow-processor") - compile project(':dbflow') - compile 'com.android.support:appcompat-v7:25.3.1' - compile project("${dbflow_project_prefix}dbflow") - compile project("${dbflow_project_prefix}dbflow-sqlcipher") - compile project("${dbflow_project_prefix}dbflow-kotlinextensions") - compile project("${dbflow_project_prefix}dbflow-rx") - compile project("${dbflow_project_prefix}dbflow-rx-kotlinextensions") - compile project("${dbflow_project_prefix}dbflow-rx2") - compile project("${dbflow_project_prefix}dbflow-rx2-kotlinextensions") + implementation project(':dbflow') + implementation 'com.android.support:appcompat-v7:26.0.1' + implementation project("${dbflow_project_prefix}dbflow") + implementation project("${dbflow_project_prefix}dbflow-sqlcipher") + implementation project("${dbflow_project_prefix}dbflow-kotlinextensions") + implementation project("${dbflow_project_prefix}dbflow-rx") + implementation project("${dbflow_project_prefix}dbflow-rx-kotlinextensions") + implementation project("${dbflow_project_prefix}dbflow-rx2") + implementation project("${dbflow_project_prefix}dbflow-rx2-kotlinextensions") kaptTest project("${dbflow_project_prefix}dbflow-processor") + kaptAndroidTest project("${dbflow_project_prefix}dbflow-processor") + + testImplementation 'org.glassfish:javax.annotation:10.0-b28' - testCompile 'junit:junit:4.12' - testCompile "org.robolectric:robolectric:3.3.2" - testCompile("com.nhaarman:mockito-kotlin:1.5.0") { + testImplementation 'junit:junit:4.12' + testImplementation "org.robolectric:robolectric:3.4.2" + testImplementation("com.nhaarman:mockito-kotlin:1.5.0") { exclude group: "org.jetbrains.kotlin" } - testCompile 'org.mockito:mockito-core:2.8.9' + testImplementation 'org.mockito:mockito-core:2.8.9' - androidTestCompile 'junit:junit:4.12' - androidTestCompile('com.android.support.test:runner:0.5') { + androidTestImplementation 'junit:junit:4.12' + androidTestImplementation('com.android.support.test:runner:0.5') { exclude group: 'com.android.support', module: 'support-annotations' } - androidTestCompile('com.android.support.test:rules:0.5') { + androidTestImplementation('com.android.support.test:rules:0.5') { exclude group: 'com.android.support', module: 'support-annotations' } - androidTestCompile 'org.awaitility:awaitility:3.0.0-rc1' + androidTestImplementation 'org.awaitility:awaitility:3.0.0-rc1' } @@ -83,10 +91,6 @@ android.applicationVariants.all { variant -> project.getTasksByName("generate${variant.name.capitalize()}Resources", false)[0].dependsOn(taskName) } -kapt { - generateStubs = true -} - dexcount { includeClasses = true orderByMethodCount = true diff --git a/dbflow-tests/src/androidTest/java/com/raizlabs/android/dbflow/DBFlowInstrumentedTestRule.kt b/dbflow-tests/src/androidTest/java/com/raizlabs/android/dbflow/DBFlowInstrumentedTestRule.kt index 48c08e0bc..3ddedd217 100644 --- a/dbflow-tests/src/androidTest/java/com/raizlabs/android/dbflow/DBFlowInstrumentedTestRule.kt +++ b/dbflow-tests/src/androidTest/java/com/raizlabs/android/dbflow/DBFlowInstrumentedTestRule.kt @@ -3,6 +3,7 @@ package com.raizlabs.android.dbflow import com.raizlabs.android.dbflow.config.DatabaseConfig import com.raizlabs.android.dbflow.config.FlowConfig import com.raizlabs.android.dbflow.config.FlowManager +import com.raizlabs.android.dbflow.prepackaged.PrepackagedDB import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement @@ -15,9 +16,13 @@ class DBFlowInstrumentedTestRule : TestRule { @Throws(Throwable::class) override fun evaluate() { FlowManager.init(FlowConfig.Builder(DemoApp.context) - .addDatabaseConfig(DatabaseConfig.Builder(AppDatabase::class.java) - .transactionManagerCreator(::ImmediateTransactionManager) - .build()).build()) + .addDatabaseConfig(DatabaseConfig.Builder(AppDatabase::class.java) + .transactionManagerCreator(::ImmediateTransactionManager) + .build()) + .addDatabaseConfig(DatabaseConfig.builder(PrepackagedDB::class.java) + .databaseName("prepackaged") + .build()) + .build()) try { base.evaluate() } finally { diff --git a/dbflow-tests/src/main/java/com/raizlabs/android/dbflow/User.java b/dbflow-tests/src/main/java/com/raizlabs/android/dbflow/User.java deleted file mode 100644 index 60ca0376b..000000000 --- a/dbflow-tests/src/main/java/com/raizlabs/android/dbflow/User.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.raizlabs.android.dbflow; - -import com.raizlabs.android.dbflow.annotation.Column; -import com.raizlabs.android.dbflow.annotation.PrimaryKey; -import com.raizlabs.android.dbflow.annotation.Table; - -@Table(database = AppDatabase.class, name = "User2") -public class User { - - @PrimaryKey - int id; - - @Column - String firstName; - - @Column - String lastName; - - @Column - String email; -} diff --git a/dbflow-tests/src/main/java/com/raizlabs/android/dbflow/User.kt b/dbflow-tests/src/main/java/com/raizlabs/android/dbflow/User.kt new file mode 100644 index 000000000..583d61896 --- /dev/null +++ b/dbflow-tests/src/main/java/com/raizlabs/android/dbflow/User.kt @@ -0,0 +1,21 @@ +package com.raizlabs.android.dbflow + +import com.raizlabs.android.dbflow.annotation.Column +import com.raizlabs.android.dbflow.annotation.PrimaryKey +import com.raizlabs.android.dbflow.annotation.Table + +@Table(database = AppDatabase::class, name = "User2") +class User { + + @PrimaryKey + var id: Int = 0 + + @Column + var firstName: String? = null + + @Column + var lastName: String? = null + + @Column + var email: String? = null +} diff --git a/dbflow-tests/src/main/java/com/raizlabs/android/dbflow/prepackaged/PrepackagedDB.kt b/dbflow-tests/src/main/java/com/raizlabs/android/dbflow/prepackaged/PrepackagedDB.kt index 20f848212..464fd34c4 100644 --- a/dbflow-tests/src/main/java/com/raizlabs/android/dbflow/prepackaged/PrepackagedDB.kt +++ b/dbflow-tests/src/main/java/com/raizlabs/android/dbflow/prepackaged/PrepackagedDB.kt @@ -6,11 +6,8 @@ import com.raizlabs.android.dbflow.annotation.PrimaryKey import com.raizlabs.android.dbflow.annotation.Table import com.raizlabs.android.dbflow.structure.BaseModel -@Database(name = PrepackagedDB.NAME, version = PrepackagedDB.VERSION) +@Database(version = PrepackagedDB.VERSION) object PrepackagedDB { - - const val NAME = "prepackaged" - const val VERSION = 1 } diff --git a/dbflow-tests/src/main/java/com/raizlabs/android/dbflow/sqlcipher/CipherDatabase.kt b/dbflow-tests/src/main/java/com/raizlabs/android/dbflow/sqlcipher/CipherDatabase.kt index 1b9f3c0fc..5c4911f7f 100644 --- a/dbflow-tests/src/main/java/com/raizlabs/android/dbflow/sqlcipher/CipherDatabase.kt +++ b/dbflow-tests/src/main/java/com/raizlabs/android/dbflow/sqlcipher/CipherDatabase.kt @@ -2,9 +2,8 @@ package com.raizlabs.android.dbflow.sqlcipher import com.raizlabs.android.dbflow.annotation.Database -@Database(name = CipherDatabase.NAME, version = CipherDatabase.VERSION) +@Database(version = CipherDatabase.VERSION) object CipherDatabase { - const val NAME = "CipherDatabase" const val VERSION = 1 } \ No newline at end of file diff --git a/dbflow-tests/src/main/java/com/raizlabs/android/dbflow/test/DemoActivity.java b/dbflow-tests/src/main/java/com/raizlabs/android/dbflow/test/DemoActivity.java index 02545a2a3..943d49d1d 100644 --- a/dbflow-tests/src/main/java/com/raizlabs/android/dbflow/test/DemoActivity.java +++ b/dbflow-tests/src/main/java/com/raizlabs/android/dbflow/test/DemoActivity.java @@ -5,8 +5,10 @@ import android.view.Menu; import android.view.MenuItem; +import com.raizlabs.android.dbflow.config.DatabaseConfig; import com.raizlabs.android.dbflow.config.FlowConfig; import com.raizlabs.android.dbflow.config.FlowManager; +import com.raizlabs.android.dbflow.prepackaged.PrepackagedDB; public class DemoActivity extends Activity { @@ -16,7 +18,12 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_demo); - FlowManager.init(new FlowConfig.Builder(getApplicationContext()).build()); + FlowManager.init(new FlowConfig.Builder(getApplicationContext()) + .addDatabaseConfig( + DatabaseConfig.builder(PrepackagedDB.class) + .databaseName("prepackaged") + .build()) + .build()); } diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/BaseUnitTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/BaseUnitTest.kt index 17edc283f..7dad0f0aa 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/BaseUnitTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/BaseUnitTest.kt @@ -1,7 +1,6 @@ package com.raizlabs.android.dbflow import android.content.Context -import android.os.Build import org.junit.Rule import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner @@ -9,8 +8,7 @@ import org.robolectric.RuntimeEnvironment import org.robolectric.annotation.Config @RunWith(RobolectricTestRunner::class) -@Config(constants = BuildConfig::class, sdk = intArrayOf(Build.VERSION_CODES.LOLLIPOP), - assetDir = "build/intermediates/classes/test/") +@Config(manifest = Config.NONE) abstract class BaseUnitTest { @JvmField diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/DBFlowTestRule.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/DBFlowTestRule.kt index f2473c4f5..261fb65c3 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/DBFlowTestRule.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/DBFlowTestRule.kt @@ -3,6 +3,7 @@ package com.raizlabs.android.dbflow import com.raizlabs.android.dbflow.config.DatabaseConfig import com.raizlabs.android.dbflow.config.FlowConfig import com.raizlabs.android.dbflow.config.FlowManager +import com.raizlabs.android.dbflow.contentprovider.ContentDatabase import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement @@ -16,9 +17,13 @@ class DBFlowTestRule : TestRule { @Throws(Throwable::class) override fun evaluate() { FlowManager.init(FlowConfig.Builder(RuntimeEnvironment.application) - .addDatabaseConfig(DatabaseConfig.Builder(TestDatabase::class.java) - .transactionManagerCreator(::ImmediateTransactionManager2) - .build()).build()) + .addDatabaseConfig(DatabaseConfig.Builder(TestDatabase::class.java) + .transactionManagerCreator(::ImmediateTransactionManager2) + .build()) + .addDatabaseConfig(DatabaseConfig.builder(ContentDatabase::class.java) + .databaseName("content") + .build()) + .build()) try { base.evaluate() } finally { diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/ImmediateTransactionManager.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/ImmediateTransactionManager.kt index 5d815a65f..ed8245ef7 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/ImmediateTransactionManager.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/ImmediateTransactionManager.kt @@ -16,9 +16,9 @@ class ImmediateTransactionQueue2 : ITransactionQueue { override fun add(transaction: Transaction) { transaction.newBuilder() - .runCallbacksOnSameThread(true) - .build() - .executeSync() + .runCallbacksOnSameThread(true) + .build() + .executeSync() } override fun cancel(transaction: Transaction) { diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/TestDatabase.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/TestDatabase.kt index 78fe6a715..44f4860da 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/TestDatabase.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/TestDatabase.kt @@ -8,13 +8,11 @@ import com.raizlabs.android.dbflow.sql.migration.UpdateTableMigration /** * Description: */ -@Database(version = TestDatabase.VERSION, name = TestDatabase.NAME) +@Database(version = TestDatabase.VERSION) object TestDatabase { const val VERSION = 1 - const val NAME = "TestDatabase" - @Migration(version = 1, database = TestDatabase::class) class TestMigration : UpdateTableMigration(SimpleModel::class.java) { override fun onPostMigrate() { diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/TestExtensions.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/TestExtensions.kt index 36a2b32af..d33cc7cc5 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/TestExtensions.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/TestExtensions.kt @@ -1,7 +1,20 @@ package com.raizlabs.android.dbflow import com.raizlabs.android.dbflow.sql.Query -import junit.framework.Assert.assertEquals +import org.junit.Assert.assertEquals +import org.junit.Assert.fail +import kotlin.reflect.KClass -fun assertEquals(string: String, query: Query) = assertEquals(string, query.query.trim()) \ No newline at end of file +fun assertEquals(string: String, query: Query) = assertEquals(string, query.query.trim()) + +fun assertThrowsException(expectedException: KClass, function: () -> Unit) { + try { + function() + fail("Expected call to fail. Unexpectedly passed") + } catch (e: Exception) { + if (e.javaClass != expectedException.java) { + fail("Expected $expectedException but got ${e.javaClass}") + } + } +} \ No newline at end of file diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/config/ConfigIntegrationTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/config/ConfigIntegrationTest.kt index 97d85e532..e475503cb 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/config/ConfigIntegrationTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/config/ConfigIntegrationTest.kt @@ -2,8 +2,8 @@ package com.raizlabs.android.dbflow.config import com.nhaarman.mockito_kotlin.mock import com.raizlabs.android.dbflow.BaseUnitTest -import com.raizlabs.android.dbflow.models.SimpleModel import com.raizlabs.android.dbflow.TestDatabase +import com.raizlabs.android.dbflow.models.SimpleModel import com.raizlabs.android.dbflow.runtime.BaseTransactionManager import com.raizlabs.android.dbflow.sql.queriable.ListModelLoader import com.raizlabs.android.dbflow.sql.queriable.SingleModelLoader @@ -11,7 +11,9 @@ import com.raizlabs.android.dbflow.sql.saveable.ModelSaver import com.raizlabs.android.dbflow.structure.database.DatabaseHelperListener import com.raizlabs.android.dbflow.structure.database.OpenHelper import com.raizlabs.android.dbflow.structure.database.transaction.ITransactionQueue -import junit.framework.Assert.* +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test @@ -43,41 +45,6 @@ class ConfigIntegrationTest : BaseUnitTest() { assertTrue(config.databaseHolders().isEmpty()) } - @Test - fun test_databaseConfig() { - - val helperListener = mock() - - val openHelperCreator = CustomOpenHelperCreator() - val managerCreator = CustomTransactionManagerCreator() - - FlowManager.init(builder - .addDatabaseConfig(DatabaseConfig.Builder(TestDatabase::class.java) - .helperListener(helperListener) - .openHelper(openHelperCreator) - .transactionManagerCreator(managerCreator) - .build()) - .build()) - - val flowConfig = FlowManager.getConfig() - assertNotNull(flowConfig) - - val databaseConfig = flowConfig.databaseConfigMap()[TestDatabase::class.java] as DatabaseConfig - assertNotNull(databaseConfig) - - assertEquals(databaseConfig.transactionManagerCreator(), managerCreator) - assertEquals(databaseConfig.databaseClass(), TestDatabase::class.java) - assertEquals(databaseConfig.helperCreator(), openHelperCreator) - assertEquals(databaseConfig.helperListener(), helperListener) - assertTrue(databaseConfig.tableConfigMap().isEmpty()) - - - val databaseDefinition = FlowManager.getDatabase(TestDatabase::class.java) - assertEquals(databaseDefinition.transactionManager, - managerCreator.testTransactionManager) - assertEquals(databaseDefinition.helper, openHelperCreator.customOpenHelper) - } - @Test fun test_tableConfig() { @@ -114,26 +81,6 @@ class ConfigIntegrationTest : BaseUnitTest() { assertEquals(modelAdapter.modelSaver, modelSaver) } - private class CustomTransactionManagerCreator : DatabaseConfig.TransactionManagerCreator { - - lateinit var testTransactionManager: TestTransactionManager - - override fun createManager(databaseDefinition: DatabaseDefinition): BaseTransactionManager { - testTransactionManager = TestTransactionManager(databaseDefinition) - return testTransactionManager - } - } - - private class CustomOpenHelperCreator : DatabaseConfig.OpenHelperCreator { - - val customOpenHelper = mock() - - override fun createHelper(databaseDefinition: DatabaseDefinition, helperListener: DatabaseHelperListener): OpenHelper { - return customOpenHelper - } - } } -class TestTransactionManager(databaseDefinition: DatabaseDefinition) - : BaseTransactionManager(mock(), databaseDefinition) diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/config/DatabaseConfigTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/config/DatabaseConfigTest.kt new file mode 100644 index 000000000..4ac3564ad --- /dev/null +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/config/DatabaseConfigTest.kt @@ -0,0 +1,101 @@ +package com.raizlabs.android.dbflow.config + +import com.nhaarman.mockito_kotlin.mock +import com.raizlabs.android.dbflow.BaseUnitTest +import com.raizlabs.android.dbflow.TestDatabase +import com.raizlabs.android.dbflow.runtime.BaseTransactionManager +import com.raizlabs.android.dbflow.structure.database.DatabaseHelperListener +import com.raizlabs.android.dbflow.structure.database.OpenHelper +import com.raizlabs.android.dbflow.structure.database.transaction.ITransactionQueue +import org.junit.Assert +import org.junit.Before +import org.junit.Test + + +/** + * Description: + */ +class DatabaseConfigTest : BaseUnitTest() { + + private lateinit var builder: FlowConfig.Builder + + @Before + fun setup() { + FlowManager.reset() + FlowLog.setMinimumLoggingLevel(FlowLog.Level.V) + builder = FlowConfig.Builder(context) + } + + @Test + fun test_databaseConfig() { + + val helperListener = mock() + + val openHelperCreator = CustomOpenHelperCreator() + val managerCreator = CustomTransactionManagerCreator() + + FlowManager.init(builder + .addDatabaseConfig(DatabaseConfig.Builder(TestDatabase::class.java) + .databaseName("Test") + .helperListener(helperListener) + .openHelper(openHelperCreator) + .transactionManagerCreator(managerCreator) + .build()) + .build()) + + val flowConfig = FlowManager.getConfig() + Assert.assertNotNull(flowConfig) + + val databaseConfig = flowConfig.databaseConfigMap()[TestDatabase::class.java]!! + Assert.assertEquals("Test", databaseConfig.databaseName) + Assert.assertEquals(".db", databaseConfig.databaseExtensionName) + Assert.assertEquals(databaseConfig.transactionManagerCreator(), managerCreator) + Assert.assertEquals(databaseConfig.databaseClass(), TestDatabase::class.java) + Assert.assertEquals(databaseConfig.helperCreator(), openHelperCreator) + Assert.assertEquals(databaseConfig.helperListener(), helperListener) + Assert.assertTrue(databaseConfig.tableConfigMap().isEmpty()) + + + val databaseDefinition = FlowManager.getDatabase(TestDatabase::class.java) + Assert.assertEquals(databaseDefinition.transactionManager, + managerCreator.testTransactionManager) + Assert.assertEquals(databaseDefinition.helper, openHelperCreator.customOpenHelper) + } + + @Test + fun test_EmptyName() { + FlowManager.init(builder + .addDatabaseConfig(DatabaseConfig.Builder(TestDatabase::class.java) + .databaseName("Test") + .extensionName("") + .build()) + .build()) + + val databaseConfig = FlowManager.getConfig().databaseConfigMap()[TestDatabase::class.java]!! + Assert.assertEquals("Test", databaseConfig.databaseName) + Assert.assertEquals("", databaseConfig.databaseExtensionName) + } + + class CustomTransactionManagerCreator : DatabaseConfig.TransactionManagerCreator { + + lateinit var testTransactionManager: TestTransactionManager + + override fun createManager(databaseDefinition: DatabaseDefinition): BaseTransactionManager { + testTransactionManager = TestTransactionManager(databaseDefinition) + return testTransactionManager + } + } + + class CustomOpenHelperCreator : DatabaseConfig.OpenHelperCreator { + + val customOpenHelper = mock() + + override fun createHelper(databaseDefinition: DatabaseDefinition, helperListener: DatabaseHelperListener): OpenHelper { + return customOpenHelper + } + } + +} + +class TestTransactionManager(databaseDefinition: DatabaseDefinition) + : BaseTransactionManager(mock(), databaseDefinition) \ No newline at end of file diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/contentprovider/ContentProviderObjects.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/contentprovider/ContentProviderObjects.kt index 1d49f2cf1..ccdedc49b 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/contentprovider/ContentProviderObjects.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/contentprovider/ContentProviderObjects.kt @@ -1,6 +1,11 @@ package com.raizlabs.android.dbflow.contentprovider -import com.raizlabs.android.dbflow.annotation.* +import com.raizlabs.android.dbflow.annotation.Column +import com.raizlabs.android.dbflow.annotation.Database +import com.raizlabs.android.dbflow.annotation.ForeignKey +import com.raizlabs.android.dbflow.annotation.ForeignKeyReference +import com.raizlabs.android.dbflow.annotation.PrimaryKey +import com.raizlabs.android.dbflow.annotation.Table import com.raizlabs.android.dbflow.annotation.provider.ContentProvider import com.raizlabs.android.dbflow.annotation.provider.ContentUri import com.raizlabs.android.dbflow.annotation.provider.TableEndpoint @@ -14,15 +19,13 @@ import com.raizlabs.android.dbflow.structure.provider.ContentUtils */ @ContentProvider(authority = ContentDatabase.AUTHORITY, database = ContentDatabase::class, baseContentUri = ContentDatabase.BASE_CONTENT_URI) -@Database(version = ContentDatabase.VERSION, name = ContentDatabase.NAME) +@Database(version = ContentDatabase.VERSION) object ContentDatabase { const val BASE_CONTENT_URI = "content://" const val AUTHORITY = "com.raizlabs.android.content.test.ContentDatabase" - const val NAME = "content" - const val VERSION = 1 } diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/contentprovider/RealContentProvider.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/contentprovider/RealContentProvider.kt index b15df770c..ad4ae5a3d 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/contentprovider/RealContentProvider.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/contentprovider/RealContentProvider.kt @@ -11,13 +11,11 @@ import com.raizlabs.android.dbflow.structure.database.DatabaseWrapper class RealContentProvider : ContentProvider() { - var databaseName = TestDatabase.NAME - lateinit var database: DatabaseWrapper override fun onCreate(): Boolean { FlowManager.init(FlowConfig.Builder(context).build()) - database = FlowManager.getDatabase(databaseName).writableDatabase + database = FlowManager.getDatabase(TestDatabase::class.java).writableDatabase return true } diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/database/transaction/FastStoreModelTransactionTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/database/transaction/FastStoreModelTransactionTest.kt index 5f19882a5..ec50b25b7 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/database/transaction/FastStoreModelTransactionTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/database/transaction/FastStoreModelTransactionTest.kt @@ -2,7 +2,13 @@ package com.raizlabs.android.dbflow.database.transaction import com.raizlabs.android.dbflow.BaseUnitTest import com.raizlabs.android.dbflow.TestDatabase -import com.raizlabs.android.dbflow.kotlinextensions.* +import com.raizlabs.android.dbflow.kotlinextensions.database +import com.raizlabs.android.dbflow.kotlinextensions.fastInsert +import com.raizlabs.android.dbflow.kotlinextensions.fastSave +import com.raizlabs.android.dbflow.kotlinextensions.fastUpdate +import com.raizlabs.android.dbflow.kotlinextensions.from +import com.raizlabs.android.dbflow.kotlinextensions.list +import com.raizlabs.android.dbflow.kotlinextensions.select import com.raizlabs.android.dbflow.models.SimpleModel import com.raizlabs.android.dbflow.models.TwoColumnModel import org.junit.Assert.assertEquals @@ -16,10 +22,10 @@ class FastStoreModelTransactionTest : BaseUnitTest() { fun testSaveBuilder() { database() - .beginTransactionAsync((0..9) - .map { SimpleModel("$it") } - .fastSave().build()) - .execute() + .beginTransactionAsync((0..9) + .map { SimpleModel("$it") } + .fastSave().build()) + .execute() val list = (select from SimpleModel::class).list assertEquals(10, list.size) @@ -29,10 +35,10 @@ class FastStoreModelTransactionTest : BaseUnitTest() { fun testInsertBuilder() { database() - .beginTransactionAsync((0..9) - .map { SimpleModel("$it") } - .fastInsert().build()) - .execute() + .beginTransactionAsync((0..9) + .map { SimpleModel("$it") } + .fastInsert().build()) + .execute() val list = (select from SimpleModel::class).list assertEquals(10, list.size) @@ -43,13 +49,13 @@ class FastStoreModelTransactionTest : BaseUnitTest() { val oldList = (0..9).map { TwoColumnModel("$it", Random().nextInt()) } database() - .beginTransactionAsync(oldList.fastInsert().build()) - .execute() + .beginTransactionAsync(oldList.fastInsert().build()) + .execute() database() - .beginTransactionAsync((0..9).map { TwoColumnModel("$it", Random().nextInt()) } - .fastUpdate().build()) - .execute() + .beginTransactionAsync((0..9).map { TwoColumnModel("$it", Random().nextInt()) } + .fastUpdate().build()) + .execute() val list = (select from TwoColumnModel::class).list assertEquals(10, list.size) diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/list/FlowCursorIteratorTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/list/FlowCursorIteratorTest.kt index 34696f4bc..db50dcab2 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/list/FlowCursorIteratorTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/list/FlowCursorIteratorTest.kt @@ -1,10 +1,10 @@ package com.raizlabs.android.dbflow.list import com.raizlabs.android.dbflow.BaseUnitTest -import com.raizlabs.android.dbflow.models.SimpleModel import com.raizlabs.android.dbflow.kotlinextensions.from import com.raizlabs.android.dbflow.kotlinextensions.save import com.raizlabs.android.dbflow.kotlinextensions.select +import com.raizlabs.android.dbflow.models.SimpleModel import org.junit.Assert.assertEquals import org.junit.Test diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/list/FlowCursorListTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/list/FlowCursorListTest.kt index ab78e713c..301fcec18 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/list/FlowCursorListTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/list/FlowCursorListTest.kt @@ -4,10 +4,17 @@ import com.nhaarman.mockito_kotlin.mock import com.nhaarman.mockito_kotlin.times import com.nhaarman.mockito_kotlin.verify import com.raizlabs.android.dbflow.BaseUnitTest +import com.raizlabs.android.dbflow.kotlinextensions.cursor +import com.raizlabs.android.dbflow.kotlinextensions.from +import com.raizlabs.android.dbflow.kotlinextensions.get +import com.raizlabs.android.dbflow.kotlinextensions.save +import com.raizlabs.android.dbflow.kotlinextensions.select import com.raizlabs.android.dbflow.models.SimpleModel -import com.raizlabs.android.dbflow.kotlinextensions.* import com.raizlabs.android.dbflow.structure.cache.SimpleMapCache -import org.junit.Assert.* +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNotEquals +import org.junit.Assert.assertTrue import org.junit.Test /** diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/list/FlowQueryListTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/list/FlowQueryListTest.kt index a406b2fce..49680b476 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/list/FlowQueryListTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/list/FlowQueryListTest.kt @@ -4,12 +4,14 @@ import com.nhaarman.mockito_kotlin.argumentCaptor import com.nhaarman.mockito_kotlin.mock import com.nhaarman.mockito_kotlin.verify import com.raizlabs.android.dbflow.BaseUnitTest -import com.raizlabs.android.dbflow.models.SimpleModel import com.raizlabs.android.dbflow.kotlinextensions.from import com.raizlabs.android.dbflow.kotlinextensions.select +import com.raizlabs.android.dbflow.models.SimpleModel import com.raizlabs.android.dbflow.structure.cache.SimpleMapCache import com.raizlabs.android.dbflow.structure.database.transaction.Transaction -import org.junit.Assert.* +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue import org.junit.Test class FlowQueryListTest : BaseUnitTest() { diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/AutoIncrementTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/AutoIncrementTest.kt new file mode 100644 index 000000000..5e1e18ece --- /dev/null +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/AutoIncrementTest.kt @@ -0,0 +1,33 @@ +package com.raizlabs.android.dbflow.models + +import com.raizlabs.android.dbflow.BaseUnitTest +import com.raizlabs.android.dbflow.TestDatabase +import com.raizlabs.android.dbflow.annotation.PrimaryKey +import com.raizlabs.android.dbflow.annotation.Table +import com.raizlabs.android.dbflow.kotlinextensions.insert +import org.junit.Assert.assertEquals +import org.junit.Test + +/** + * Description: + */ +class AutoIncrementTest : BaseUnitTest() { + + @Test + fun testCanInsertAutoIncrement() { + val model = AutoIncrementingModel() + model.insert() + assertEquals(1L, model.id) + } + + @Test + fun testCanInsertExistingIdAutoIncrement() { + val model = AutoIncrementingModel(3) + model.insert() + assertEquals(3L, model.id) + } +} + + +@Table(database = TestDatabase::class) +class AutoIncrementingModel(@PrimaryKey(autoincrement = true) var id: Long = 0) \ No newline at end of file diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/CachingModels.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/CachingModels.kt index 892816b9e..3bf98526f 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/CachingModels.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/CachingModels.kt @@ -1,7 +1,11 @@ package com.raizlabs.android.dbflow.models import com.raizlabs.android.dbflow.TestDatabase -import com.raizlabs.android.dbflow.annotation.* +import com.raizlabs.android.dbflow.annotation.Column +import com.raizlabs.android.dbflow.annotation.ForeignKey +import com.raizlabs.android.dbflow.annotation.MultiCacheField +import com.raizlabs.android.dbflow.annotation.PrimaryKey +import com.raizlabs.android.dbflow.annotation.Table import com.raizlabs.android.dbflow.structure.cache.IMultiKeyCacheConverter @Table(database = TestDatabase::class, cachingEnabled = true) diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/CachingModelsTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/CachingModelsTest.kt index 9001b31f5..a8a4484d5 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/CachingModelsTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/CachingModelsTest.kt @@ -1,7 +1,11 @@ package com.raizlabs.android.dbflow.models import com.raizlabs.android.dbflow.BaseUnitTest -import com.raizlabs.android.dbflow.kotlinextensions.* +import com.raizlabs.android.dbflow.kotlinextensions.from +import com.raizlabs.android.dbflow.kotlinextensions.list +import com.raizlabs.android.dbflow.kotlinextensions.result +import com.raizlabs.android.dbflow.kotlinextensions.save +import com.raizlabs.android.dbflow.kotlinextensions.select import org.junit.Assert.assertEquals import org.junit.Assert.assertNotEquals import org.junit.Test diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/DontCreateModelTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/DontCreateModelTest.kt new file mode 100644 index 000000000..22edf3655 --- /dev/null +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/DontCreateModelTest.kt @@ -0,0 +1,22 @@ +package com.raizlabs.android.dbflow.models + +import android.database.sqlite.SQLiteException +import com.raizlabs.android.dbflow.BaseUnitTest +import com.raizlabs.android.dbflow.assertThrowsException +import com.raizlabs.android.dbflow.kotlinextensions.from +import com.raizlabs.android.dbflow.kotlinextensions.list +import com.raizlabs.android.dbflow.kotlinextensions.select +import org.junit.Test + +/** + * Description: + */ +class DontCreateModelTest : BaseUnitTest() { + + @Test + fun testModelNotCreated() { + assertThrowsException(SQLiteException::class) { + (select from DontCreateModel::class).list + } + } +} diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/ForeignKeyModels.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/ForeignKeyModels.kt index 15b30c1fb..781a98df7 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/ForeignKeyModels.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/ForeignKeyModels.kt @@ -2,7 +2,16 @@ package com.raizlabs.android.dbflow.models import android.database.Cursor import com.raizlabs.android.dbflow.TestDatabase -import com.raizlabs.android.dbflow.annotation.* +import com.raizlabs.android.dbflow.annotation.Column +import com.raizlabs.android.dbflow.annotation.ColumnMap +import com.raizlabs.android.dbflow.annotation.ColumnMapReference +import com.raizlabs.android.dbflow.annotation.ConflictAction +import com.raizlabs.android.dbflow.annotation.ForeignKey +import com.raizlabs.android.dbflow.annotation.ForeignKeyAction +import com.raizlabs.android.dbflow.annotation.ForeignKeyReference +import com.raizlabs.android.dbflow.annotation.NotNull +import com.raizlabs.android.dbflow.annotation.PrimaryKey +import com.raizlabs.android.dbflow.annotation.Table import com.raizlabs.android.dbflow.structure.listener.LoadFromCursorListener /** @@ -40,8 +49,8 @@ class BlogRef(@PrimaryKey(autoincrement = true) var id: Int = 0, @Column var nam */ @Table(database = TestDatabase::class) class BlogRefNoModel(@PrimaryKey(autoincrement = true) var id: Int = 0, @Column var name: String = "", - @ForeignKey(references = arrayOf(ForeignKeyReference(columnName = "authorId", foreignKeyColumnName = "id")), - tableClass = Author::class) + @ForeignKey(references = arrayOf(ForeignKeyReference(columnName = "authorId", foreignKeyColumnName = "id", notNull = NotNull(onNullConflict = ConflictAction.FAIL))), + tableClass = Author::class) var authorId: String? = null) @@ -58,9 +67,21 @@ class BlogPrimary(@PrimaryKey @ForeignKey var author: Author? = null, @Column va @Table(database = TestDatabase::class) class BlogStubbed(@PrimaryKey(autoincrement = true) var id: Int = 0, @Column var name: String = "", @ForeignKey(stubbedRelationship = true, deleteForeignKeyModel = true, saveForeignKeyModel = true, - onDelete = ForeignKeyAction.CASCADE, onUpdate = ForeignKeyAction.RESTRICT) + onDelete = ForeignKeyAction.CASCADE, onUpdate = ForeignKeyAction.RESTRICT) var author: Author? = null) : LoadFromCursorListener { override fun onLoadFromCursor(cursor: Cursor) { } -} \ No newline at end of file +} + +class Location(var latitude: Double = 0.0, var longitude: Double = 0.0) + +@Table(database = TestDatabase::class) +class Position(@PrimaryKey var id: Int = 0, @ColumnMap var location: Location? = null) + +@Table(database = TestDatabase::class) +class Position2(@PrimaryKey var id: Int = 0, + @ColumnMap(references = arrayOf( + ColumnMapReference(columnName = "latitude", columnMapFieldName = "latitude"), + ColumnMapReference(columnName = "longitude", columnMapFieldName = "longitude"))) + var location: Location? = null) diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/IndexModels.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/IndexModels.kt index a0be122fe..ca6206d24 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/IndexModels.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/IndexModels.kt @@ -1,7 +1,11 @@ package com.raizlabs.android.dbflow.models import com.raizlabs.android.dbflow.TestDatabase -import com.raizlabs.android.dbflow.annotation.* +import com.raizlabs.android.dbflow.annotation.Column +import com.raizlabs.android.dbflow.annotation.Index +import com.raizlabs.android.dbflow.annotation.IndexGroup +import com.raizlabs.android.dbflow.annotation.PrimaryKey +import com.raizlabs.android.dbflow.annotation.Table import java.util.* /** @@ -9,8 +13,8 @@ import java.util.* */ @Table(database = TestDatabase::class, indexGroups = arrayOf(IndexGroup(number = 1, name = "firstIndex"), - IndexGroup(number = 2, name = "secondIndex"), - IndexGroup(number = 3, name = "thirdIndex"))) + IndexGroup(number = 2, name = "secondIndex"), + IndexGroup(number = 3, name = "thirdIndex"))) class IndexModel { @Index(indexGroups = intArrayOf(1, 2, 3)) @PrimaryKey diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/ModelViews.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/ModelViews.kt index afd5ba286..2fa430801 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/ModelViews.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/ModelViews.kt @@ -2,22 +2,39 @@ package com.raizlabs.android.dbflow.models import com.raizlabs.android.dbflow.TestDatabase import com.raizlabs.android.dbflow.annotation.Column +import com.raizlabs.android.dbflow.annotation.ColumnMap import com.raizlabs.android.dbflow.annotation.ModelView import com.raizlabs.android.dbflow.annotation.ModelViewQuery import com.raizlabs.android.dbflow.kotlinextensions.from import com.raizlabs.android.dbflow.kotlinextensions.property -import com.raizlabs.android.dbflow.models.Author_Table.* +import com.raizlabs.android.dbflow.models.Author_Table.first_name +import com.raizlabs.android.dbflow.models.Author_Table.id +import com.raizlabs.android.dbflow.models.Author_Table.last_name import com.raizlabs.android.dbflow.sql.language.SQLite.select import com.raizlabs.android.dbflow.sql.language.property.IProperty +class AuthorName(var name: String = "", var age: Int = 0) + + @ModelView(database = TestDatabase::class) -class AuthorView(@Column var authorId: Int = 0, @Column var authorName: String = "") { +class AuthorView(@Column var authorId: Int = 0, @Column var authorName: String = "", + @ColumnMap var author: AuthorName? = null) { companion object { @JvmField @ModelViewQuery val query = select(id.`as`("authorId"), - first_name.concatenate(" ".property as IProperty>) - .concatenate(last_name as IProperty>).`as`("authorName")) from Author::class + first_name.concatenate(" ".property as IProperty>) + .concatenate(last_name as IProperty>).`as`("authorName")) from Author::class + } +} + +@ModelView(database = TestDatabase::class, priority = 2, allFields = true) +class PriorityView(var name: String = "") { + + companion object { + @JvmField + @ModelViewQuery + val query = select((first_name + last_name).`as`("name")) from Author::class } } \ No newline at end of file diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/OneToManyModelTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/OneToManyModelTest.kt index 338cf044b..188869dc6 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/OneToManyModelTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/OneToManyModelTest.kt @@ -1,8 +1,18 @@ package com.raizlabs.android.dbflow.models import com.raizlabs.android.dbflow.BaseUnitTest -import com.raizlabs.android.dbflow.kotlinextensions.* -import org.junit.Assert.* +import com.raizlabs.android.dbflow.kotlinextensions.delete +import com.raizlabs.android.dbflow.kotlinextensions.exists +import com.raizlabs.android.dbflow.kotlinextensions.from +import com.raizlabs.android.dbflow.kotlinextensions.list +import com.raizlabs.android.dbflow.kotlinextensions.result +import com.raizlabs.android.dbflow.kotlinextensions.save +import com.raizlabs.android.dbflow.kotlinextensions.select +import com.raizlabs.android.dbflow.kotlinextensions.writableDatabaseForTable +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue import org.junit.Test class OneToManyModelTest : BaseUnitTest() { @@ -23,7 +33,6 @@ class OneToManyModelTest : BaseUnitTest() { // assert loading works as expected. oneToManyModel = (select from OneToManyModel::class).result!! - val wrapper = writableDatabaseForTable() assertNotNull(oneToManyModel.getRelatedOrders()) assertTrue(!oneToManyModel.getRelatedOrders().isEmpty()) diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/OneToManyModels.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/OneToManyModels.kt index 0e92586ef..18864840b 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/OneToManyModels.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/OneToManyModels.kt @@ -5,6 +5,7 @@ import com.raizlabs.android.dbflow.annotation.OneToMany import com.raizlabs.android.dbflow.annotation.PrimaryKey import com.raizlabs.android.dbflow.annotation.Table import com.raizlabs.android.dbflow.kotlinextensions.from +import com.raizlabs.android.dbflow.kotlinextensions.oneToMany import com.raizlabs.android.dbflow.kotlinextensions.select import com.raizlabs.android.dbflow.kotlinextensions.where import com.raizlabs.android.dbflow.models.TwoColumnModel_Table.id @@ -17,20 +18,23 @@ class OneToManyModel(@PrimaryKey var name: String? = null) { var models: List? = null + @get:OneToMany(methods = arrayOf(OneToMany.Method.ALL)) + var simpleModels by oneToMany { select from OneToManyBaseModel::class } + @OneToMany(methods = arrayOf(OneToMany.Method.ALL), isVariablePrivate = true, - variableName = "orders", efficientMethods = false) + variableName = "orders", efficientMethods = false) fun getRelatedOrders(): List { var localOrders = orders if (localOrders == null) { localOrders = (select from TwoColumnModel::class where id.greaterThan(3)) - .queryList() + .queryList() } orders = localOrders return localOrders } @OneToMany(methods = arrayOf(OneToMany.Method.DELETE), isVariablePrivate = true, - variableName = "models") + variableName = "models") fun getRelatedModels(): List { var localModels = models if (localModels == null) { diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/QueryModelTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/QueryModelTest.kt index 3ed55a318..dcee6a3be 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/QueryModelTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/QueryModelTest.kt @@ -1,7 +1,12 @@ package com.raizlabs.android.dbflow.models import com.raizlabs.android.dbflow.BaseUnitTest -import com.raizlabs.android.dbflow.kotlinextensions.* +import com.raizlabs.android.dbflow.kotlinextensions.eq +import com.raizlabs.android.dbflow.kotlinextensions.exists +import com.raizlabs.android.dbflow.kotlinextensions.from +import com.raizlabs.android.dbflow.kotlinextensions.innerJoin +import com.raizlabs.android.dbflow.kotlinextensions.on +import com.raizlabs.android.dbflow.kotlinextensions.save import com.raizlabs.android.dbflow.models.Author_Table.id import com.raizlabs.android.dbflow.models.Blog_Table.author_id import com.raizlabs.android.dbflow.models.Blog_Table.name diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/SimpleTestModels.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/SimpleTestModels.kt index be19b6fac..a2cbddc53 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/SimpleTestModels.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/SimpleTestModels.kt @@ -1,7 +1,14 @@ package com.raizlabs.android.dbflow.models import com.raizlabs.android.dbflow.TestDatabase -import com.raizlabs.android.dbflow.annotation.* +import com.raizlabs.android.dbflow.annotation.Column +import com.raizlabs.android.dbflow.annotation.ColumnIgnore +import com.raizlabs.android.dbflow.annotation.ConflictAction +import com.raizlabs.android.dbflow.annotation.ForeignKey +import com.raizlabs.android.dbflow.annotation.ManyToMany +import com.raizlabs.android.dbflow.annotation.PrimaryKey +import com.raizlabs.android.dbflow.annotation.QueryModel +import com.raizlabs.android.dbflow.annotation.Table import com.raizlabs.android.dbflow.converter.TypeConverter import com.raizlabs.android.dbflow.data.Blob import com.raizlabs.android.dbflow.structure.BaseModel @@ -30,6 +37,9 @@ class CharModel(@PrimaryKey var id: Int = 0, @Column var exampleChar: Char? = nu @Table(database = TestDatabase::class) class TwoColumnModel(@PrimaryKey var name: String? = "", @Column var id: Int = 0) +@Table(database = TestDatabase::class, createWithDatabase = false) +class DontCreateModel(@PrimaryKey var id: Int = 0) + enum class Difficulty { EASY, MEDIUM, @@ -72,6 +82,12 @@ class TypeConverterModel(@PrimaryKey var id: Int = 0, @Column(typeConverter = CustomTypeConverter::class) @PrimaryKey var customType: CustomType? = null) +@Table(database = TestDatabase::class) +class EnumTypeConverterModel(@PrimaryKey var id: Int = 0, + @Column var blob: Blob? = null, + @Column(typeConverter = CustomEnumTypeConverter::class) + var difficulty: Difficulty = Difficulty.EASY) + @Table(database = TestDatabase::class, allFields = true) class FeedEntry(@PrimaryKey var id: Int = 0, var title: String? = null, @@ -79,18 +95,18 @@ class FeedEntry(@PrimaryKey var id: Int = 0, @Table(database = TestDatabase::class) @ManyToMany( - generatedTableClassName = "Refund", referencedTable = Transfer::class, - referencedTableColumnName = "refund_in", thisTableColumnName = "refund_out", - saveForeignKeyModels = true + generatedTableClassName = "Refund", referencedTable = Transfer::class, + referencedTableColumnName = "refund_in", thisTableColumnName = "refund_out", + saveForeignKeyModels = true ) data class Transfer(@PrimaryKey var transfer_id: UUID = UUID.randomUUID()) @Table(database = TestDatabase::class) data class Transfer2( - @PrimaryKey - var id: UUID = UUID.randomUUID(), - @ForeignKey(stubbedRelationship = true) - var origin: Account? = null + @PrimaryKey + var id: UUID = UUID.randomUUID(), + @ForeignKey(stubbedRelationship = true) + var origin: Account? = null ) @Table(database = TestDatabase::class) @@ -128,6 +144,18 @@ class CustomTypeConverter : TypeConverter() { } +class CustomEnumTypeConverter : TypeConverter() { + override fun getDBValue(model: Difficulty) = model.name.substring(0..0) + + override fun getModelValue(data: String) = when(data) { + "E" -> Difficulty.EASY + "M" -> Difficulty.MEDIUM + "H" -> Difficulty.HARD + else -> Difficulty.HARD + } + +} + @Table(database = TestDatabase::class) class DefaultModel(@PrimaryKey @Column(defaultValue = "5") var id: Int? = 0, @Column(defaultValue = "5.0") var location: Double? = 0.0, @@ -156,10 +184,10 @@ class TestModelParent : BaseModel() { @Table(database = TestDatabase::class) class NullableNumbers(@PrimaryKey var id: Int = 0, - @Column var float: Float? = null, - @Column var double: Double? = null, - @Column var long: Long? = null, - @Column var int: Int? = null, + @Column var f: Float? = null, + @Column var d: Double? = null, + @Column var l: Long? = null, + @Column var i: Int? = null, @Column var bigDecimal: BigDecimal? = null, @Column var bigInteger: BigInteger? = null) diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/issue/Issue.java b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/issue/Issue.java new file mode 100644 index 000000000..61d6663d6 --- /dev/null +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/issue/Issue.java @@ -0,0 +1,34 @@ +package com.raizlabs.android.dbflow.models.issue; + +import com.raizlabs.android.dbflow.TestDatabase; +import com.raizlabs.android.dbflow.annotation.OneToMany; +import com.raizlabs.android.dbflow.annotation.PrimaryKey; +import com.raizlabs.android.dbflow.annotation.Table; +import com.raizlabs.android.dbflow.sql.language.SQLite; +import com.raizlabs.android.dbflow.structure.BaseModel; + +import java.util.List; + +/** + * Description: + */ + +@Table(database = TestDatabase.class) +public class Issue extends BaseModel { + + @PrimaryKey + String id; + + List subIssueList; + + @OneToMany(methods = {OneToMany.Method.SAVE, OneToMany.Method.DELETE}, variableName = "subIssueList") + public List getDbSubIssueList() { + if (subIssueList == null || subIssueList.isEmpty()) { + subIssueList = SQLite.select() + .from(SubIssue.class) + .where(SubIssue_Table.owningIssueId.eq(id)) + .queryList(); + } + return subIssueList; + } +} diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/issue/Page.java b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/issue/Page.java new file mode 100644 index 000000000..3f93879ef --- /dev/null +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/issue/Page.java @@ -0,0 +1,25 @@ +package com.raizlabs.android.dbflow.models.issue; + +import com.raizlabs.android.dbflow.TestDatabase; +import com.raizlabs.android.dbflow.annotation.Column; +import com.raizlabs.android.dbflow.annotation.ForeignKey; +import com.raizlabs.android.dbflow.annotation.PrimaryKey; +import com.raizlabs.android.dbflow.annotation.Table; +import com.raizlabs.android.dbflow.structure.BaseModel; + +/** + * Description: + */ +@Table(database = TestDatabase.class) +public class Page extends BaseModel { + + @PrimaryKey + @Column + String id; + + @PrimaryKey + String owningIssueId; + + @ForeignKey(stubbedRelationship = true) + SubIssue subIssue; +} diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/issue/SubIssue.java b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/issue/SubIssue.java new file mode 100644 index 000000000..1841d4750 --- /dev/null +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/models/issue/SubIssue.java @@ -0,0 +1,41 @@ +package com.raizlabs.android.dbflow.models.issue; + +import com.raizlabs.android.dbflow.TestDatabase; +import com.raizlabs.android.dbflow.annotation.OneToMany; +import com.raizlabs.android.dbflow.annotation.PrimaryKey; +import com.raizlabs.android.dbflow.annotation.Table; +import com.raizlabs.android.dbflow.sql.language.SQLite; +import com.raizlabs.android.dbflow.structure.BaseModel; + +import java.util.ArrayList; +import java.util.List; + +/** + * Description: + */ + +@Table(database = TestDatabase.class) +public class SubIssue extends BaseModel { + + @PrimaryKey + String id; + + @PrimaryKey + String owningIssueId; + + List pageList; + + @OneToMany(methods = {OneToMany.Method.SAVE, OneToMany.Method.DELETE}, variableName = "pageList") + public List getDbPageList() { + if (pageList == null) { + pageList = new ArrayList<>(); + } + if (pageList.isEmpty()) { + pageList = SQLite.select() + .from(Page.class) + .where(Page_Table.owningIssueId.eq(owningIssueId), Page_Table.subIssue_id.eq(id)) + .queryList(); + } + return pageList; + } +} diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/runtime/DirectNotifierTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/runtime/DirectNotifierTest.kt index 3cdeeb3bf..34834cca5 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/runtime/DirectNotifierTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/runtime/DirectNotifierTest.kt @@ -1,17 +1,20 @@ package com.raizlabs.android.dbflow.runtime import android.content.Context -import android.os.Build import com.nhaarman.mockito_kotlin.mock import com.nhaarman.mockito_kotlin.times import com.nhaarman.mockito_kotlin.verify -import com.raizlabs.android.dbflow.BuildConfig import com.raizlabs.android.dbflow.ImmediateTransactionManager2 import com.raizlabs.android.dbflow.TestDatabase import com.raizlabs.android.dbflow.config.DatabaseConfig import com.raizlabs.android.dbflow.config.FlowConfig import com.raizlabs.android.dbflow.config.FlowManager -import com.raizlabs.android.dbflow.kotlinextensions.* +import com.raizlabs.android.dbflow.kotlinextensions.columnValues +import com.raizlabs.android.dbflow.kotlinextensions.delete +import com.raizlabs.android.dbflow.kotlinextensions.insert +import com.raizlabs.android.dbflow.kotlinextensions.save +import com.raizlabs.android.dbflow.kotlinextensions.set +import com.raizlabs.android.dbflow.kotlinextensions.update import com.raizlabs.android.dbflow.models.SimpleModel import com.raizlabs.android.dbflow.models.SimpleModel_Table import com.raizlabs.android.dbflow.structure.BaseModel @@ -25,8 +28,7 @@ import org.robolectric.RuntimeEnvironment import org.robolectric.annotation.Config @RunWith(RobolectricTestRunner::class) -@Config(constants = BuildConfig::class, sdk = intArrayOf(Build.VERSION_CODES.LOLLIPOP), - assetDir = "build/intermediates/classes/test/") +@Config (manifest = Config.NONE) class DirectNotifierTest { val context: Context diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/CaseTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/CaseTest.kt index 5f2a65731..1b29e968e 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/CaseTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/CaseTest.kt @@ -1,12 +1,14 @@ package com.raizlabs.android.dbflow.sql.language import com.raizlabs.android.dbflow.BaseUnitTest -import com.raizlabs.android.dbflow.models.SimpleModel_Table import com.raizlabs.android.dbflow.kotlinextensions.`else` import com.raizlabs.android.dbflow.kotlinextensions.case import com.raizlabs.android.dbflow.kotlinextensions.caseWhen import com.raizlabs.android.dbflow.kotlinextensions.propertyString -import org.junit.Assert.* +import com.raizlabs.android.dbflow.models.SimpleModel_Table +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue import org.junit.Test class CaseTest : BaseUnitTest() { diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/CursorResultTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/CursorResultTest.kt index 91b96ddf4..b695dc7d4 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/CursorResultTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/CursorResultTest.kt @@ -2,10 +2,19 @@ package com.raizlabs.android.dbflow.sql.language import android.database.StaleDataException import com.raizlabs.android.dbflow.BaseUnitTest +import com.raizlabs.android.dbflow.kotlinextensions.cursorResult +import com.raizlabs.android.dbflow.kotlinextensions.from +import com.raizlabs.android.dbflow.kotlinextensions.save +import com.raizlabs.android.dbflow.kotlinextensions.select +import com.raizlabs.android.dbflow.kotlinextensions.toCustomList +import com.raizlabs.android.dbflow.kotlinextensions.toCustomListClose +import com.raizlabs.android.dbflow.kotlinextensions.toCustomModel +import com.raizlabs.android.dbflow.kotlinextensions.toCustomModelClose import com.raizlabs.android.dbflow.models.SimpleCustomModel import com.raizlabs.android.dbflow.models.SimpleModel -import com.raizlabs.android.dbflow.kotlinextensions.* -import org.junit.Assert.* +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/DeleteTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/DeleteTest.kt index 0ff138276..b416ddf67 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/DeleteTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/DeleteTest.kt @@ -1,9 +1,13 @@ package com.raizlabs.android.dbflow.sql.language import com.raizlabs.android.dbflow.BaseUnitTest +import com.raizlabs.android.dbflow.kotlinextensions.delete +import com.raizlabs.android.dbflow.kotlinextensions.from +import com.raizlabs.android.dbflow.kotlinextensions.list +import com.raizlabs.android.dbflow.kotlinextensions.save +import com.raizlabs.android.dbflow.kotlinextensions.select import com.raizlabs.android.dbflow.models.SimpleModel import com.raizlabs.android.dbflow.models.SimpleModel_Table -import com.raizlabs.android.dbflow.kotlinextensions.* import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Test diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/ExistenceOperatorTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/ExistenceOperatorTest.kt index 2c30fe5c3..f4e410180 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/ExistenceOperatorTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/ExistenceOperatorTest.kt @@ -1,11 +1,11 @@ package com.raizlabs.android.dbflow.sql.language import com.raizlabs.android.dbflow.BaseUnitTest -import com.raizlabs.android.dbflow.models.SimpleModel -import com.raizlabs.android.dbflow.models.SimpleModel_Table import com.raizlabs.android.dbflow.kotlinextensions.from import com.raizlabs.android.dbflow.kotlinextensions.select import com.raizlabs.android.dbflow.kotlinextensions.where +import com.raizlabs.android.dbflow.models.SimpleModel +import com.raizlabs.android.dbflow.models.SimpleModel_Table import org.junit.Assert.assertEquals import org.junit.Test @@ -15,6 +15,6 @@ class ExistenceOperatorTest : BaseUnitTest() { @Test fun validateQuery() { assertEquals("EXISTS (SELECT * FROM `SimpleModel` WHERE `name`='name')", ExistenceOperator() - .where(select from SimpleModel::class where SimpleModel_Table.name.eq("name")).query.trim()) + .where(select from SimpleModel::class where SimpleModel_Table.name.eq("name")).query.trim()) } } \ No newline at end of file diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/FromTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/FromTest.kt index 16e373322..512c160be 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/FromTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/FromTest.kt @@ -1,15 +1,19 @@ package com.raizlabs.android.dbflow.sql.language import com.raizlabs.android.dbflow.BaseUnitTest -import com.raizlabs.android.dbflow.kotlinextensions.* +import com.raizlabs.android.dbflow.kotlinextensions.`as` +import com.raizlabs.android.dbflow.kotlinextensions.from +import com.raizlabs.android.dbflow.kotlinextensions.innerJoin +import com.raizlabs.android.dbflow.kotlinextensions.on +import com.raizlabs.android.dbflow.kotlinextensions.select import com.raizlabs.android.dbflow.models.SimpleModel import com.raizlabs.android.dbflow.models.SimpleModel_Table.name import com.raizlabs.android.dbflow.models.TwoColumnModel import com.raizlabs.android.dbflow.models.TwoColumnModel_Table import com.raizlabs.android.dbflow.models.TwoColumnModel_Table.id import com.raizlabs.android.dbflow.sql.language.SQLite.select -import junit.framework.Assert.assertEquals -import junit.framework.Assert.assertTrue +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue import org.junit.Test class FromTest : BaseUnitTest() { @@ -27,7 +31,7 @@ class FromTest : BaseUnitTest() { @Test fun validateMultipleProjection() { assertEquals("SELECT `name`,`name`,`id` FROM `SimpleModel`", - (select(name, TwoColumnModel_Table.name, id) from SimpleModel::class).query.trim()) + (select(name, TwoColumnModel_Table.name, id) from SimpleModel::class).query.trim()) } @Test @@ -38,10 +42,10 @@ class FromTest : BaseUnitTest() { @Test fun validateJoins() { val from = (select from SimpleModel::class - innerJoin TwoColumnModel::class - on name.eq(TwoColumnModel_Table.name.withTable())) + innerJoin TwoColumnModel::class + on name.eq(TwoColumnModel_Table.name.withTable())) assertEquals("SELECT * FROM `SimpleModel` INNER JOIN `TwoColumnModel` ON `name`=`TwoColumnModel`.`name`", - from.query.trim()) + from.query.trim()) assertTrue(from.associatedTables.isNotEmpty()) } } \ No newline at end of file diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/IndexTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/IndexTest.kt index 3b81104fb..0dc98776b 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/IndexTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/IndexTest.kt @@ -1,10 +1,10 @@ package com.raizlabs.android.dbflow.sql.language import com.raizlabs.android.dbflow.BaseUnitTest -import com.raizlabs.android.dbflow.models.SimpleModel -import com.raizlabs.android.dbflow.models.SimpleModel_Table import com.raizlabs.android.dbflow.kotlinextensions.indexOn import com.raizlabs.android.dbflow.kotlinextensions.nameAlias +import com.raizlabs.android.dbflow.models.SimpleModel +import com.raizlabs.android.dbflow.models.SimpleModel_Table import org.junit.Assert.assertEquals import org.junit.Test diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/IndexedByTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/IndexedByTest.kt index a16d8fa08..77a6a74fc 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/IndexedByTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/IndexedByTest.kt @@ -1,10 +1,10 @@ package com.raizlabs.android.dbflow.sql.language import com.raizlabs.android.dbflow.BaseUnitTest -import com.raizlabs.android.dbflow.models.SimpleModel -import com.raizlabs.android.dbflow.models.SimpleModel_Table import com.raizlabs.android.dbflow.kotlinextensions.from import com.raizlabs.android.dbflow.kotlinextensions.select +import com.raizlabs.android.dbflow.models.SimpleModel +import com.raizlabs.android.dbflow.models.SimpleModel_Table import com.raizlabs.android.dbflow.sql.language.property.IndexProperty import org.junit.Assert.assertEquals import org.junit.Test diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/InsertTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/InsertTest.kt index 8387af691..21178f025 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/InsertTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/InsertTest.kt @@ -2,15 +2,14 @@ package com.raizlabs.android.dbflow.sql.language import android.content.ContentValues import com.raizlabs.android.dbflow.BaseUnitTest -import com.raizlabs.android.dbflow.models.SimpleModel -import com.raizlabs.android.dbflow.models.TwoColumnModel -import com.raizlabs.android.dbflow.models.TwoColumnModel_Table.id -import com.raizlabs.android.dbflow.models.TwoColumnModel_Table.name import com.raizlabs.android.dbflow.kotlinextensions.from import com.raizlabs.android.dbflow.kotlinextensions.insert import com.raizlabs.android.dbflow.kotlinextensions.select import com.raizlabs.android.dbflow.kotlinextensions.set -import com.raizlabs.android.dbflow.sql.language.property.IProperty +import com.raizlabs.android.dbflow.models.SimpleModel +import com.raizlabs.android.dbflow.models.TwoColumnModel +import com.raizlabs.android.dbflow.models.TwoColumnModel_Table.id +import com.raizlabs.android.dbflow.models.TwoColumnModel_Table.name import org.junit.Assert.assertEquals import org.junit.Test @@ -50,7 +49,7 @@ class InsertTest : BaseUnitTest() { assertEquals("INSERT INTO `TwoColumnModel`(`name`, `id`) VALUES('name', 'id')", insert().columns("name", "id").values("name", "id").query.trim()) assertEquals("INSERT INTO `TwoColumnModel`(`name`, `id`) VALUES('name', 'id')", - insert().columns(arrayListOf(name, id) as List>>).values("name", "id").query.trim()) + insert().columns(listOf(name, id)).values("name", "id").query.trim()) } @Test diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/JoinTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/JoinTest.kt index 808322621..be2acea20 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/JoinTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/JoinTest.kt @@ -1,12 +1,19 @@ package com.raizlabs.android.dbflow.sql.language import com.raizlabs.android.dbflow.BaseUnitTest -import com.raizlabs.android.dbflow.kotlinextensions.* +import com.raizlabs.android.dbflow.kotlinextensions.crossJoin +import com.raizlabs.android.dbflow.kotlinextensions.from +import com.raizlabs.android.dbflow.kotlinextensions.innerJoin +import com.raizlabs.android.dbflow.kotlinextensions.leftOuterJoin +import com.raizlabs.android.dbflow.kotlinextensions.naturalJoin +import com.raizlabs.android.dbflow.kotlinextensions.on +import com.raizlabs.android.dbflow.kotlinextensions.select +import com.raizlabs.android.dbflow.kotlinextensions.using import com.raizlabs.android.dbflow.models.SimpleModel import com.raizlabs.android.dbflow.models.SimpleModel_Table import com.raizlabs.android.dbflow.models.TwoColumnModel import com.raizlabs.android.dbflow.models.TwoColumnModel_Table -import junit.framework.Assert.assertEquals +import org.junit.Assert.assertEquals import org.junit.Test @@ -15,57 +22,57 @@ class JoinTest : BaseUnitTest() { @Test fun validateAliasJoin() { assertEquals("SELECT * FROM `SimpleModel` INNER JOIN `TwoColumnModel` AS `Name` ON `TwoColumnModel`.`name`=`name`", - ((select from SimpleModel::class innerJoin - TwoColumnModel::class).`as`("Name") on TwoColumnModel_Table.name.withTable().eq(SimpleModel_Table.name)).query.trim()) + ((select from SimpleModel::class innerJoin + TwoColumnModel::class).`as`("Name") on TwoColumnModel_Table.name.withTable().eq(SimpleModel_Table.name)).query.trim()) } @Test fun testInnerJoin() { val join = select from SimpleModel::class innerJoin - TwoColumnModel::class on TwoColumnModel_Table.name.withTable().eq(SimpleModel_Table.name) + TwoColumnModel::class on TwoColumnModel_Table.name.withTable().eq(SimpleModel_Table.name) assertEquals("SELECT * FROM `SimpleModel` INNER JOIN `TwoColumnModel` ON `TwoColumnModel`.`name`=`name`", - join.query.trim()) + join.query.trim()) } @Test fun testLeftOuterJoin() { val join = select from SimpleModel::class leftOuterJoin - TwoColumnModel::class on TwoColumnModel_Table.name.withTable().eq(SimpleModel_Table.name) + TwoColumnModel::class on TwoColumnModel_Table.name.withTable().eq(SimpleModel_Table.name) assertEquals("SELECT * FROM `SimpleModel` LEFT OUTER JOIN `TwoColumnModel` ON `TwoColumnModel`.`name`=`name`", - join.query.trim()) + join.query.trim()) } @Test fun testCrossJoin() { val join = select from SimpleModel::class crossJoin - TwoColumnModel::class on TwoColumnModel_Table.name.withTable().eq(SimpleModel_Table.name) + TwoColumnModel::class on TwoColumnModel_Table.name.withTable().eq(SimpleModel_Table.name) assertEquals("SELECT * FROM `SimpleModel` CROSS JOIN `TwoColumnModel` ON `TwoColumnModel`.`name`=`name`", - join.query.trim()) + join.query.trim()) } @Test fun testMultiJoin() { val join = select from SimpleModel::class innerJoin - TwoColumnModel::class on TwoColumnModel_Table.name.withTable().eq(SimpleModel_Table.name) crossJoin - TwoColumnModel::class on TwoColumnModel_Table.id.withTable().eq(SimpleModel_Table.name) + TwoColumnModel::class on TwoColumnModel_Table.name.withTable().eq(SimpleModel_Table.name) crossJoin + TwoColumnModel::class on TwoColumnModel_Table.id.withTable().eq(SimpleModel_Table.name) assertEquals("SELECT * FROM `SimpleModel` INNER JOIN `TwoColumnModel` ON `TwoColumnModel`.`name`=`name`" + - " CROSS JOIN `TwoColumnModel` ON `TwoColumnModel`.`id`=`name`", - join.query.trim()) + " CROSS JOIN `TwoColumnModel` ON `TwoColumnModel`.`id`=`name`", + join.query.trim()) } @Test fun testInnerJoinOnUsing() { val join = select from SimpleModel::class innerJoin - TwoColumnModel::class using SimpleModel_Table.name.withTable() + TwoColumnModel::class using SimpleModel_Table.name.withTable() assertEquals("SELECT * FROM `SimpleModel` INNER JOIN `TwoColumnModel` USING (`SimpleModel`.`name`)", - join.query.trim()) + join.query.trim()) } @Test fun testNaturalJoin() { val join = (select from SimpleModel::class naturalJoin - TwoColumnModel::class).end() + TwoColumnModel::class).end() assertEquals("SELECT * FROM `SimpleModel` NATURAL JOIN `TwoColumnModel`", - join.query.trim()) + join.query.trim()) } } \ No newline at end of file diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/MethodTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/MethodTest.kt index 09f611d67..d1d63bb9d 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/MethodTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/MethodTest.kt @@ -4,8 +4,21 @@ import com.raizlabs.android.dbflow.BaseUnitTest import com.raizlabs.android.dbflow.models.TwoColumnModel_Table.id import com.raizlabs.android.dbflow.models.TwoColumnModel_Table.name import com.raizlabs.android.dbflow.sql.SQLiteType -import com.raizlabs.android.dbflow.sql.language.Method.* -import junit.framework.Assert.assertEquals +import com.raizlabs.android.dbflow.sql.language.Method.avg +import com.raizlabs.android.dbflow.sql.language.Method.cast +import com.raizlabs.android.dbflow.sql.language.Method.count +import com.raizlabs.android.dbflow.sql.language.Method.date +import com.raizlabs.android.dbflow.sql.language.Method.datetime +import com.raizlabs.android.dbflow.sql.language.Method.group_concat +import com.raizlabs.android.dbflow.sql.language.Method.ifNull +import com.raizlabs.android.dbflow.sql.language.Method.max +import com.raizlabs.android.dbflow.sql.language.Method.min +import com.raizlabs.android.dbflow.sql.language.Method.nullIf +import com.raizlabs.android.dbflow.sql.language.Method.replace +import com.raizlabs.android.dbflow.sql.language.Method.strftime +import com.raizlabs.android.dbflow.sql.language.Method.sum +import com.raizlabs.android.dbflow.sql.language.Method.total +import org.junit.Assert.assertEquals import org.junit.Test class MethodTest : BaseUnitTest() { diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/NameAliasTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/NameAliasTest.kt index 160210fad..8b9854071 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/NameAliasTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/NameAliasTest.kt @@ -3,8 +3,8 @@ package com.raizlabs.android.dbflow.sql.language import com.raizlabs.android.dbflow.BaseUnitTest import com.raizlabs.android.dbflow.kotlinextensions.`as` import com.raizlabs.android.dbflow.kotlinextensions.nameAlias -import junit.framework.Assert.assertEquals -import junit.framework.Assert.assertFalse +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse import org.junit.Test class NameAliasTest : BaseUnitTest() { diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/OperatorTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/OperatorTest.kt index 568d90aa2..b557c1d1f 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/OperatorTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/OperatorTest.kt @@ -3,7 +3,12 @@ package com.raizlabs.android.dbflow.sql.language import com.raizlabs.android.dbflow.BaseUnitTest import com.raizlabs.android.dbflow.annotation.Collate import com.raizlabs.android.dbflow.assertEquals -import com.raizlabs.android.dbflow.kotlinextensions.* +import com.raizlabs.android.dbflow.kotlinextensions.and +import com.raizlabs.android.dbflow.kotlinextensions.between +import com.raizlabs.android.dbflow.kotlinextensions.collate +import com.raizlabs.android.dbflow.kotlinextensions.from +import com.raizlabs.android.dbflow.kotlinextensions.op +import com.raizlabs.android.dbflow.kotlinextensions.select import com.raizlabs.android.dbflow.models.SimpleModel import com.raizlabs.android.dbflow.models.TwoColumnModel_Table.id import org.junit.Test diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/OrderByTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/OrderByTest.kt index 0e32150fb..38c9b82f6 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/OrderByTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/OrderByTest.kt @@ -1,11 +1,11 @@ package com.raizlabs.android.dbflow.sql.language import com.raizlabs.android.dbflow.BaseUnitTest -import com.raizlabs.android.dbflow.models.SimpleModel_Table.name import com.raizlabs.android.dbflow.annotation.Collate import com.raizlabs.android.dbflow.assertEquals import com.raizlabs.android.dbflow.kotlinextensions.collate import com.raizlabs.android.dbflow.kotlinextensions.nameAlias +import com.raizlabs.android.dbflow.models.SimpleModel_Table.name import org.junit.Test class OrderByTest : BaseUnitTest() { diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/SelectTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/SelectTest.kt index 854d5b9f4..cd9f72d48 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/SelectTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/SelectTest.kt @@ -1,12 +1,12 @@ package com.raizlabs.android.dbflow.sql.language import com.raizlabs.android.dbflow.BaseUnitTest +import com.raizlabs.android.dbflow.assertEquals +import com.raizlabs.android.dbflow.kotlinextensions.from import com.raizlabs.android.dbflow.models.SimpleModel import com.raizlabs.android.dbflow.models.TwoColumnModel import com.raizlabs.android.dbflow.models.TwoColumnModel_Table.id import com.raizlabs.android.dbflow.models.TwoColumnModel_Table.name -import com.raizlabs.android.dbflow.assertEquals -import com.raizlabs.android.dbflow.kotlinextensions.from import com.raizlabs.android.dbflow.sql.language.SQLite.select import org.junit.Test diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/SetTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/SetTest.kt index 7518b904d..f83a64dfc 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/SetTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/SetTest.kt @@ -1,10 +1,10 @@ package com.raizlabs.android.dbflow.sql.language import com.raizlabs.android.dbflow.BaseUnitTest +import com.raizlabs.android.dbflow.assertEquals import com.raizlabs.android.dbflow.models.SimpleModel import com.raizlabs.android.dbflow.models.SimpleModel_Table.name import com.raizlabs.android.dbflow.models.TwoColumnModel_Table.id -import com.raizlabs.android.dbflow.assertEquals import com.raizlabs.android.dbflow.sql.Query import org.junit.Test @@ -13,13 +13,13 @@ class SetTest : BaseUnitTest() { @Test fun validateSetWithConditions() { assertEquals("SET `name`='name'", - Set(Query { "" }, SimpleModel::class.java).conditions(name.`is`("name"))) + Set(Query { "" }, SimpleModel::class.java).conditions(name.`is`("name"))) } @Test fun validateMultipleConditions() { assertEquals("SET `name`='name', `id`=0", - Set(Query { "" }, SimpleModel::class.java) - .conditions(name.`is`("name"), id.`is`(0))) + Set(Query { "" }, SimpleModel::class.java) + .conditions(name.`is`("name"), id.`is`(0))) } } \ No newline at end of file diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/TriggerTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/TriggerTest.kt index aedaf2f2d..7a108451d 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/TriggerTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/TriggerTest.kt @@ -1,12 +1,23 @@ package com.raizlabs.android.dbflow.sql.language import com.raizlabs.android.dbflow.BaseUnitTest +import com.raizlabs.android.dbflow.assertEquals +import com.raizlabs.android.dbflow.kotlinextensions.and +import com.raizlabs.android.dbflow.kotlinextensions.begin +import com.raizlabs.android.dbflow.kotlinextensions.columnValues +import com.raizlabs.android.dbflow.kotlinextensions.createTrigger +import com.raizlabs.android.dbflow.kotlinextensions.eq +import com.raizlabs.android.dbflow.kotlinextensions.from +import com.raizlabs.android.dbflow.kotlinextensions.insert +import com.raizlabs.android.dbflow.kotlinextensions.insertOn +import com.raizlabs.android.dbflow.kotlinextensions.property +import com.raizlabs.android.dbflow.kotlinextensions.select +import com.raizlabs.android.dbflow.kotlinextensions.updateOn +import com.raizlabs.android.dbflow.kotlinextensions.where import com.raizlabs.android.dbflow.models.SimpleModel import com.raizlabs.android.dbflow.models.SimpleModel_Table.name import com.raizlabs.android.dbflow.models.TwoColumnModel import com.raizlabs.android.dbflow.models.TwoColumnModel_Table.id -import com.raizlabs.android.dbflow.assertEquals -import com.raizlabs.android.dbflow.kotlinextensions.* import com.raizlabs.android.dbflow.sql.SQLiteType import org.junit.Assert.assertNotNull import org.junit.Test @@ -16,32 +27,32 @@ class TriggerTest : BaseUnitTest() { @Test fun validateBasicTrigger() { assertEquals("CREATE TRIGGER IF NOT EXISTS `MyTrigger` AFTER INSERT ON `SimpleModel` " + - "\nBEGIN" + - "\nINSERT INTO `TwoColumnModel`(`name`) VALUES(`new`.`name`);" + - "\nEND", - createTrigger("MyTrigger").after() insertOn SimpleModel::class begin - insert(TwoColumnModel::class).columnValues(name to NameAlias.ofTable("new", "name"))) + "\nBEGIN" + + "\nINSERT INTO `TwoColumnModel`(`name`) VALUES(`new`.`name`);" + + "\nEND", + createTrigger("MyTrigger").after() insertOn SimpleModel::class begin + insert(TwoColumnModel::class).columnValues(name to NameAlias.ofTable("new", "name"))) } @Test fun validateUpdateTriggerMultiline() { assertEquals("CREATE TEMP TRIGGER IF NOT EXISTS `MyTrigger` BEFORE UPDATE ON `SimpleModel` " + - "\nBEGIN" + - "\nINSERT INTO `TwoColumnModel`(`name`) VALUES(`new`.`name`);" + - "\nINSERT INTO `TwoColumnModel`(`id`) VALUES(CAST(`new`.`name` AS INTEGER));" + - "\nEND", - createTrigger("MyTrigger").temporary().before() updateOn SimpleModel::class begin - insert(TwoColumnModel::class).columnValues(name to NameAlias.ofTable("new", "name")) and - insert(TwoColumnModel::class) - .columnValues(id to Method.cast(NameAlias.ofTable("new", "name").property) - .`as`(SQLiteType.INTEGER))) + "\nBEGIN" + + "\nINSERT INTO `TwoColumnModel`(`name`) VALUES(`new`.`name`);" + + "\nINSERT INTO `TwoColumnModel`(`id`) VALUES(CAST(`new`.`name` AS INTEGER));" + + "\nEND", + createTrigger("MyTrigger").temporary().before() updateOn SimpleModel::class begin + insert(TwoColumnModel::class).columnValues(name to NameAlias.ofTable("new", "name")) and + insert(TwoColumnModel::class) + .columnValues(id to Method.cast(NameAlias.ofTable("new", "name").property) + .`as`(SQLiteType.INTEGER))) } @Test fun validateTriggerWorks() { val trigger = createTrigger("MyTrigger").after() insertOn SimpleModel::class begin - insert(TwoColumnModel::class).columnValues(name to NameAlias.ofTable("new", "name")) + insert(TwoColumnModel::class).columnValues(name to NameAlias.ofTable("new", "name")) trigger.enable() SimpleModel("Test").insert() diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/UnsafeStringOperatorTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/UnsafeStringOperatorTest.kt index 4ad3a9fcb..fd3998184 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/UnsafeStringOperatorTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/UnsafeStringOperatorTest.kt @@ -1,11 +1,11 @@ package com.raizlabs.android.dbflow.sql.language import com.raizlabs.android.dbflow.BaseUnitTest -import com.raizlabs.android.dbflow.models.SimpleModel import com.raizlabs.android.dbflow.assertEquals import com.raizlabs.android.dbflow.kotlinextensions.from import com.raizlabs.android.dbflow.kotlinextensions.select import com.raizlabs.android.dbflow.kotlinextensions.where +import com.raizlabs.android.dbflow.models.SimpleModel import org.junit.Test class UnsafeStringOperatorTest : BaseUnitTest() { @@ -15,6 +15,6 @@ class UnsafeStringOperatorTest : BaseUnitTest() { val op = UnSafeStringOperator("name = ?, id = ?, test = ?", arrayOf("'name'", "0", "'test'")) assertEquals("name = 'name', id = 0, test = 'test'", op) assertEquals("SELECT * FROM `SimpleModel` WHERE name = 'name', id = 0, test = 'test'", - select from SimpleModel::class where op) + select from SimpleModel::class where op) } } \ No newline at end of file diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/UpdateTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/UpdateTest.kt index 09fb28e90..fb7e0c46a 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/UpdateTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/UpdateTest.kt @@ -48,8 +48,8 @@ class UpdateTest : BaseUnitTest() { @Test fun validateWildcardQuery() { assertEquals("UPDATE OR FAIL `NumberModel` SET `id`=? WHERE `id`=?", - update().or(ConflictAction.FAIL) - .set(id.eq(Property.WILDCARD)) - .where(id.eq(Property.WILDCARD))) + update().or(ConflictAction.FAIL) + .set(id.eq(Property.WILDCARD)) + .where(id.eq(Property.WILDCARD))) } } \ No newline at end of file diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/WhereTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/WhereTest.kt index 7adaf749c..d6b053ebd 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/WhereTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/WhereTest.kt @@ -1,12 +1,26 @@ package com.raizlabs.android.dbflow.sql.language import com.raizlabs.android.dbflow.BaseUnitTest +import com.raizlabs.android.dbflow.assertEquals +import com.raizlabs.android.dbflow.kotlinextensions.and +import com.raizlabs.android.dbflow.kotlinextensions.from +import com.raizlabs.android.dbflow.kotlinextensions.groupBy +import com.raizlabs.android.dbflow.kotlinextensions.having +import com.raizlabs.android.dbflow.kotlinextensions.limit +import com.raizlabs.android.dbflow.kotlinextensions.list +import com.raizlabs.android.dbflow.kotlinextensions.nameAlias +import com.raizlabs.android.dbflow.kotlinextensions.offset +import com.raizlabs.android.dbflow.kotlinextensions.or +import com.raizlabs.android.dbflow.kotlinextensions.orderBy +import com.raizlabs.android.dbflow.kotlinextensions.result +import com.raizlabs.android.dbflow.kotlinextensions.select +import com.raizlabs.android.dbflow.kotlinextensions.update +import com.raizlabs.android.dbflow.kotlinextensions.where +import com.raizlabs.android.dbflow.kotlinextensions.whereExists import com.raizlabs.android.dbflow.models.SimpleModel import com.raizlabs.android.dbflow.models.SimpleModel_Table.name import com.raizlabs.android.dbflow.models.TwoColumnModel import com.raizlabs.android.dbflow.models.TwoColumnModel_Table.id -import com.raizlabs.android.dbflow.assertEquals -import com.raizlabs.android.dbflow.kotlinextensions.* import com.raizlabs.android.dbflow.sql.language.OrderBy.fromNameAlias import com.raizlabs.android.dbflow.sql.language.SQLite.select import org.junit.Assert.fail @@ -17,92 +31,92 @@ class WhereTest : BaseUnitTest() { @Test fun validateBasicWhere() { assertEquals("SELECT * FROM `SimpleModel` WHERE `name`='name'", - select from SimpleModel::class where name.`is`("name")) + select from SimpleModel::class where name.`is`("name")) } @Test fun validateComplexQueryWhere() { assertEquals("SELECT * FROM `SimpleModel` WHERE `name`='name' OR `id`=1 AND (`id`=0 OR `name`='hi')", - select from SimpleModel::class where name.`is`("name") or id.eq(1) and (id.`is`(0) or name.eq("hi"))) + select from SimpleModel::class where name.`is`("name") or id.eq(1) and (id.`is`(0) or name.eq("hi"))) } @Test fun validateGroupBy() { assertEquals("SELECT * FROM `SimpleModel` WHERE `name`='name' GROUP BY `name`", - select from SimpleModel::class where name.`is`("name") groupBy name) + select from SimpleModel::class where name.`is`("name") groupBy name) } @Test fun validateGroupByNameAlias() { assertEquals("SELECT * FROM `SimpleModel` WHERE `name`='name' GROUP BY `name`,`id`", - (select from SimpleModel::class where name.`is`("name")).groupBy("name".nameAlias, "id".nameAlias)) + (select from SimpleModel::class where name.`is`("name")).groupBy("name".nameAlias, "id".nameAlias)) } @Test fun validateGroupByNameProps() { assertEquals("SELECT * FROM `SimpleModel` WHERE `name`='name' GROUP BY `name`,`id`", - (select from SimpleModel::class where name.`is`("name")).groupBy(name, id)) + (select from SimpleModel::class where name.`is`("name")).groupBy(name, id)) } @Test fun validateHaving() { assertEquals("SELECT * FROM `SimpleModel` WHERE `name`='name' HAVING `name` LIKE 'That'", - select from SimpleModel::class where name.`is`("name") having name.like("That")) + select from SimpleModel::class where name.`is`("name") having name.like("That")) } @Test fun validateLimit() { assertEquals("SELECT * FROM `SimpleModel` WHERE `name`='name' LIMIT 10", - select from SimpleModel::class where name.`is`("name") limit 10) + select from SimpleModel::class where name.`is`("name") limit 10) } @Test fun validateOffset() { assertEquals("SELECT * FROM `SimpleModel` WHERE `name`='name' OFFSET 10", - select from SimpleModel::class where name.`is`("name") offset 10) + select from SimpleModel::class where name.`is`("name") offset 10) } @Test fun validateWhereExists() { assertEquals("SELECT * FROM `SimpleModel` " + - "WHERE EXISTS (SELECT `name` FROM `SimpleModel` WHERE `name` LIKE 'Andrew')", - select from SimpleModel::class - whereExists (select(name) from SimpleModel::class where name.like("Andrew"))) + "WHERE EXISTS (SELECT `name` FROM `SimpleModel` WHERE `name` LIKE 'Andrew')", + select from SimpleModel::class + whereExists (select(name) from SimpleModel::class where name.like("Andrew"))) } @Test fun validateOrderByWhere() { assertEquals("SELECT * FROM `SimpleModel` " + - "WHERE `name`='name' ORDER BY `name` ASC", - (select from SimpleModel::class - where name.eq("name")).orderBy(name, true)) + "WHERE `name`='name' ORDER BY `name` ASC", + (select from SimpleModel::class + where name.eq("name")).orderBy(name, true)) } @Test fun validateOrderByWhereAlias() { assertEquals("SELECT * FROM `SimpleModel` " + - "WHERE `name`='name' ORDER BY `name` ASC", - (select from SimpleModel::class - where name.eq("name")).orderBy("name".nameAlias, true)) + "WHERE `name`='name' ORDER BY `name` ASC", + (select from SimpleModel::class + where name.eq("name")).orderBy("name".nameAlias, true)) } @Test fun validateOrderBy() { assertEquals("SELECT * FROM `SimpleModel` " + - "WHERE `name`='name' ORDER BY `name` ASC", - select from SimpleModel::class - where name.eq("name") orderBy fromNameAlias("name".nameAlias).ascending()) + "WHERE `name`='name' ORDER BY `name` ASC", + select from SimpleModel::class + where name.eq("name") orderBy fromNameAlias("name".nameAlias).ascending()) } @Test fun validateOrderByAll() { assertEquals("SELECT * FROM `TwoColumnModel` " + - "WHERE `name`='name' ORDER BY `name` ASC,`id` DESC", - (select from TwoColumnModel::class - where name.eq("name")) - .orderByAll(listOf( - fromNameAlias("name".nameAlias).ascending(), - fromNameAlias("id".nameAlias).descending()))) + "WHERE `name`='name' ORDER BY `name` ASC,`id` DESC", + (select from TwoColumnModel::class + where name.eq("name")) + .orderByAll(listOf( + fromNameAlias("name".nameAlias).ascending(), + fromNameAlias("id".nameAlias).descending()))) } @Test diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/property/PropertyFactoryTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/property/PropertyFactoryTest.kt index f3e9fecce..7476f9c6f 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/property/PropertyFactoryTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/property/PropertyFactoryTest.kt @@ -1,11 +1,11 @@ package com.raizlabs.android.dbflow.sql.language.property import com.raizlabs.android.dbflow.BaseUnitTest -import com.raizlabs.android.dbflow.models.SimpleModel import com.raizlabs.android.dbflow.kotlinextensions.from import com.raizlabs.android.dbflow.kotlinextensions.property import com.raizlabs.android.dbflow.kotlinextensions.propertyString import com.raizlabs.android.dbflow.kotlinextensions.select +import com.raizlabs.android.dbflow.models.SimpleModel import org.junit.Assert.assertEquals import org.junit.Test diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/property/TypeConvertedPropertyTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/property/TypeConvertedPropertyTest.kt index 162df2733..8289bb323 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/property/TypeConvertedPropertyTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/language/property/TypeConvertedPropertyTest.kt @@ -1,8 +1,11 @@ package com.raizlabs.android.dbflow.sql.language.property import com.raizlabs.android.dbflow.BaseUnitTest -import com.raizlabs.android.dbflow.models.SimpleModel import com.raizlabs.android.dbflow.converter.DateConverter +import com.raizlabs.android.dbflow.models.Difficulty +import com.raizlabs.android.dbflow.models.EnumTypeConverterModel_Table +import com.raizlabs.android.dbflow.models.SimpleModel +import com.raizlabs.android.dbflow.sql.language.NameAlias import org.junit.Assert.assertEquals import org.junit.Test import java.util.* @@ -19,7 +22,17 @@ class TypeConvertedPropertyTest : BaseUnitTest() { val date = Date() assertEquals("`Prop`=${date.time}", property.eq(date).query) + assertEquals("`SimpleModel`.`Prop`=${date.time}", property.withTable().eq(date).query) + val inverted = property.invertProperty() assertEquals("`Prop`=5050505", inverted.eq(5050505).query) } + + @Test + fun testCustomEnumTypeConverter() { + + assertEquals("`difficulty`='H'", EnumTypeConverterModel_Table.difficulty.eq(Difficulty.HARD).query) + assertEquals("`EnumTypeConverterModel`.`difficulty`='H'", EnumTypeConverterModel_Table.difficulty.withTable().eq(Difficulty.HARD).query) + assertEquals("`et`.`difficulty`='H'", EnumTypeConverterModel_Table.difficulty.withTable(NameAlias.builder("et").build()).eq(Difficulty.HARD).query) + } } \ No newline at end of file diff --git a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/queriable/AsyncQueryTest.kt b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/queriable/AsyncQueryTest.kt index d62c8c2bf..10925cc4f 100644 --- a/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/queriable/AsyncQueryTest.kt +++ b/dbflow-tests/src/test/java/com/raizlabs/android/dbflow/sql/queriable/AsyncQueryTest.kt @@ -1,8 +1,14 @@ package com.raizlabs.android.dbflow.sql.queriable import com.raizlabs.android.dbflow.BaseUnitTest +import com.raizlabs.android.dbflow.kotlinextensions.async +import com.raizlabs.android.dbflow.kotlinextensions.cursorResult +import com.raizlabs.android.dbflow.kotlinextensions.from +import com.raizlabs.android.dbflow.kotlinextensions.list +import com.raizlabs.android.dbflow.kotlinextensions.result +import com.raizlabs.android.dbflow.kotlinextensions.save +import com.raizlabs.android.dbflow.kotlinextensions.select import com.raizlabs.android.dbflow.models.SimpleModel -import com.raizlabs.android.dbflow.kotlinextensions.* import com.raizlabs.android.dbflow.sql.language.CursorResult import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull diff --git a/dbflow-tests/src/test/resources/com/android/tools/test_config.properties b/dbflow-tests/src/test/resources/com/android/tools/test_config.properties new file mode 100644 index 000000000..b26a774fd --- /dev/null +++ b/dbflow-tests/src/test/resources/com/android/tools/test_config.properties @@ -0,0 +1,3 @@ +android_merged_manifest=./build/intermediates/manifests/full/debug/AndroidManifest.xml +android_merged_resources=./build/intermediates/res/merged/debug +android_merged_assets=./build/intermediates/assets/debug \ No newline at end of file diff --git a/dbflow/build.gradle b/dbflow/build.gradle index 521f11295..896bdc472 100644 --- a/dbflow/build.gradle +++ b/dbflow/build.gradle @@ -24,8 +24,8 @@ android { } dependencies { - compile project("${dbflow_project_prefix}dbflow-core") - compile "com.android.support:support-annotations:25.3.1" + api project("${dbflow_project_prefix}dbflow-core") + api "com.android.support:support-annotations:26.0.1" } apply from: '../android-artifacts.gradle' diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/config/DatabaseConfig.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/config/DatabaseConfig.java index 347b41996..11c3d50cd 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/config/DatabaseConfig.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/config/DatabaseConfig.java @@ -3,6 +3,7 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import com.raizlabs.android.dbflow.StringUtils; import com.raizlabs.android.dbflow.runtime.BaseTransactionManager; import com.raizlabs.android.dbflow.runtime.ModelNotifier; import com.raizlabs.android.dbflow.structure.database.DatabaseHelperListener; @@ -16,6 +17,14 @@ */ public final class DatabaseConfig { + public static DatabaseConfig.Builder builder(@NonNull Class database) { + return new DatabaseConfig.Builder(database); + } + + public static DatabaseConfig.Builder inMemoryBuilder(@NonNull Class database) { + return new DatabaseConfig.Builder(database).inMemory(); + } + public interface OpenHelperCreator { OpenHelper createHelper(DatabaseDefinition databaseDefinition, DatabaseHelperListener helperListener); @@ -32,7 +41,9 @@ public interface TransactionManagerCreator { private final DatabaseHelperListener helperListener; private final Map, TableConfig> tableConfigMap; private final ModelNotifier modelNotifier; - + private final boolean inMemory; + private final String databaseName; + private final String databaseExtensionName; DatabaseConfig(Builder builder) { openHelperCreator = builder.openHelperCreator; @@ -41,6 +52,33 @@ public interface TransactionManagerCreator { helperListener = builder.helperListener; tableConfigMap = builder.tableConfigMap; modelNotifier = builder.modelNotifier; + inMemory = builder.inMemory; + if (builder.databaseName == null) { + databaseName = builder.databaseClass.getSimpleName(); + } else { + databaseName = builder.databaseName; + } + + if (builder.databaseExtensionName == null) { + databaseExtensionName = ".db"; + } else { + databaseExtensionName = StringUtils.isNotNullOrEmpty(builder.databaseExtensionName) + ? "." + builder.databaseExtensionName : ""; + } + } + + @NonNull + public String getDatabaseExtensionName() { + return databaseExtensionName; + } + + public boolean isInMemory() { + return inMemory; + } + + @NonNull + public String getDatabaseName() { + return databaseName; } @Nullable @@ -87,6 +125,9 @@ public static final class Builder { DatabaseHelperListener helperListener; final Map, TableConfig> tableConfigMap = new HashMap<>(); ModelNotifier modelNotifier; + boolean inMemory = false; + String databaseName; + String databaseExtensionName; public Builder(@NonNull Class databaseClass) { this.databaseClass = databaseClass; @@ -112,6 +153,30 @@ public Builder modelNotifier(ModelNotifier modelNotifier) { return this; } + @NonNull + public Builder inMemory() { + inMemory = true; + return this; + } + + /** + * @return Pass in dynamic database name here. Otherwise it defaults to class name. + */ + @NonNull + public Builder databaseName(String name) { + databaseName = name; + return this; + } + + /** + * @return Pass in the extension for the DB here. + * Otherwise defaults to ".db". If empty string passed, no extension is used. + */ + public Builder extensionName(String name) { + databaseExtensionName = name; + return this; + } + /** * Overrides the default {@link OpenHelper} for a {@link DatabaseDefinition}. * diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/config/DatabaseDefinition.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/config/DatabaseDefinition.java index 42ed846aa..b7f64040b 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/config/DatabaseDefinition.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/config/DatabaseDefinition.java @@ -4,7 +4,6 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.raizlabs.android.dbflow.StringUtils; import com.raizlabs.android.dbflow.annotation.Database; import com.raizlabs.android.dbflow.annotation.QueryModel; import com.raizlabs.android.dbflow.annotation.Table; @@ -73,12 +72,16 @@ public abstract class DatabaseDefinition { @Nullable private ModelNotifier modelNotifier; - @SuppressWarnings("unchecked") public DatabaseDefinition() { - databaseConfig = FlowManager.getConfig() - .databaseConfigMap().get(getAssociatedDatabaseClassFile()); - + applyDatabaseConfig(FlowManager.getConfig().databaseConfigMap().get(getAssociatedDatabaseClassFile())); + } + /** + * Applies a database configuration object to this class. + */ + @SuppressWarnings({"unchecked", "ConstantConditions"}) + void applyDatabaseConfig(@Nullable DatabaseConfig databaseConfig) { + this.databaseConfig = databaseConfig; if (databaseConfig != null) { // initialize configuration if exists. Collection tableConfigCollection = databaseConfig.tableConfigMap().values(); @@ -288,15 +291,16 @@ public void executeTransaction(@NonNull ITransaction transaction) { * @return The name of this database as defined in {@link Database} */ @NonNull - public abstract String getDatabaseName(); + public String getDatabaseName() { + return databaseConfig != null ? databaseConfig.getDatabaseName() : getAssociatedDatabaseClassFile().getSimpleName(); + } /** * @return The file name that this database points to */ @NonNull public String getDatabaseFileName() { - return getDatabaseName() + (StringUtils.isNotNullOrEmpty(getDatabaseExtensionName()) ? - "." + getDatabaseExtensionName() : ""); + return getDatabaseName() + getDatabaseExtensionName(); } /** @@ -304,13 +308,15 @@ public String getDatabaseFileName() { */ @NonNull public String getDatabaseExtensionName() { - return "db"; + return databaseConfig != null ? databaseConfig.getDatabaseExtensionName() : ".db"; } /** * @return True if the database will reside in memory. */ - public abstract boolean isInMemory(); + public boolean isInMemory() { + return databaseConfig != null && databaseConfig.isInMemory(); + } /** * @return The version of the database currently. @@ -338,46 +344,64 @@ public String getDatabaseExtensionName() { @NonNull public abstract Class getAssociatedDatabaseClassFile(); + + /** + * @deprecated use {@link #reset()} + */ + @Deprecated + public void reset(Context context) { + reset(databaseConfig); + } + + /** + * Performs a full deletion of this database. Reopens the {@link FlowSQLiteOpenHelper} as well. + * Reapplies the {@link DatabaseConfig} if we have one. + */ + public void reset() { + reset(databaseConfig); + } + /** * Performs a full deletion of this database. Reopens the {@link FlowSQLiteOpenHelper} as well. * - * @param context Where the database resides + * @param databaseConfig sets a new {@link DatabaseConfig} on this class. */ - public void reset(@NonNull Context context) { + public void reset(@Nullable DatabaseConfig databaseConfig) { if (!isResetting) { - isResetting = true; - getTransactionManager().stopQueue(); - getHelper().closeDB(); - for (ModelAdapter modelAdapter : modelAdapters.values()) { - modelAdapter.closeInsertStatement(); - modelAdapter.closeCompiledStatement(); - } - context.deleteDatabase(getDatabaseFileName()); - - // recreate queue after interrupting it. - if (databaseConfig == null || databaseConfig.transactionManagerCreator() == null) { - transactionManager = new DefaultTransactionManager(this); - } else { - transactionManager = databaseConfig.transactionManagerCreator().createManager(this); - } - openHelper = null; - isResetting = false; + destroy(); + // reapply configuration before opening it. + applyDatabaseConfig(databaseConfig); getHelper().getDatabase(); } } - public void destroy(@NonNull Context context) { + /** + * Deletes the underlying database and destroys it. + */ + public void destroy() { if (!isResetting) { isResetting = true; - getTransactionManager().stopQueue(); - getHelper().closeDB(); - context.deleteDatabase(getDatabaseFileName()); - + close(); + FlowManager.getContext().deleteDatabase(getDatabaseFileName()); openHelper = null; isResetting = false; } } + /** + * Closes the DB and stops the {@link BaseTransactionManager} + */ + public void close() { + getTransactionManager().stopQueue(); + for (ModelAdapter modelAdapter : modelAdapters.values()) { + modelAdapter.closeInsertStatement(); + modelAdapter.closeCompiledStatement(); + modelAdapter.closeDeleteStatement(); + modelAdapter.closeUpdateStatement(); + } + getHelper().closeDB(); + } + /** * @return True if the database is ok. If backups are enabled, we restore from backup and will * override the return value if it replaces the main DB. diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/config/FlowConfig.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/config/FlowConfig.java index 15481471c..8a6136917 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/config/FlowConfig.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/config/FlowConfig.java @@ -15,6 +15,10 @@ */ public final class FlowConfig { + public static FlowConfig.Builder builder(Context context) { + return new FlowConfig.Builder(context); + } + private final Set> databaseHolders; private final Map, DatabaseConfig> databaseConfigMap; private final Context context; diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/config/FlowManager.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/config/FlowManager.java index 3acd7b6c4..1550bd911 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/config/FlowManager.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/config/FlowManager.java @@ -108,6 +108,25 @@ public static Class getTableClassForName(String databaseName, String tableNam return modelClass; } + /** + * @param databaseClass The class of the database. Will throw an exception if the database doesn't exist. + * @param tableName The name of the table in the DB. + * @return The associated table class for the specified name. + */ + public static Class getTableClassForName(Class databaseClass, String tableName) { + DatabaseDefinition databaseDefinition = getDatabase(databaseClass); + Class modelClass = databaseDefinition.getModelClassForName(tableName); + if (modelClass == null) { + modelClass = databaseDefinition.getModelClassForName(QueryBuilder.quote(tableName)); + if (modelClass == null) { + throw new IllegalArgumentException(String.format("The specified table %1s was not found. " + + "Did you forget to add the @Table annotation and point it to %1s?", + tableName, databaseClass)); + } + } + return modelClass; + } + /** * @param table The table to lookup the database for. * @return the corresponding {@link DatabaseDefinition} for the specified model @@ -134,6 +153,11 @@ public static DatabaseDefinition getDatabase(Class databaseClass) { return databaseDefinition; } + @NonNull + public static String getDatabaseName(Class database) { + return getDatabase(database).getDatabaseName(); + } + @NonNull public static DatabaseWrapper getWritableDatabaseForTable(Class table) { return getDatabaseForTable(table).getWritableDatabase(); @@ -215,7 +239,7 @@ protected static void loadDatabaseHolder(Class holderC public static void reset() { Set, DatabaseDefinition>> entrySet = globalDatabaseHolder.databaseClassLookupMap.entrySet(); for (Map.Entry, DatabaseDefinition> value : entrySet) { - value.getValue().reset(getContext()); + value.getValue().reset(); } globalDatabaseHolder.reset(); loadedModules.clear(); @@ -302,7 +326,7 @@ public static synchronized void destroy() { Set, DatabaseDefinition>> entrySet = globalDatabaseHolder.databaseClassLookupMap.entrySet(); for (Map.Entry, DatabaseDefinition> value : entrySet) { - value.getValue().destroy(getContext()); + value.getValue().destroy(); } config = null; diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/config/TableConfig.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/config/TableConfig.java index cc1d955a9..c01aefa7c 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/config/TableConfig.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/config/TableConfig.java @@ -16,6 +16,10 @@ */ public final class TableConfig { + public static TableConfig.Builder builder(Class tableClass) { + return new TableConfig.Builder<>(tableClass); + } + private final Class tableClass; private final ModelSaver modelSaver; private final SingleModelLoader singleModelLoader; diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/SqlUtils.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/SqlUtils.java index 8e894e1d7..b90777162 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/SqlUtils.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/SqlUtils.java @@ -220,6 +220,16 @@ public static long longForQuery(@NonNull DatabaseWrapper wrapper, } } + public static double doubleForQuery(@NonNull DatabaseWrapper wrapper, + @NonNull String query) { + DatabaseStatement statement = wrapper.compileStatement(query); + try { + return statement.simpleQueryForLong(); + } finally { + statement.close(); + } + } + /** * Converts a byte[] to a String hex representation for within wrapper queries. */ diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/language/BaseQueriable.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/language/BaseQueriable.java index 207884723..34668341d 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/language/BaseQueriable.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/language/BaseQueriable.java @@ -45,15 +45,7 @@ public Class getTable() { */ @Override public long count(@NonNull DatabaseWrapper databaseWrapper) { - try { - String query = getQuery(); - FlowLog.log(FlowLog.Level.V, "Executing query: " + query); - return SqlUtils.longForQuery(databaseWrapper, query); - } catch (SQLiteDoneException sde) { - // catch exception here, log it but return 0; - FlowLog.log(FlowLog.Level.W, sde); - } - return 0; + return longValue(databaseWrapper); } /** @@ -63,7 +55,25 @@ public long count(@NonNull DatabaseWrapper databaseWrapper) { */ @Override public long count() { - return count(FlowManager.getWritableDatabaseForTable(table)); + return longValue(); + } + + @Override + public long longValue() { + return longValue(FlowManager.getWritableDatabaseForTable(table)); + } + + @Override + public long longValue(DatabaseWrapper databaseWrapper) { + try { + String query = getQuery(); + FlowLog.log(FlowLog.Level.V, "Executing query: " + query); + return SqlUtils.longForQuery(databaseWrapper, query); + } catch (SQLiteDoneException sde) { + // catch exception here, log it but return 0; + FlowLog.log(FlowLog.Level.W, sde); + } + return 0; } @Override diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/language/BaseTransformable.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/language/BaseTransformable.java index 1e21b2996..ea768bf70 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/language/BaseTransformable.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/language/BaseTransformable.java @@ -38,26 +38,6 @@ public FlowCursor query(@NonNull DatabaseWrapper databaseWrapper) { return where().query(databaseWrapper); } - /** - * Executes a SQL statement that retrieves the count of results in the DB. - * - * @return The number of rows this query returns - */ - @Override - public long count() { - return where().count(); - } - - @Override - public long count(@NonNull DatabaseWrapper databaseWrapper) { - return where().count(databaseWrapper); - } - - @Override - public long executeUpdateDelete(@NonNull DatabaseWrapper databaseWrapper) { - return where().executeUpdateDelete(databaseWrapper); - } - @NonNull @Override public Where groupBy(NameAlias... nameAliases) { diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/language/property/TypeConvertedProperty.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/language/property/TypeConvertedProperty.java index 2d2255129..0fa7eca83 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/language/property/TypeConvertedProperty.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/language/property/TypeConvertedProperty.java @@ -72,4 +72,13 @@ public TypeConverter getTypeConverter(Class modelClass) { return databaseProperty; } + @NonNull + @Override + public Property withTable(@NonNull NameAlias tableNameAlias) { + NameAlias nameAlias = this.getNameAlias() + .newBuilder() + .withTable(tableNameAlias.getQuery()) + .build(); + return new TypeConvertedProperty<>(this.getTable(), nameAlias, this.convertToDB, this.getter); + } } diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/migration/IndexMigration.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/migration/IndexMigration.java index 4a97b6632..668a05152 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/migration/IndexMigration.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/migration/IndexMigration.java @@ -17,11 +17,6 @@ public abstract class IndexMigration extends BaseMigration { */ private Class onTable; - /** - * The name of this index - */ - private String name; - /** * The underlying index object. */ @@ -49,7 +44,6 @@ public final void migrate(@NonNull DatabaseWrapper database) { @Override public void onPostMigrate() { onTable = null; - name = null; index = null; } @@ -82,7 +76,7 @@ public IndexMigration unique() { @NonNull public Index getIndex() { if (index == null) { - index = new Index(name).on(onTable); + index = new Index(getName()).on(onTable); } return index; } @@ -94,5 +88,4 @@ public Index getIndex() { public String getIndexQuery() { return getIndex().getQuery(); } - } diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/queriable/Queriable.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/queriable/Queriable.java index ba2003fa8..e6d70f665 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/queriable/Queriable.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/queriable/Queriable.java @@ -50,14 +50,28 @@ public interface Queriable extends Query { /** * @return the count of the results of the query. + * @deprecated use {@link #longValue()} */ + @Deprecated long count(); + /** + * @return the long value of the results of query. + */ + long longValue(); + + /** + * @return the long value of the results of query. + */ + long longValue(DatabaseWrapper databaseWrapper); + /** * Allows you to pass in a {@link DatabaseWrapper} manually. * * @return the count of the results of the query. + * @deprecated use {@link #longValue(DatabaseWrapper)} */ + @Deprecated long count(@NonNull DatabaseWrapper databaseWrapper); /** diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/saveable/AutoIncrementModelSaver.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/saveable/AutoIncrementModelSaver.java new file mode 100644 index 000000000..8c73aa7b4 --- /dev/null +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/saveable/AutoIncrementModelSaver.java @@ -0,0 +1,61 @@ +package com.raizlabs.android.dbflow.sql.saveable; + +import android.support.annotation.NonNull; + +import com.raizlabs.android.dbflow.runtime.NotifyDistributor; +import com.raizlabs.android.dbflow.structure.BaseModel; +import com.raizlabs.android.dbflow.structure.database.DatabaseStatement; +import com.raizlabs.android.dbflow.structure.database.DatabaseWrapper; + +/** + * Description: Used to properly handle autoincrementing fields. + */ +public class AutoIncrementModelSaver extends ModelSaver { + + @Override + public synchronized long insert(@NonNull TModel model) { + return insert(model, getWritableDatabase()); + } + + @Override + public synchronized long insert(@NonNull TModel model, @NonNull DatabaseWrapper wrapper) { + final boolean hasAutoIncrement = getModelAdapter().hasAutoIncrement(model); + DatabaseStatement insertStatement = hasAutoIncrement + ? getModelAdapter().getCompiledStatement(wrapper) + : getModelAdapter().getInsertStatement(wrapper); + long id; + try { + if (hasAutoIncrement) { + getModelAdapter().bindToStatement(insertStatement, model); + } else { + getModelAdapter().bindToInsertStatement(insertStatement, model); + } + id = insertStatement.executeInsert(); + if (id > INSERT_FAILED) { + getModelAdapter().updateAutoIncrement(model, id); + NotifyDistributor.get().notifyModelChanged(model, getModelAdapter(), BaseModel.Action.INSERT); + } + } finally { + // since we generate an insert every time, we can safely close the statement here. + insertStatement.close(); + } + return id; + } + + @Override + public synchronized long insert(@NonNull TModel model, + @NonNull DatabaseStatement insertStatement, + @NonNull DatabaseWrapper wrapper) { + if (getModelAdapter().hasAutoIncrement(model)) { + getModelAdapter().bindToStatement(insertStatement, model); + } else { + getModelAdapter().bindToInsertStatement(insertStatement, model); + } + long id = insertStatement.executeInsert(); + if (id > INSERT_FAILED) { + getModelAdapter().updateAutoIncrement(model, id); + NotifyDistributor.get().notifyModelChanged(model, getModelAdapter(), BaseModel.Action.INSERT); + } + return id; + } +} diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/saveable/ModelSaver.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/saveable/ModelSaver.java index d91d4d708..ac35a8319 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/saveable/ModelSaver.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/sql/saveable/ModelSaver.java @@ -17,7 +17,7 @@ */ public class ModelSaver { - private static final int INSERT_FAILED = -1; + public static final int INSERT_FAILED = -1; private ModelAdapter modelAdapter; diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/ModelAdapter.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/ModelAdapter.java index 14133f452..3b437769a 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/ModelAdapter.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/ModelAdapter.java @@ -29,7 +29,7 @@ */ @SuppressWarnings("NullableProblems") public abstract class ModelAdapter extends InstanceAdapter - implements InternalAdapter { + implements InternalAdapter { private DatabaseStatement insertStatement; private DatabaseStatement compiledStatement; @@ -93,6 +93,22 @@ public void closeInsertStatement() { insertStatement = null; } + public void closeUpdateStatement() { + if (updateStatement == null) { + return; + } + updateStatement.close(); + updateStatement = null; + } + + public void closeDeleteStatement() { + if (deleteStatement == null) { + return; + } + deleteStatement.close(); + deleteStatement = null; + } + /** * @param databaseWrapper The database used to do an insert statement. * @return a new compiled {@link DatabaseStatement} representing insert. Not cached, always generated. @@ -279,9 +295,9 @@ public void updateAutoIncrement(@NonNull TModel model, @NonNull Number id) { @Override public Number getAutoIncrementingId(@NonNull TModel model) { throw new InvalidDBConfiguration( - String.format("This method may have been called in error. The model class %1s must contain" + - "a single primary key (if used in a ModelCache, this method may be called)", - getModelClass())); + String.format("This method may have been called in error. The model class %1s must contain" + + "a single primary key (if used in a ModelCache, this method may be called)", + getModelClass())); } /** @@ -291,9 +307,13 @@ public Number getAutoIncrementingId(@NonNull TModel model) { @NonNull public String getAutoIncrementingColumnName() { throw new InvalidDBConfiguration( - String.format("This method may have been called in error. The model class %1s must contain " + - "an autoincrementing or single int/long primary key (if used in a ModelCache, this method may be called)", - getModelClass())); + String.format("This method may have been called in error. The model class %1s must contain " + + "an autoincrementing or single int/long primary key (if used in a ModelCache, this method may be called)", + getModelClass())); + } + + public boolean hasAutoIncrement(TModel model) { + return getAutoIncrementingId(model).longValue() > 0; } /** @@ -406,7 +426,7 @@ public Object getCachingId(@NonNull TModel model) { public ModelSaver getModelSaver() { if (modelSaver == null) { - modelSaver = new ModelSaver<>(); + modelSaver = createSingleModelSaver(); modelSaver.setModelAdapter(this); } return modelSaver; @@ -419,6 +439,10 @@ public ListModelSaver getListModelSaver() { return listModelSaver; } + protected ModelSaver createSingleModelSaver() { + return new ModelSaver<>(); + } + protected ListModelSaver createListModelSaver() { return new ListModelSaver<>(getModelSaver()); } @@ -456,8 +480,8 @@ public int getCacheSize() { public IMultiKeyCacheConverter getCacheConverter() { throw new InvalidDBConfiguration("For multiple primary keys, a public static IMultiKeyCacheConverter field must" + - "be marked with @MultiCacheField in the corresponding model class. The resulting key" + - "must be a unique combination of the multiple keys, otherwise inconsistencies may occur."); + "be marked with @MultiCacheField in the corresponding model class. The resulting key" + + "must be a unique combination of the multiple keys, otherwise inconsistencies may occur."); } public ModelCache createModelCache() { @@ -513,18 +537,26 @@ public ConflictAction getInsertOnConflictAction() { return ConflictAction.ABORT; } + /** + * @return When false, this table gets generated and associated with database, however it will not immediately + * get created upon startup. This is useful for keeping around legacy tables for migrations. + */ + public boolean createWithDatabase() { + return true; + } + private void throwCachingError() { throw new InvalidDBConfiguration( - String.format("This method may have been called in error. The model class %1s must contain" + - "an auto-incrementing or at least one primary key (if used in a ModelCache, this method may be called)", - getModelClass())); + String.format("This method may have been called in error. The model class %1s must contain" + + "an auto-incrementing or at least one primary key (if used in a ModelCache, this method may be called)", + getModelClass())); } private void throwSingleCachingError() { throw new InvalidDBConfiguration( - String.format("This method may have been called in error. The model class %1s must contain" + - "an auto-incrementing or one primary key (if used in a ModelCache, this method may be called)", - getModelClass())); + String.format("This method may have been called in error. The model class %1s must contain" + + "an auto-incrementing or one primary key (if used in a ModelCache, this method may be called)", + getModelClass())); } } diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/database/BaseDatabaseHelper.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/database/BaseDatabaseHelper.java index 21839602c..807056552 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/database/BaseDatabaseHelper.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/database/BaseDatabaseHelper.java @@ -45,14 +45,16 @@ public DatabaseDefinition getDatabaseDefinition() { public void onCreate(@NonNull DatabaseWrapper db) { checkForeignKeySupport(db); - executeCreations(db); + executeTableCreations(db); executeMigrations(db, -1, db.getVersion()); + executeViewCreations(db); } public void onUpgrade(@NonNull DatabaseWrapper db, int oldVersion, int newVersion) { checkForeignKeySupport(db); - executeCreations(db); + executeTableCreations(db); executeMigrations(db, oldVersion, newVersion); + executeViewCreations(db); } public void onOpen(@NonNull DatabaseWrapper db) { @@ -73,22 +75,32 @@ protected void checkForeignKeySupport(@NonNull DatabaseWrapper database) { } } - /** - * This method executes CREATE TABLE statements as well as CREATE VIEW on the database passed. - */ - protected void executeCreations(@NonNull final DatabaseWrapper database) { + protected void executeTableCreations(@NonNull final DatabaseWrapper database){ try { database.beginTransaction(); List modelAdapters = databaseDefinition.getModelAdapters(); for (ModelAdapter modelAdapter : modelAdapters) { - try { - database.execSQL(modelAdapter.getCreationQuery()); - } catch (SQLiteException e) { - FlowLog.logError(e); + if (modelAdapter.createWithDatabase()) { + try { + database.execSQL(modelAdapter.getCreationQuery()); + } catch (SQLiteException e) { + FlowLog.logError(e); + } } } + database.setTransactionSuccessful(); + } finally { + database.endTransaction(); + } + } - // create our model views + /** + * This method executes CREATE TABLE statements as well as CREATE VIEW on the database passed. + */ + protected void executeViewCreations(@NonNull final DatabaseWrapper database){ + + try { + database.beginTransaction(); List modelViews = databaseDefinition.getModelViewAdapters(); for (ModelViewAdapter modelView : modelViews) { QueryBuilder queryBuilder = new QueryBuilder() @@ -106,7 +118,6 @@ protected void executeCreations(@NonNull final DatabaseWrapper database) { } finally { database.endTransaction(); } - } protected void executeMigrations(@NonNull final DatabaseWrapper db, diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/database/FlowSQLiteOpenHelper.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/database/FlowSQLiteOpenHelper.java index 99ef042d2..922fff94c 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/database/FlowSQLiteOpenHelper.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/database/FlowSQLiteOpenHelper.java @@ -17,10 +17,10 @@ public class FlowSQLiteOpenHelper extends SQLiteOpenHelper implements OpenHelper private DatabaseHelperDelegate databaseHelperDelegate; private AndroidDatabase androidDatabase; + public FlowSQLiteOpenHelper(@NonNull DatabaseDefinition databaseDefinition, @NonNull DatabaseHelperListener listener) { - super(FlowManager.getContext(), - databaseDefinition.isInMemory() ? null : databaseDefinition.getDatabaseFileName(), + super(FlowManager.getContext(), databaseDefinition.isInMemory() ? null : databaseDefinition.getDatabaseFileName(), null, databaseDefinition.getDatabaseVersion()); OpenHelper backupHelper = null; diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/database/transaction/QueryTransaction.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/database/transaction/QueryTransaction.java index 23eefaaef..f96b7e562 100644 --- a/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/database/transaction/QueryTransaction.java +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/database/transaction/QueryTransaction.java @@ -27,7 +27,7 @@ public interface QueryResultCallback { * @param transaction The transaction that ran. * @param tResult The result of the query. Use this object to get data that you need. */ - void onQueryResult(QueryTransaction transaction, + void onQueryResult(@NonNull QueryTransaction transaction, @NonNull CursorResult tResult); } diff --git a/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/database/transaction/TransactionWrapper.java b/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/database/transaction/TransactionWrapper.java new file mode 100644 index 000000000..4ef0b1bc7 --- /dev/null +++ b/dbflow/src/main/java/com/raizlabs/android/dbflow/structure/database/transaction/TransactionWrapper.java @@ -0,0 +1,31 @@ +package com.raizlabs.android.dbflow.structure.database.transaction; + +import com.raizlabs.android.dbflow.structure.database.DatabaseWrapper; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +/** + * Description: Wraps multiple transactions together. + */ +public class TransactionWrapper implements ITransaction { + + private final List transactions = new ArrayList<>(); + + public TransactionWrapper(ITransaction... transactions) { + this.transactions.addAll(Arrays.asList(transactions)); + } + + public TransactionWrapper(Collection transactions) { + this.transactions.addAll(transactions); + } + + @Override + public void execute(DatabaseWrapper databaseWrapper) { + for (ITransaction transaction : transactions) { + transaction.execute(databaseWrapper); + } + } +} diff --git a/gradle.properties b/gradle.properties index b728ea80e..d3c83148e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,8 +8,8 @@ bt_licenseUrl=http://opensource.org/licenses/MIT bt_repo=Libraries dbflow_project_prefix=: kotlin.incremental=false -dbflow_build_tools_version=25.0.1 +dbflow_build_tools_version=26.0.0 dbflow_min_sdk=4 dbflow_min_sdk_rx=15 -dbflow_target_sdk=25 \ No newline at end of file +dbflow_target_sdk=26 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c52196d7e..4227ae5c7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-milestone-1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip diff --git a/usage2 b/usage2 index 99495e356..76b48d64b 160000 --- a/usage2 +++ b/usage2 @@ -1 +1 @@ -Subproject commit 99495e3566e38785870f6c580caa3915709f8d1f +Subproject commit 76b48d64bf3f1e5256a7003d2230a29e2fb07c7a