ProcessorErrors.kt revision cab865bed3b4e9df8b86b0b16c589c4e6dd0b71d
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.arch.persistence.room.processor 18 19import android.arch.persistence.room.Delete 20import android.arch.persistence.room.Insert 21import android.arch.persistence.room.Query 22import android.arch.persistence.room.RawQuery 23import android.arch.persistence.room.Update 24import android.arch.persistence.room.ext.RoomTypeNames 25import android.arch.persistence.room.parser.SQLTypeAffinity 26import android.arch.persistence.room.vo.CustomTypeConverter 27import android.arch.persistence.room.vo.Field 28import com.squareup.javapoet.TypeName 29 30object ProcessorErrors { 31 private fun String.trim(): String { 32 return this.trimIndent().replace("\n", " ") 33 } 34 val MISSING_QUERY_ANNOTATION = "Query methods must be annotated with ${Query::class.java}" 35 val MISSING_INSERT_ANNOTATION = "Insertion methods must be annotated with ${Insert::class.java}" 36 val MISSING_DELETE_ANNOTATION = "Deletion methods must be annotated with ${Delete::class.java}" 37 val MISSING_UPDATE_ANNOTATION = "Update methods must be annotated with ${Update::class.java}" 38 val MISSING_RAWQUERY_ANNOTATION = "RawQuery methods must be annotated with" + 39 " ${RawQuery::class.java}" 40 val INVALID_ON_CONFLICT_VALUE = "On conflict value must be one of @OnConflictStrategy values." 41 val INVALID_INSERTION_METHOD_RETURN_TYPE = "Methods annotated with @Insert can return either" + 42 " void, long, Long, long[], Long[] or List<Long>." 43 val TRANSACTION_REFERENCE_DOCS = "https://developer.android.com/reference/android/arch/" + 44 "persistence/room/Transaction.html" 45 46 fun insertionMethodReturnTypeMismatch(definedReturn: TypeName, 47 expectedReturnTypes: List<TypeName>): String { 48 return "Method returns $definedReturn but it should return one of the following: `" + 49 expectedReturnTypes.joinToString(", ") + "`. If you want to return the list of" + 50 " row ids from the query, your insertion method can receive only 1 parameter." 51 } 52 53 val ABSTRACT_METHOD_IN_DAO_MISSING_ANY_ANNOTATION = "Abstract method in DAO must be annotated" + 54 " with ${Query::class.java} AND ${Insert::class.java}" 55 val INVALID_ANNOTATION_COUNT_IN_DAO_METHOD = "An abstract DAO method must be" + 56 " annotated with one and only one of the following annotations: " + 57 DaoProcessor.PROCESSED_ANNOTATIONS.joinToString(",") { 58 it.java.simpleName 59 } 60 val CANNOT_RESOLVE_RETURN_TYPE = "Cannot resolve return type for %s" 61 val CANNOT_USE_UNBOUND_GENERICS_IN_QUERY_METHODS = "Cannot use unbound generics in query" + 62 " methods. It must be bound to a type through base Dao class." 63 val CANNOT_USE_UNBOUND_GENERICS_IN_INSERTION_METHODS = "Cannot use unbound generics in" + 64 " insertion methods. It must be bound to a type through base Dao class." 65 val CANNOT_USE_UNBOUND_GENERICS_IN_ENTITY_FIELDS = "Cannot use unbound fields in entities." 66 val CANNOT_USE_UNBOUND_GENERICS_IN_DAO_CLASSES = "Cannot use unbound generics in Dao classes." + 67 " If you are trying to create a base DAO, create a normal class, extend it with type" + 68 " params then mark the subclass with @Dao." 69 val CANNOT_FIND_GETTER_FOR_FIELD = "Cannot find getter for field." 70 val CANNOT_FIND_SETTER_FOR_FIELD = "Cannot find setter for field." 71 val MISSING_PRIMARY_KEY = "An entity must have at least 1 field annotated with @PrimaryKey" 72 val AUTO_INCREMENTED_PRIMARY_KEY_IS_NOT_INT = "If a primary key is annotated with" + 73 " autoGenerate, its type must be int, Integer, long or Long." 74 val AUTO_INCREMENT_EMBEDDED_HAS_MULTIPLE_FIELDS = "When @PrimaryKey annotation is used on a" + 75 " field annotated with @Embedded, the embedded class should have only 1 field." 76 77 fun multiplePrimaryKeyAnnotations(primaryKeys: List<String>): String { 78 return """ 79 You cannot have multiple primary keys defined in an Entity. If you 80 want to declare a composite primary key, you should use @Entity#primaryKeys and 81 not use @PrimaryKey. Defined Primary Keys: 82 ${primaryKeys.joinToString(", ")}""".trim() 83 } 84 85 fun primaryKeyColumnDoesNotExist(columnName: String, allColumns: List<String>): String { 86 return "$columnName referenced in the primary key does not exists in the Entity." + 87 " Available column names:${allColumns.joinToString(", ")}" 88 } 89 90 val DAO_MUST_BE_AN_ABSTRACT_CLASS_OR_AN_INTERFACE = "Dao class must be an abstract class or" + 91 " an interface" 92 val DATABASE_MUST_BE_ANNOTATED_WITH_DATABASE = "Database must be annotated with @Database" 93 val DAO_MUST_BE_ANNOTATED_WITH_DAO = "Dao class must be annotated with @Dao" 94 95 fun daoMustHaveMatchingConstructor(daoName: String, dbName: String): String { 96 return """ 97 $daoName needs to have either an empty constructor or a constructor that takes 98 $dbName as its only parameter. 99 """.trim() 100 } 101 102 val ENTITY_MUST_BE_ANNOTATED_WITH_ENTITY = "Entity class must be annotated with @Entity" 103 val DATABASE_ANNOTATION_MUST_HAVE_LIST_OF_ENTITIES = "@Database annotation must specify list" + 104 " of entities" 105 val COLUMN_NAME_CANNOT_BE_EMPTY = "Column name cannot be blank. If you don't want to set it" + 106 ", just remove the @ColumnInfo annotation or use @ColumnInfo.INHERIT_FIELD_NAME." 107 108 val ENTITY_TABLE_NAME_CANNOT_BE_EMPTY = "Entity table name cannot be blank. If you don't want" + 109 " to set it, just remove the tableName property." 110 111 val CANNOT_BIND_QUERY_PARAMETER_INTO_STMT = "Query method parameters should either be a" + 112 " type that can be converted into a database column or a List / Array that contains" + 113 " such type. You can consider adding a Type Adapter for this." 114 115 val QUERY_PARAMETERS_CANNOT_START_WITH_UNDERSCORE = "Query/Insert method parameters cannot " + 116 "start with underscore (_)." 117 118 val CANNOT_FIND_QUERY_RESULT_ADAPTER = "Not sure how to convert a Cursor to this method's " + 119 "return type" 120 121 val INSERTION_DOES_NOT_HAVE_ANY_PARAMETERS_TO_INSERT = "Method annotated with" + 122 " @Insert but does not have any parameters to insert." 123 124 val DELETION_MISSING_PARAMS = "Method annotated with" + 125 " @Delete but does not have any parameters to delete." 126 127 val UPDATE_MISSING_PARAMS = "Method annotated with" + 128 " @Update but does not have any parameters to update." 129 130 val TRANSACTION_METHOD_MODIFIERS = "Method annotated with @Transaction must not be " + 131 "private, final, or abstract. It can be abstract only if the method is also" + 132 " annotated with @Query." 133 134 val TRANSACTION_MISSING_ON_RELATION = "The return value includes a Pojo with a @Relation." + 135 " It is usually desired to annotate this method with @Transaction to avoid" + 136 " possibility of inconsistent results between the Pojo and its relations. See " + 137 TRANSACTION_REFERENCE_DOCS + " for details." 138 139 val CANNOT_FIND_ENTITY_FOR_SHORTCUT_QUERY_PARAMETER = "Type of the parameter must be a class " + 140 "annotated with @Entity or a collection/array of it." 141 142 val DB_MUST_EXTEND_ROOM_DB = "Classes annotated with @Database should extend " + 143 RoomTypeNames.ROOM_DB 144 145 val LIVE_DATA_QUERY_WITHOUT_SELECT = "LiveData return type can only be used with SELECT" + 146 " queries." 147 148 val OBSERVABLE_QUERY_NOTHING_TO_OBSERVE = "Observable query return type (LiveData, Flowable" + 149 ", DataSource, DataSourceFactory etc) can only be used with SELECT queries that" + 150 " directly or indirectly (via @Relation, for example) access at least one table. For" + 151 " @RawQuery, you should specify the list of tables to be observed via the" + 152 " observedEntities field." 153 154 val RECURSIVE_REFERENCE_DETECTED = "Recursive referencing through @Embedded and/or @Relation " + 155 "detected: %s" 156 157 private val TOO_MANY_MATCHING_GETTERS = "Ambiguous getter for %s. All of the following " + 158 "match: %s. You can @Ignore the ones that you don't want to match." 159 160 fun tooManyMatchingGetters(field: Field, methodNames: List<String>): String { 161 return TOO_MANY_MATCHING_GETTERS.format(field, methodNames.joinToString(", ")) 162 } 163 164 private val TOO_MANY_MATCHING_SETTERS = "Ambiguous setter for %s. All of the following " + 165 "match: %s. You can @Ignore the ones that you don't want to match." 166 167 fun tooManyMatchingSetter(field: Field, methodNames: List<String>): String { 168 return TOO_MANY_MATCHING_SETTERS.format(field, methodNames.joinToString(", ")) 169 } 170 171 val CANNOT_FIND_COLUMN_TYPE_ADAPTER = "Cannot figure out how to save this field into" + 172 " database. You can consider adding a type converter for it." 173 174 val CANNOT_FIND_STMT_BINDER = "Cannot figure out how to bind this field into a statement." 175 176 val CANNOT_FIND_CURSOR_READER = "Cannot figure out how to read this field from a cursor." 177 178 private val MISSING_PARAMETER_FOR_BIND = "Each bind variable in the query must have a" + 179 " matching method parameter. Cannot find method parameters for %s." 180 181 fun missingParameterForBindVariable(bindVarName: List<String>): String { 182 return MISSING_PARAMETER_FOR_BIND.format(bindVarName.joinToString(", ")) 183 } 184 185 private val UNUSED_QUERY_METHOD_PARAMETER = "Unused parameter%s: %s" 186 fun unusedQueryMethodParameter(unusedParams: List<String>): String { 187 return UNUSED_QUERY_METHOD_PARAMETER.format( 188 if (unusedParams.size > 1) "s" else "", 189 unusedParams.joinToString(",")) 190 } 191 192 private val DUPLICATE_TABLES = "Table name \"%s\" is used by multiple entities: %s" 193 fun duplicateTableNames(tableName: String, entityNames: List<String>): String { 194 return DUPLICATE_TABLES.format(tableName, entityNames.joinToString(", ")) 195 } 196 197 val DELETION_METHODS_MUST_RETURN_VOID_OR_INT = "Deletion methods must either return void or" + 198 " return int (the number of deleted rows)." 199 200 val UPDATE_METHODS_MUST_RETURN_VOID_OR_INT = "Update methods must either return void or" + 201 " return int (the number of updated rows)." 202 203 val DAO_METHOD_CONFLICTS_WITH_OTHERS = "Dao method has conflicts." 204 205 fun duplicateDao(dao: TypeName, methodNames: List<String>): String { 206 return """ 207 All of these functions [${methodNames.joinToString(", ")}] return the same DAO 208 class [$dao]. 209 A database can use a DAO only once so you should remove ${methodNames.size - 1} of 210 these conflicting DAO methods. If you are implementing any of these to fulfill an 211 interface, don't make it abstract, instead, implement the code that calls the 212 other one. 213 """.trim() 214 } 215 216 fun pojoMissingNonNull(pojoTypeName: TypeName, missingPojoFields: List<String>, 217 allQueryColumns: List<String>): String { 218 return """ 219 The columns returned by the query does not have the fields 220 [${missingPojoFields.joinToString(",")}] in $pojoTypeName even though they are 221 annotated as non-null or primitive. 222 Columns returned by the query: [${allQueryColumns.joinToString(",")}] 223 """.trim() 224 } 225 226 fun cursorPojoMismatch(pojoTypeName: TypeName, 227 unusedColumns: List<String>, allColumns: List<String>, 228 unusedFields: List<Field>, allFields: List<Field>): String { 229 val unusedColumnsWarning = if (unusedColumns.isNotEmpty()) { 230 """ 231 The query returns some columns [${unusedColumns.joinToString(", ")}] which are not 232 use by $pojoTypeName. You can use @ColumnInfo annotation on the fields to specify 233 the mapping. 234 """.trim() 235 } else { 236 "" 237 } 238 val unusedFieldsWarning = if (unusedFields.isNotEmpty()) { 239 """ 240 $pojoTypeName has some fields 241 [${unusedFields.joinToString(", ") { it.columnName }}] which are not returned by the 242 query. If they are not supposed to be read from the result, you can mark them with 243 @Ignore annotation. 244 """.trim() 245 } else { 246 "" 247 } 248 return """ 249 $unusedColumnsWarning 250 $unusedFieldsWarning 251 You can suppress this warning by annotating the method with 252 @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH). 253 Columns returned by the query: ${allColumns.joinToString(", ")}. 254 Fields in $pojoTypeName: ${allFields.joinToString(", ") { it.columnName }}. 255 """.trim() 256 } 257 258 val TYPE_CONVERTER_UNBOUND_GENERIC = "Cannot use unbound generics in Type Converters." 259 val TYPE_CONVERTER_BAD_RETURN_TYPE = "Invalid return type for a type converter." 260 val TYPE_CONVERTER_MUST_RECEIVE_1_PARAM = "Type converters must receive 1 parameter." 261 val TYPE_CONVERTER_EMPTY_CLASS = "Class is referenced as a converter but it does not have any" + 262 " converter methods." 263 val TYPE_CONVERTER_MISSING_NOARG_CONSTRUCTOR = "Classes that are used as TypeConverters must" + 264 " have no-argument public constructors." 265 val TYPE_CONVERTER_MUST_BE_PUBLIC = "Type converters must be public." 266 267 fun duplicateTypeConverters(converters: List<CustomTypeConverter>): String { 268 return "Multiple methods define the same conversion. Conflicts with these:" + 269 " ${converters.joinToString(", ") { it.toString() }}" 270 } 271 272 // TODO must print field paths. 273 val POJO_FIELD_HAS_DUPLICATE_COLUMN_NAME = "Field has non-unique column name." 274 275 fun pojoDuplicateFieldNames(columnName: String, fieldPaths: List<String>): String { 276 return "Multiple fields have the same columnName: $columnName." + 277 " Field names: ${fieldPaths.joinToString(", ")}." 278 } 279 280 fun embeddedPrimaryKeyIsDropped(entityQName: String, fieldName: String): String { 281 return "Primary key constraint on $fieldName is ignored when being merged into " + 282 entityQName 283 } 284 285 val INDEX_COLUMNS_CANNOT_BE_EMPTY = "List of columns in an index cannot be empty" 286 287 fun indexColumnDoesNotExist(columnName: String, allColumns: List<String>): String { 288 return "$columnName referenced in the index does not exists in the Entity." + 289 " Available column names:${allColumns.joinToString(", ")}" 290 } 291 292 fun duplicateIndexInEntity(indexName: String): String { 293 return "There are multiple indices with name $indexName. This happen if you've declared" + 294 " the same index multiple times or different indices have the same name. See" + 295 " @Index documentation for details." 296 } 297 298 fun duplicateIndexInDatabase(indexName: String, indexPaths: List<String>): String { 299 return "There are multiple indices with name $indexName. You should rename " + 300 "${indexPaths.size - 1} of these to avoid the conflict:" + 301 "${indexPaths.joinToString(", ")}." 302 } 303 304 fun droppedEmbeddedFieldIndex(fieldPath: String, grandParent: String): String { 305 return "The index will be dropped when being merged into $grandParent" + 306 "($fieldPath). You must re-declare it in $grandParent if you want to index this" + 307 " field in $grandParent." 308 } 309 310 fun droppedEmbeddedIndex(entityName: String, fieldPath: String, grandParent: String): String { 311 return "Indices defined in $entityName will be dropped when it is merged into" + 312 " $grandParent ($fieldPath). You can re-declare them in $grandParent." 313 } 314 315 fun droppedSuperClassIndex(childEntity: String, superEntity: String): String { 316 return "Indices defined in $superEntity will NOT be re-used in $childEntity. If you want" + 317 " to inherit them, you must re-declare them in $childEntity." + 318 " Alternatively, you can set inheritSuperIndices to true in the @Entity annotation." 319 } 320 321 fun droppedSuperClassFieldIndex(fieldName: String, childEntity: String, 322 superEntity: String): String { 323 return "Index defined on field `$fieldName` in $superEntity will NOT be re-used in" + 324 " $childEntity. " + 325 "If you want to inherit it, you must re-declare it in $childEntity." + 326 " Alternatively, you can set inheritSuperIndices to true in the @Entity annotation." 327 } 328 329 val RELATION_NOT_COLLECTION = "Fields annotated with @Relation must be a List or Set." 330 331 fun relationCannotFindEntityField(entityName: String, columnName: String, 332 availableColumns: List<String>): String { 333 return "Cannot find the child entity column `$columnName` in $entityName." + 334 " Options: ${availableColumns.joinToString(", ")}" 335 } 336 337 fun relationCannotFindParentEntityField(entityName: String, columnName: String, 338 availableColumns: List<String>): String { 339 return "Cannot find the parent entity column `$columnName` in $entityName." + 340 " Options: ${availableColumns.joinToString(", ")}" 341 } 342 343 val RELATION_IN_ENTITY = "Entities cannot have relations." 344 345 val CANNOT_FIND_TYPE = "Cannot find type." 346 347 fun relationAffinityMismatch(parentColumn: String, childColumn: String, 348 parentAffinity: SQLTypeAffinity?, 349 childAffinity: SQLTypeAffinity?): String { 350 return """ 351 The affinity of parent column ($parentColumn : $parentAffinity) does not match the type 352 affinity of the child column ($childColumn : $childAffinity). 353 """.trim() 354 } 355 356 val CANNOT_USE_MORE_THAN_ONE_POJO_FIELD_ANNOTATION = "A field can be annotated with only" + 357 " one of the following:" + PojoProcessor.PROCESSED_ANNOTATIONS.joinToString(",") { 358 it.java.simpleName 359 } 360 361 fun relationBadProject(entityQName: String, missingColumnNames: List<String>, 362 availableColumnNames: List<String>): String { 363 return """ 364 $entityQName does not have the following columns: ${missingColumnNames.joinToString(",")}. 365 Available columns are: ${availableColumnNames.joinToString(",")} 366 """.trim() 367 } 368 369 val MISSING_SCHEMA_EXPORT_DIRECTORY = "Schema export directory is not provided to the" + 370 " annotation processor so we cannot export the schema. You can either provide" + 371 " `room.schemaLocation` annotation processor argument OR set exportSchema to false." 372 373 val INVALID_FOREIGN_KEY_ACTION = "Invalid foreign key action. It must be one of the constants" + 374 " defined in ForeignKey.Action" 375 376 fun foreignKeyNotAnEntity(className: String): String { 377 return """ 378 Classes referenced in Foreign Key annotations must be @Entity classes. $className is not 379 an entity 380 """.trim() 381 } 382 383 val FOREIGN_KEY_CANNOT_FIND_PARENT = "Cannot find parent entity class." 384 385 fun foreignKeyChildColumnDoesNotExist(columnName: String, allColumns: List<String>): String { 386 return "($columnName) referenced in the foreign key does not exists in the Entity." + 387 " Available column names:${allColumns.joinToString(", ")}" 388 } 389 390 fun foreignKeyParentColumnDoesNotExist(parentEntity: String, 391 missingColumn: String, 392 allColumns: List<String>): String { 393 return "($missingColumn) does not exist in $parentEntity. Available columns are" + 394 " ${allColumns.joinToString(",")}" 395 } 396 397 val FOREIGN_KEY_EMPTY_CHILD_COLUMN_LIST = "Must specify at least 1 column name for the child" 398 399 val FOREIGN_KEY_EMPTY_PARENT_COLUMN_LIST = "Must specify at least 1 column name for the parent" 400 401 fun foreignKeyColumnNumberMismatch( 402 childColumns: List<String>, parentColumns: List<String>): String { 403 return """ 404 Number of child columns in foreign key must match number of parent columns. 405 Child reference has ${childColumns.joinToString(",")} and parent reference has 406 ${parentColumns.joinToString(",")} 407 """.trim() 408 } 409 410 fun foreignKeyMissingParentEntityInDatabase(parentTable: String, childEntity: String): String { 411 return """ 412 $parentTable table referenced in the foreign keys of $childEntity does not exist in 413 the database. Maybe you forgot to add the referenced entity in the entities list of 414 the @Database annotation?""".trim() 415 } 416 417 fun foreignKeyMissingIndexInParent(parentEntity: String, parentColumns: List<String>, 418 childEntity: String, childColumns: List<String>): String { 419 return """ 420 $childEntity has a foreign key (${childColumns.joinToString(",")}) that references 421 $parentEntity (${parentColumns.joinToString(",")}) but $parentEntity does not have 422 a unique index on those columns nor the columns are its primary key. 423 SQLite requires having a unique constraint on referenced parent columns so you must 424 add a unique index to $parentEntity that has 425 (${parentColumns.joinToString(",")}) column(s). 426 """.trim() 427 } 428 429 fun foreignKeyMissingIndexInChildColumns(childColumns: List<String>): String { 430 return """ 431 (${childColumns.joinToString(",")}) column(s) reference a foreign key but 432 they are not part of an index. This may trigger full table scans whenever parent 433 table is modified so you are highly advised to create an index that covers these 434 columns. 435 """.trim() 436 } 437 438 fun foreignKeyMissingIndexInChildColumn(childColumn: String): String { 439 return """ 440 $childColumn column references a foreign key but it is not part of an index. This 441 may trigger full table scans whenever parent table is modified so you are highly 442 advised to create an index that covers this column. 443 """.trim() 444 } 445 446 fun shortcutEntityIsNotInDatabase(database: String, dao: String, entity: String): String { 447 return """ 448 $dao is part of $database but this entity is not in the database. Maybe you forgot 449 to add $entity to the entities section of the @Database? 450 """.trim() 451 } 452 453 val MISSING_ROOM_GUAVA_ARTIFACT = "To use Guava features, you must add `guava`" + 454 " artifact from Room as a dependency. android.arch.persistence.room:guava:<version>" 455 456 val MISSING_ROOM_RXJAVA2_ARTIFACT = "To use RxJava2 features, you must add `rxjava2`" + 457 " artifact from Room as a dependency. android.arch.persistence.room:rxjava2:<version>" 458 459 fun ambigiousConstructor( 460 pojo: String, paramName: String, matchingFields: List<String>): String { 461 return """ 462 Ambiguous constructor. The parameter ($paramName) in $pojo matches multiple fields: 463 [${matchingFields.joinToString(",")}]. If you don't want to use this constructor, 464 you can annotate it with @Ignore. If you want Room to use this constructor, you can 465 rename the parameters to exactly match the field name to fix the ambiguity. 466 """.trim() 467 } 468 469 val MISSING_POJO_CONSTRUCTOR = """ 470 Entities and Pojos must have a usable public constructor. You can have an empty 471 constructor or a constructor whose parameters match the fields (by name and type). 472 """.trim() 473 474 val TOO_MANY_POJO_CONSTRUCTORS = """ 475 Room cannot pick a constructor since multiple constructors are suitable. Try to annotate 476 unwanted constructors with @Ignore. 477 """.trim() 478 479 val TOO_MANY_POJO_CONSTRUCTORS_CHOOSING_NO_ARG = """ 480 There are multiple good constructors and Room will pick the no-arg constructor. 481 You can use the @Ignore annotation to eliminate unwanted constructors. 482 """.trim() 483 484 val RELATION_CANNOT_BE_CONSTRUCTOR_PARAMETER = """ 485 Fields annotated with @Relation cannot be constructor parameters. These values are 486 fetched after the object is constructed. 487 """.trim() 488 489 val PAGING_SPECIFY_DATA_SOURCE_TYPE = "For now, Room only supports PositionalDataSource class." 490 491 fun primaryKeyNull(field: String): String { 492 return "You must annotate primary keys with @NonNull. \"$field\" is nullable. SQLite " + 493 "considers this a " + 494 "bug and Room does not allow it. See SQLite docs for details: " + 495 "https://www.sqlite.org/lang_createtable.html" 496 } 497 498 val INVALID_COLUMN_NAME = "Invalid column name. Room does not allow using ` or \" in column" + 499 " names" 500 501 val INVALID_TABLE_NAME = "Invalid table name. Room does not allow using ` or \" in table names" 502 503 val RAW_QUERY_BAD_PARAMS = "RawQuery methods should have 1 and only 1 parameter with type" + 504 " String or SupportSQLiteQuery" 505 506 val RAW_QUERY_BAD_RETURN_TYPE = "RawQuery methods must return a non-void type." 507} 508