ProcessorErrors.kt revision 3c592c4ccbc6052b11443b0fa575052c08fefa55
119b41105359a52aeb80070dec40247241231f05dYigit Boyar/*
219b41105359a52aeb80070dec40247241231f05dYigit Boyar * Copyright (C) 2016 The Android Open Source Project
319b41105359a52aeb80070dec40247241231f05dYigit Boyar *
419b41105359a52aeb80070dec40247241231f05dYigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
519b41105359a52aeb80070dec40247241231f05dYigit Boyar * you may not use this file except in compliance with the License.
619b41105359a52aeb80070dec40247241231f05dYigit Boyar * You may obtain a copy of the License at
719b41105359a52aeb80070dec40247241231f05dYigit Boyar *
819b41105359a52aeb80070dec40247241231f05dYigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
919b41105359a52aeb80070dec40247241231f05dYigit Boyar *
1019b41105359a52aeb80070dec40247241231f05dYigit Boyar * Unless required by applicable law or agreed to in writing, software
1119b41105359a52aeb80070dec40247241231f05dYigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
1219b41105359a52aeb80070dec40247241231f05dYigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1319b41105359a52aeb80070dec40247241231f05dYigit Boyar * See the License for the specific language governing permissions and
1419b41105359a52aeb80070dec40247241231f05dYigit Boyar * limitations under the License.
1519b41105359a52aeb80070dec40247241231f05dYigit Boyar */
1619b41105359a52aeb80070dec40247241231f05dYigit Boyar
1719b41105359a52aeb80070dec40247241231f05dYigit Boyarpackage com.android.support.room.processor
1819b41105359a52aeb80070dec40247241231f05dYigit Boyar
19958df7dd95c2cecf93cacef6998a4d7e8d39b7efYigit Boyarimport com.android.support.room.Delete
204f0db7db556b473393dfc31bba5ea67def574877Yigit Boyarimport com.android.support.room.Insert
2119b41105359a52aeb80070dec40247241231f05dYigit Boyarimport com.android.support.room.Query
2274b28faea4bcc4b7fab113a61a066d22dfae7258Yigit Boyarimport com.android.support.room.Update
23291985054e698c918df1c735d1042b63b9e97219Yigit Boyarimport com.android.support.room.ext.RoomTypeNames
24092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyarimport com.android.support.room.parser.SQLTypeAffinity
25275e7088223c097c1a2df718455bede42bc9efedYigit Boyarimport com.android.support.room.vo.CustomTypeConverter
261600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyarimport com.android.support.room.vo.Field
2788865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyarimport com.squareup.javapoet.TypeName
28875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyarimport javax.lang.model.type.TypeMirror
2919b41105359a52aeb80070dec40247241231f05dYigit Boyar
3019b41105359a52aeb80070dec40247241231f05dYigit Boyarobject ProcessorErrors {
312c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar    private fun String.trim(): String {
322c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar        return this.trimIndent().replace(System.lineSeparator(), " ")
332c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar    }
3419b41105359a52aeb80070dec40247241231f05dYigit Boyar    val MISSING_QUERY_ANNOTATION = "Query methods must be annotated with ${Query::class.java}"
354f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar    val MISSING_INSERT_ANNOTATION = "Insertion methods must be annotated with ${Insert::class.java}"
36958df7dd95c2cecf93cacef6998a4d7e8d39b7efYigit Boyar    val MISSING_DELETE_ANNOTATION = "Deletion methods must be annotated with ${Delete::class.java}"
3774b28faea4bcc4b7fab113a61a066d22dfae7258Yigit Boyar    val MISSING_UPDATE_ANNOTATION = "Update methods must be annotated with ${Update::class.java}"
38333b4b5e49c48adf7fb928d445b6f7f276b54a02Yigit Boyar    val INVALID_ON_CONFLICT_VALUE = "On conflict value must be one of @OnConflictStrategy values."
394f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar    val INVALID_INSERTION_METHOD_RETURN_TYPE = "Methods annotated with @Insert can return either" +
404f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar            " void, long, long[] or List<Long>."
41f5f2cf6b9ed63915448e81551e4b7bb72a26030eYigit Boyar
42f5f2cf6b9ed63915448e81551e4b7bb72a26030eYigit Boyar    fun insertionMethodReturnTypeMismatch(definedReturn : TypeName,
43f5f2cf6b9ed63915448e81551e4b7bb72a26030eYigit Boyar                                          expectedReturnTypes : List<TypeName>) : String {
44f5f2cf6b9ed63915448e81551e4b7bb72a26030eYigit Boyar        return "Method returns $definedReturn but it should return one of the following: `" +
45f5f2cf6b9ed63915448e81551e4b7bb72a26030eYigit Boyar                expectedReturnTypes.joinToString(", ") + "`. If you want to return the list of" +
46f5f2cf6b9ed63915448e81551e4b7bb72a26030eYigit Boyar                " row ids from the query, your insertion method can receive only 1 parameter."
47f5f2cf6b9ed63915448e81551e4b7bb72a26030eYigit Boyar    }
48f5f2cf6b9ed63915448e81551e4b7bb72a26030eYigit Boyar
494f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar    val ABSTRACT_METHOD_IN_DAO_MISSING_ANY_ANNOTATION = "Abstract method in DAO must be annotated" +
504f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar            " with ${Query::class.java} AND ${Insert::class.java}"
51958df7dd95c2cecf93cacef6998a4d7e8d39b7efYigit Boyar    val CANNOT_USE_MORE_THAN_ONE_DAO_METHOD_ANNOTATION = "A DAO method can be annotated with only" +
52958df7dd95c2cecf93cacef6998a4d7e8d39b7efYigit Boyar            " one of the following:" + DaoProcessor.PROCESSED_ANNOTATIONS.joinToString(",") {
53958df7dd95c2cecf93cacef6998a4d7e8d39b7efYigit Boyar        it.java.simpleName
54958df7dd95c2cecf93cacef6998a4d7e8d39b7efYigit Boyar    }
5519b41105359a52aeb80070dec40247241231f05dYigit Boyar    val CANNOT_RESOLVE_RETURN_TYPE = "Cannot resolve return type for %s"
564f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar    val CANNOT_USE_UNBOUND_GENERICS_IN_QUERY_METHODS = "Cannot use unbound generics in query" +
574f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar            " methods. It must be bound to a type through base Dao class."
584f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar    val CANNOT_USE_UNBOUND_GENERICS_IN_INSERTION_METHODS = "Cannot use unbound generics in" +
594f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar            " insertion methods. It must be bound to a type through base Dao class."
60de33ce4068e2678c03fa6fd62f4770be89f79adcYigit Boyar    val CANNOT_USE_UNBOUND_GENERICS_IN_ENTITY_FIELDS = "Cannot use unbound fields in entities."
610f77cff2005ccc6263b9902b3ea56fe01161ba51Yigit Boyar    val CANNOT_USE_UNBOUND_GENERICS_IN_DAO_CLASSES = "Cannot use unbound generics in Dao classes." +
620f77cff2005ccc6263b9902b3ea56fe01161ba51Yigit Boyar            " If you are trying to create a base DAO, create a normal class, extend it with type" +
630f77cff2005ccc6263b9902b3ea56fe01161ba51Yigit Boyar            " params then mark the subclass with @Dao."
641600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar    val CANNOT_FIND_GETTER_FOR_FIELD = "Cannot find getter for field."
651600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar    val CANNOT_FIND_SETTER_FOR_FIELD = "Cannot find setter for field."
66e6325fbeaa2e6759496ea2ca9a4d3d958df690d7Yigit Boyar    val MISSING_PRIMARY_KEY = "An entity must have at least 1 field annotated with @PrimaryKey"
672c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar    val AUTO_INCREMENTED_PRIMARY_KEY_IS_NOT_INT = "If a primary key is annotated with" +
682c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar            " autoGenerate, its type must be int, Integer, long or Long."
692c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar    val AUTO_INCREMENT_DECOMPOSED_HAS_MULTIPLE_FIELDS = "When @PrimaryKey annotation is used on a" +
702c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar            " field annotated with @Decompose, the decomposed class should have only 1 field."
712c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar
722c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar    fun multiplePrimaryKeyAnnotations(primaryKeys: List<String>): String {
732c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar        return """
742c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                You cannot have multiple primary keys defined in an Entity. If you
752c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                want to declare a composite primary key, you should use @Entity#primaryKeys and
762c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                not use @PrimaryKey. Defined Primary Keys:
772c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                ${primaryKeys.joinToString(", ")}""".trim()
782c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar    }
792c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar
802c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar    fun primaryKeyColumnDoesNotExist(columnName: String, allColumns: List<String>): String {
812c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar        return "$columnName referenced in the primary key does not exists in the Entity." +
822c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                " Available column names:${allColumns.joinToString(", ")}"
832c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar    }
842c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar
850f77cff2005ccc6263b9902b3ea56fe01161ba51Yigit Boyar    val DAO_MUST_BE_AN_ABSTRACT_CLASS_OR_AN_INTERFACE = "Dao class must be an abstract class or" +
860f77cff2005ccc6263b9902b3ea56fe01161ba51Yigit Boyar            " an interface"
878bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar    val DATABASE_MUST_BE_ANNOTATED_WITH_DATABASE = "Database must be annotated with @Database"
888bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar    val DAO_MUST_BE_ANNOTATED_WITH_DAO = "Dao class must be annotated with @Dao"
898bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar    val ENTITY_MUST_BE_ANNOTATED_WITH_ENTITY = "Entity class must be annotated with @Entity"
908bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar    val DATABASE_ANNOTATION_MUST_HAVE_LIST_OF_ENTITIES = "@Database annotation must specify list" +
918bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar            " of entities"
920fc66ddc60bdc71d5466bb1db1a218e5a3d9c1fcYigit Boyar    val COLUMN_NAME_CANNOT_BE_EMPTY = "Column name cannot be blank. If you don't want to set it" +
93275e7088223c097c1a2df718455bede42bc9efedYigit Boyar            ", just remove the @ColumnInfo annotation or use @ColumnInfo.INHERIT_FIELD_NAME."
940fc66ddc60bdc71d5466bb1db1a218e5a3d9c1fcYigit Boyar
950fc66ddc60bdc71d5466bb1db1a218e5a3d9c1fcYigit Boyar    val ENTITY_TABLE_NAME_CANNOT_BE_EMPTY = "Entity table name cannot be blank. If you don't want" +
960fc66ddc60bdc71d5466bb1db1a218e5a3d9c1fcYigit Boyar            " to set it, just remove the tableName property."
970f77cff2005ccc6263b9902b3ea56fe01161ba51Yigit Boyar
98275e7088223c097c1a2df718455bede42bc9efedYigit Boyar    val CANNOT_BIND_QUERY_PARAMETER_INTO_STMT = "Query method parameters should either be a" +
99275e7088223c097c1a2df718455bede42bc9efedYigit Boyar            " type that can be converted into a database column or a List / Array that contains" +
100275e7088223c097c1a2df718455bede42bc9efedYigit Boyar            " such type. You can consider adding a Type Adapter for this."
101250a3e6dc5d50c533575b7d276730b89eecc7c19Yigit Boyar
1024f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar    val QUERY_PARAMETERS_CANNOT_START_WITH_UNDERSCORE = "Query/Insert method parameters cannot " +
1034f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar            "start with underscore (_)."
1048e543c445cb5559e579f54c1ac00d0ca83ec3fbbYigit Boyar
105efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar    val CANNOT_FIND_QUERY_RESULT_ADAPTER = "Not sure how to convert a Cursor to this method's " +
106efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar            "return type"
107efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar
1084f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar    val INSERTION_DOES_NOT_HAVE_ANY_PARAMETERS_TO_INSERT = "Method annotated with" +
1094f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar            " @Insert but does not have any parameters to insert."
1104f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar
1114f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar    val INSERTION_METHOD_PARAMETERS_MUST_HAVE_THE_SAME_ENTITY_TYPE = "Parameter types in " +
1124f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar            "insertion methods must be the same type. If you want to insert entities from " +
1134f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar            "different types atomically, use a transaction."
1144f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar
11574b28faea4bcc4b7fab113a61a066d22dfae7258Yigit Boyar    val DELETION_MISSING_PARAMS = "Method annotated with" +
116958df7dd95c2cecf93cacef6998a4d7e8d39b7efYigit Boyar            " @Delete but does not have any parameters to delete."
117958df7dd95c2cecf93cacef6998a4d7e8d39b7efYigit Boyar
11874b28faea4bcc4b7fab113a61a066d22dfae7258Yigit Boyar    val DELETION_MULTIPLE_ENTITY_TYPES = "Parameter types in " +
119958df7dd95c2cecf93cacef6998a4d7e8d39b7efYigit Boyar            "deletion methods must be the same type. If you want to delete entities from " +
120958df7dd95c2cecf93cacef6998a4d7e8d39b7efYigit Boyar            "different types atomically, use a transaction."
121958df7dd95c2cecf93cacef6998a4d7e8d39b7efYigit Boyar
12274b28faea4bcc4b7fab113a61a066d22dfae7258Yigit Boyar    val UPDATE_MISSING_PARAMS = "Method annotated with" +
12374b28faea4bcc4b7fab113a61a066d22dfae7258Yigit Boyar            " @Update but does not have any parameters to update."
12474b28faea4bcc4b7fab113a61a066d22dfae7258Yigit Boyar
12574b28faea4bcc4b7fab113a61a066d22dfae7258Yigit Boyar    val UPDATE_MULTIPLE_ENTITY_TYPES = "Parameter types in " +
12674b28faea4bcc4b7fab113a61a066d22dfae7258Yigit Boyar            "update methods must be the same type. If you want to update entities from " +
12774b28faea4bcc4b7fab113a61a066d22dfae7258Yigit Boyar            "different types atomically, use a transaction."
12874b28faea4bcc4b7fab113a61a066d22dfae7258Yigit Boyar
129958df7dd95c2cecf93cacef6998a4d7e8d39b7efYigit Boyar    val CANNOT_FIND_ENTITY_FOR_SHORTCUT_QUERY_PARAMETER = "Type of the parameter must be a class " +
130958df7dd95c2cecf93cacef6998a4d7e8d39b7efYigit Boyar            "annotated with @Entity or a collection/array of it."
1314f0db7db556b473393dfc31bba5ea67def574877Yigit Boyar
132291985054e698c918df1c735d1042b63b9e97219Yigit Boyar    val DB_MUST_EXTEND_ROOM_DB = "Classes annotated with @Database should extend " +
133291985054e698c918df1c735d1042b63b9e97219Yigit Boyar            RoomTypeNames.ROOM_DB
134291985054e698c918df1c735d1042b63b9e97219Yigit Boyar
135846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar    val LIVE_DATA_QUERY_WITHOUT_SELECT = "LiveData return type can only be used with SELECT" +
136846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar            " queries."
137846dfcf52e22de6d912f8ece05ff939c2c9bd154Yigit Boyar
138250a3e6dc5d50c533575b7d276730b89eecc7c19Yigit Boyar    private val TOO_MANY_MATCHING_GETTERS = "Ambiguous getter for %s. All of the following " +
139250a3e6dc5d50c533575b7d276730b89eecc7c19Yigit Boyar            "match: %s. You can @Ignore the ones that you don't want to match."
140efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar
141efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar    fun tooManyMatchingGetters(field: Field, methodNames: List<String>): String {
1421600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar        return TOO_MANY_MATCHING_GETTERS.format(field, methodNames.joinToString(", "))
1431600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar    }
1441600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar
145250a3e6dc5d50c533575b7d276730b89eecc7c19Yigit Boyar    private val TOO_MANY_MATCHING_SETTERS = "Ambiguous setter for %s. All of the following " +
146250a3e6dc5d50c533575b7d276730b89eecc7c19Yigit Boyar            "match: %s. You can @Ignore the ones that you don't want to match."
147efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar
148efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar    fun tooManyMatchingSetter(field: Field, methodNames: List<String>): String {
1491600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar        return TOO_MANY_MATCHING_SETTERS.format(field, methodNames.joinToString(", "))
1501600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar    }
151250a3e6dc5d50c533575b7d276730b89eecc7c19Yigit Boyar
152275e7088223c097c1a2df718455bede42bc9efedYigit Boyar    val CANNOT_FIND_COLUMN_TYPE_ADAPTER = "Cannot figure out how to save this field into" +
153275e7088223c097c1a2df718455bede42bc9efedYigit Boyar            " database. You can consider adding a type converter for it."
154275e7088223c097c1a2df718455bede42bc9efedYigit Boyar
155275e7088223c097c1a2df718455bede42bc9efedYigit Boyar    val CANNOT_FIND_STMT_BINDER = "Cannot figure out how to bind this field into a statement."
156275e7088223c097c1a2df718455bede42bc9efedYigit Boyar
157275e7088223c097c1a2df718455bede42bc9efedYigit Boyar    val CANNOT_FIND_CURSOR_READER = "Cannot figure out how to read this field from a cursor."
158275e7088223c097c1a2df718455bede42bc9efedYigit Boyar
159250a3e6dc5d50c533575b7d276730b89eecc7c19Yigit Boyar    private val MISSING_PARAMETER_FOR_BIND = "Each bind variable in the query must have a" +
160250a3e6dc5d50c533575b7d276730b89eecc7c19Yigit Boyar            " matching method parameter. Cannot find method parameters for %s."
161efaf86afac3163868eda7f91a1c04e3f6e6d7520Yigit Boyar
162250a3e6dc5d50c533575b7d276730b89eecc7c19Yigit Boyar    fun missingParameterForBindVariable(bindVarName: List<String>): String {
163250a3e6dc5d50c533575b7d276730b89eecc7c19Yigit Boyar        return MISSING_PARAMETER_FOR_BIND.format(bindVarName.joinToString(", "))
164250a3e6dc5d50c533575b7d276730b89eecc7c19Yigit Boyar    }
165250a3e6dc5d50c533575b7d276730b89eecc7c19Yigit Boyar
166250a3e6dc5d50c533575b7d276730b89eecc7c19Yigit Boyar    private val UNUSED_QUERY_METHOD_PARAMETER = "Unused parameter%s: %s"
167250a3e6dc5d50c533575b7d276730b89eecc7c19Yigit Boyar    fun unusedQueryMethodParameter(unusedParams: List<String>): String {
168250a3e6dc5d50c533575b7d276730b89eecc7c19Yigit Boyar        return UNUSED_QUERY_METHOD_PARAMETER.format(
169250a3e6dc5d50c533575b7d276730b89eecc7c19Yigit Boyar                if (unusedParams.size > 1) "s" else "",
170250a3e6dc5d50c533575b7d276730b89eecc7c19Yigit Boyar                unusedParams.joinToString(","))
171250a3e6dc5d50c533575b7d276730b89eecc7c19Yigit Boyar    }
172af2292b2f53204a3004f53201f51908d70d8090eYigit Boyar
173af2292b2f53204a3004f53201f51908d70d8090eYigit Boyar    private val DUPLICATE_TABLES = "Table name \"%s\" is used by multiple entities: %s"
17413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar    fun duplicateTableNames(tableName: String, entityNames: List<String>): String {
175af2292b2f53204a3004f53201f51908d70d8090eYigit Boyar        return DUPLICATE_TABLES.format(tableName, entityNames.joinToString(", "))
176af2292b2f53204a3004f53201f51908d70d8090eYigit Boyar    }
177958df7dd95c2cecf93cacef6998a4d7e8d39b7efYigit Boyar
178958df7dd95c2cecf93cacef6998a4d7e8d39b7efYigit Boyar    val DELETION_METHODS_MUST_RETURN_VOID_OR_INT = "Deletion methods must either return void or" +
179958df7dd95c2cecf93cacef6998a4d7e8d39b7efYigit Boyar            " return int (the number of deleted rows)."
18088865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar
18174b28faea4bcc4b7fab113a61a066d22dfae7258Yigit Boyar    val UPDATE_METHODS_MUST_RETURN_VOID_OR_INT = "Update methods must either return void or" +
18274b28faea4bcc4b7fab113a61a066d22dfae7258Yigit Boyar            " return int (the number of updated rows)."
18374b28faea4bcc4b7fab113a61a066d22dfae7258Yigit Boyar
18488865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar    val DAO_METHOD_CONFLICTS_WITH_OTHERS = "Dao method has conflicts."
18588865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar
18613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar    fun duplicateDao(dao: TypeName, methodNames: List<String>): String {
18788865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar        return """
188275e7088223c097c1a2df718455bede42bc9efedYigit Boyar                All of these functions [${methodNames.joinToString(", ")}] return the same DAO
189275e7088223c097c1a2df718455bede42bc9efedYigit Boyar                class [$dao].
19013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                A database can use a DAO only once so you should remove ${methodNames.size - 1} of
19113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                these conflicting DAO methods. If you are implementing any of these to fulfill an
19213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                interface, don't make it abstract, instead, implement the code that calls the
19313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                other one.
1942c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                """.trim()
19513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar    }
19613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar
19713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar    fun cursorPojoMismatch(pojoTypeName: TypeName,
19813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                           unusedColumns: List<String>, allColumns: List<String>,
19913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                           unusedFields: List<Field>, allFields: List<Field>): String {
2002c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar        val unusedColumnsWarning = if (unusedColumns.isNotEmpty()) {
2012c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar            """
202275e7088223c097c1a2df718455bede42bc9efedYigit Boyar                The query returns some columns [${unusedColumns.joinToString(", ")}] which are not
203275e7088223c097c1a2df718455bede42bc9efedYigit Boyar                use by $pojoTypeName. You can use @ColumnInfo annotation on the fields to specify
20413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                the mapping.
2052c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar            """.trim()
20613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        } else {
20713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar            ""
20813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        }
2092c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar        val unusedFieldsWarning = if (unusedFields.isNotEmpty()) {
2102c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar            """
21113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                $pojoTypeName has some fields
212275e7088223c097c1a2df718455bede42bc9efedYigit Boyar                [${unusedFields.joinToString(", ") { it.columnName }}] which are not returned by the
21313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                query. If they are not supposed to be read from the result, you can mark them with
21413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar                @Ignore annotation.
2152c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar            """.trim()
21613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        } else {
21713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar            ""
21813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        }
21913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar        return """
22013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar            $unusedColumnsWarning
22113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar            $unusedFieldsWarning
22213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar            You can suppress this warning by annotating the method with
22313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar            @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH).
22413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar            Columns returned by the query: ${allColumns.joinToString(", ")}.
22513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar            Fields in $pojoTypeName: ${allFields.joinToString(", ") { it.columnName }}.
2262c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar            """.trim()
22788865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar    }
22888865f77c35657a2bc545a718ca16a648fc8b62eYigit Boyar
229275e7088223c097c1a2df718455bede42bc9efedYigit Boyar    val TYPE_CONVERTER_UNBOUND_GENERIC = "Cannot use unbound generics in Type Converters."
230275e7088223c097c1a2df718455bede42bc9efedYigit Boyar    val TYPE_CONVERTER_BAD_RETURN_TYPE = "Invalid return type for a type converter."
231275e7088223c097c1a2df718455bede42bc9efedYigit Boyar    val TYPE_CONVERTER_MUST_RECEIVE_1_PARAM = "Type converters must receive 1 parameter."
232275e7088223c097c1a2df718455bede42bc9efedYigit Boyar    val TYPE_CONVERTER_EMPTY_CLASS = "Class is referenced as a converter but it does not have any" +
233275e7088223c097c1a2df718455bede42bc9efedYigit Boyar            " converter methods."
234275e7088223c097c1a2df718455bede42bc9efedYigit Boyar    val TYPE_CONVERTER_MISSING_NOARG_CONSTRUCTOR = "Classes that are used as TypeConverters must" +
235275e7088223c097c1a2df718455bede42bc9efedYigit Boyar            " have no-argument public constructors."
236275e7088223c097c1a2df718455bede42bc9efedYigit Boyar    val TYPE_CONVERTER_MUST_BE_PUBLIC = "Type converters must be public."
237275e7088223c097c1a2df718455bede42bc9efedYigit Boyar
2382c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar    fun duplicateTypeConverters(converters: List<CustomTypeConverter>): String {
239275e7088223c097c1a2df718455bede42bc9efedYigit Boyar        return "Multiple methods define the same conversion. Conflicts with these:" +
240275e7088223c097c1a2df718455bede42bc9efedYigit Boyar                " ${converters.joinToString(", ") { it.toString() }}"
241275e7088223c097c1a2df718455bede42bc9efedYigit Boyar    }
24296cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar
24396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar    // TODO must print field paths.
24496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar    val POJO_FIELD_HAS_DUPLICATE_COLUMN_NAME = "Field has non-unique column name."
24596cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar
2462c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar    fun pojoDuplicateFieldNames(columnName: String, fieldPaths: List<String>): String {
24796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        return "Multiple fields have the same columnName: $columnName." +
24896cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                " Field names: ${fieldPaths.joinToString(", ")}."
24996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar    }
25096cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar
2512c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar    fun decomposedPrimaryKeyIsDropped(entityQName: String, fieldName: String): String {
25296cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar        return "Primary key constraint on $fieldName is ignored when being merged into " +
25396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar                entityQName
25496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar    }
255dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar
256dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar    val INDEX_COLUMNS_CANNOT_BE_EMPTY = "List of columns in an index cannot be empty"
257dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar
2582c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar    fun indexColumnDoesNotExist(columnName: String, allColumns: List<String>): String {
259dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar        return "$columnName referenced in the index does not exists in the Entity." +
260dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar                " Available column names:${allColumns.joinToString(", ")}"
261dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar    }
262dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar
2632c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar    fun duplicateIndexInEntity(indexName: String): String {
264dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar        return "There are multiple indices with name $indexName. This happen if you've declared" +
265dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar                " the same index multiple times or different indices have the same name. See" +
266dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar                " @Index documentation for details."
267dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar    }
268dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar
2692c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar    fun duplicateIndexInDatabase(indexName: String, indexPaths: List<String>): String {
270dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar        return "There are multiple indices with name $indexName. You should rename " +
271dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar                "${indexPaths.size - 1} of these to avoid the conflict:" +
272dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar                "${indexPaths.joinToString(", ")}."
273dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar    }
274dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar
2752c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar    fun droppedDecomposedFieldIndex(fieldPath: String, grandParent: String): String {
276dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar        return "The index will be dropped when being merged into $grandParent" +
277dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar                "($fieldPath). You must re-declare it in $grandParent if you want to index this" +
278dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar                " field in $grandParent."
279dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar    }
280dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar
2812c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar    fun droppedDecomposedIndex(entityName: String, fieldPath: String, grandParent: String)
282dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar            : String {
283dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar        return "Indices defined in $entityName will be dropped when it is merged into" +
284dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar                " $grandParent ($fieldPath). You can re-declare them in $grandParent."
285dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar    }
286dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar
2872c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar    fun droppedSuperClassIndex(childEntity: String, superEntity: String): String {
288dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar        return "Indices defined in $superEntity will NOT be re-used in $childEntity. If you want" +
289dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar                " to inherit them, you must re-declare them in $childEntity." +
290dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar                " Alternatively, you can set inheritSuperIndices to true in the @Entity annotation."
291dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar    }
292dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar
2932c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar    fun droppedSuperClassFieldIndex(fieldName: String, childEntity: String,
2942c6462f129bf43965ed8b054b026f6a28fe6fd8fYigit Boyar                                    superEntity: String): String {
295dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar        return "Index defined on field `$fieldName` in $superEntity will NOT be re-used in" +
296dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar                " $childEntity. " +
297dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar                "If you want to inherit it, you must re-declare it in $childEntity." +
298dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar                " Alternatively, you can set inheritSuperIndices to true in the @Entity annotation."
299dc18ce63fe07921b1080e48d3e597e2b5240d17aYigit Boyar    }
300092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
301092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    val RELATION_NOT_COLLECTION = "Fields annotated with @Relation must be a List or Set."
302092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
303f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar    fun relationCannotFindEntityField(entityName : String, columnName: String,
304f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar                                      availableColumns: List<String>) : String {
305f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar        return "Cannot find the child entity column `$columnName` in $entityName." +
306f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar                " Options: ${availableColumns.joinToString(", ")}"
307092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    }
308092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
309f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar    fun relationCannotFindParentEntityField(entityName : String, columnName: String,
310f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar                                            availableColumns: List<String>) : String {
311f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar        return "Cannot find the parent entity column `$columnName` in $entityName." +
312f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar                " Options: ${availableColumns.joinToString(", ")}"
313092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    }
314092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
315092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    val RELATION_IN_ENTITY = "Entities cannot have relations."
316092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
317092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    val CANNOT_FIND_TYPE = "Cannot find type."
318092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
319f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar    fun relationAffinityMismatch(parentColumn: String, childColumn: String,
320092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                                 parentAffinity : SQLTypeAffinity?,
321092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                                 childAffinity : SQLTypeAffinity?) : String {
322092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        return """
323f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar        The affinity of parent column ($parentColumn : $parentAffinity) does not match the type
324f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar        affinity of the child column ($childColumn : $childAffinity).
325092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        """.trim()
326092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    }
327092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
328092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    val CANNOT_USE_MORE_THAN_ONE_POJO_FIELD_ANNOTATION = "A field can be annotated with only" +
329092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar            " one of the following:" + PojoProcessor.PROCESSED_ANNOTATIONS.joinToString(",") {
330092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        it.java.simpleName
331092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    }
332092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar
333092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    fun relationBadProject(entityQName : String, missingColumnNames : List<String>,
334092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar                           availableColumnNames : List<String>) : String {
335092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        return """
336092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        $entityQName does not have the following columns: ${missingColumnNames.joinToString(",")}.
337092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        Available columns are: ${availableColumnNames.joinToString(",")}
338092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar        """.trim()
339092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar    }
340a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar
341a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar    val MISSING_SCHEMA_EXPORT_DIRECTORY = "Schema export directory is not provided to the" +
342a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            " annotation processor so we cannot export the schema. You can either provide" +
343a64756a18111a7312b3fa03b76d13381a8907176Yigit Boyar            " `room.schemaLocation` annotation processor argument OR set exportSchema to false."
344875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar
345875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    val INVALID_FOREIGN_KEY_ACTION = "Invalid foreign key action. It must be one of the constants" +
346875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar            " defined in ForeignKey.Action"
347875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar
348875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    fun foreignKeyNotAnEntity(className : String) : String {
349875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar        return """
350875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar        Classes referenced in Foreign Key annotations must be @Entity classes. $className is not
351875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar        an entity
352875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar        """.trim()
353875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    }
354875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar
355875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    val FOREIGN_KEY_CANNOT_FIND_PARENT = "Cannot find parent entity class."
356875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar
357875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    fun foreignKeyChildColumnDoesNotExist(columnName: String, allColumns: List<String>): String {
358875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar        return "($columnName) referenced in the foreign key does not exists in the Entity." +
359875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                " Available column names:${allColumns.joinToString(", ")}"
360875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    }
361875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar
362875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    fun foreignKeyParentColumnDoesNotExist(parentEntity : String,
363875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                                           missingColumn: String,
364875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                                           allColumns : List<String>): String {
365875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar        return "($missingColumn) does not exist in $parentEntity. Available columns are" +
366875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                " ${allColumns.joinToString(",")}"
367875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    }
368875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar
369875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    val FOREIGN_KEY_EMPTY_CHILD_COLUMN_LIST = "Must specify at least 1 column name for the child"
370875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar
371875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    val FOREIGN_KEY_EMPTY_PARENT_COLUMN_LIST = "Must specify at least 1 column name for the parent"
372875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar
373875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    fun foreignKeyColumnNumberMismatch(childColumns : List<String>, parentColumns : List<String>)
374875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar            : String {
375875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar        return """
376875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                Number of child columns in foreign key must match number of parent columns.
377875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                Child reference has ${childColumns.joinToString(",")} and parent reference has
378875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                ${parentColumns.joinToString(",")}
379875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar               """.trim()
380875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    }
381875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar
382875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    fun foreignKeyMissingParentEntityInDatabase(parentTable : String, childEntity : String)
383875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar            : String {
384875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar        return """
385875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                $parentTable table referenced in the foreign keys of $childEntity does not exist in
386875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                the database. Maybe you forgot to add the referenced entity in the entities list of
387875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                the @Database annotation?""".trim()
388875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    }
389875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar
390875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    fun foreignKeyMissingIndexInParent(parentEntity : String, parentColumns: List<String>,
391875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                                       childEntity : String, childColumns: List<String>): String {
392875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar        return """
393875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                $childEntity has a foreign key (${childColumns.joinToString(",")}) that references
394875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                $parentEntity (${parentColumns.joinToString(",")}) but $parentEntity does not have
395875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                a unique index on those columns nor the columns are its primary key.
396875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                SQLite requires having a unique constraint on referenced parent columns so you must
397875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                add a unique index to $parentEntity that has
398875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                (${parentColumns.joinToString(",")}) column(s).
399875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar               """.trim()
400875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    }
401875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar
402875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    fun foreignKeyMissingIndexInChildColumns(childColumns: List<String>) : String {
403875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar        return """
404875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                (${childColumns.joinToString(",")}) column(s) reference a foreign key but
405875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                they are not part of an index. This may trigger full table scans whenever parent
406875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                table is modified so you are highly advised to create an index that covers these
407875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                columns.
408875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar               """.trim()
409875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    }
410875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar
411875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    fun foreignKeyMissingIndexInChildColumn(childColumn: String) : String {
412875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar        return """
413875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                $childColumn column references a foreign key but it is not part of an index. This
414875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                may trigger full table scans whenever parent table is modified so you are highly
415875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar                advised to create an index that covers this column.
416875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar               """.trim()
417875203d39f95be2367dec3ee70be4e2169b4e0f0Yigit Boyar    }
41808ddf77b7cc743f85b23e83de8b22b69fe4bf6d2Yigit Boyar
41908ddf77b7cc743f85b23e83de8b22b69fe4bf6d2Yigit Boyar    fun shortcutEntityIsNotInDatabase(database : String, dao : String, entity : String) : String {
42008ddf77b7cc743f85b23e83de8b22b69fe4bf6d2Yigit Boyar        return """
42108ddf77b7cc743f85b23e83de8b22b69fe4bf6d2Yigit Boyar                $dao is part of $database but this entity is not in the database. Maybe you forgot
42208ddf77b7cc743f85b23e83de8b22b69fe4bf6d2Yigit Boyar                to add $entity to the entities section of the @Database?
42308ddf77b7cc743f85b23e83de8b22b69fe4bf6d2Yigit Boyar                """.trim()
42408ddf77b7cc743f85b23e83de8b22b69fe4bf6d2Yigit Boyar    }
4253c592c4ccbc6052b11443b0fa575052c08fefa55Yigit Boyar    val MISSING_ROOM_RXJAVA2_ARTIFACT = "To use RxJava2 features, you must add `rxjava2`" +
4263c592c4ccbc6052b11443b0fa575052c08fefa55Yigit Boyar            " artifact from Room as a dependency. com.android.support.room:rxjava2:<version>"
42719b41105359a52aeb80070dec40247241231f05dYigit Boyar}
428