diff --git a/README.md b/README.md index 4780396..13cd4b5 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,127 @@ -# RoomMigrationsGenerator -Automated Android Room ORM migrations generator with compile-time code generation +# Roomigrant + +Roomigrant is a helper library to automatically generate Android Room library migrations using compile-time code generation. + +# How does it work? + +Roomigrant uses scheme files generated by Room library and generates migrations base on difference between them. This means that Room schem generation must be enabled in build.gradle file: + +```groovy +android { + defaultConfig { + javaCompileOptions { + annotationProcessorOptions { + arguments = ["room.schemaLocation": "$projectDir/schemas".toString()] + } + } + } +} +``` + +Then actual Roomigrant library and compiler should be added to dependencies (preferrably after room dependencies): + +```groovy +dependencies { + // room + implementation 'android.arch.persistence.room:runtime:1.1.1' + kapt 'android.arch.persistence.room:compiler:1.1.1' + + // roomigrant + compileOnly project(':RoomigrantLib') + kapt project(':RoomigrantCompiler') +} +``` + +After that actual database class should be annotated to enable migrations generator: + +```kotlin +@Database(version = 5, entities = [Object1Dbo::class, Object2Dbo::class]) +@GenerateRoomMigrations +abstract class Database : RoomDatabase() { + // ... +} +``` + +And finally migrations can be added to actual Room database creation: + +```kotlin +Room.databaseBuilder(appContext, Database::class.java, "database.sqlite") + .addMigrations(*Database_Migrations.build()) + .build() +``` + +# Default rules + +Roominator will try its best to migrate everything by itself. It default rules are: + + - columns that have new affinity/type will use SQLite's CAST method + - null cells became not nullable will take default value for thir's affinity/type + - new columns will be initialized to default value + -- 0 for INTEGER + -- 0.0 for REAL + -- "" for TEXT or BLOB + +Because of SQLite limitations when any change other than adding new column is done: + - new merge table will be created + - data copied from original table to merge table + - original table will be removed + - merge table will be renamed back to original + +# Custom rules + +Sometimes it will be required to write custom migration rules. It can be done by adding classes to GenerateRoomMigrations annotation: + +```kotlin +@Database(version = 5, entities = [Object1Dbo::class, Object2Dbo::class]) +@GenerateRoomMigrations(Rules::class) +abstract class Database : RoomDatabase() { + // ... +} +``` + +And after that adding methods annotated with FieldMigrationRule annotation to provided classes: + +```kotlin +// version 3 had Object1Dbo.intVal column +// version 4 has Object1Dbo.intValRenamed column +@FieldMigrationRule(version1 = 3, version2 = 4, table = "Object1Dbo", field = "intValRenamed") +fun migrate_3_4_Object1Dbo_intVal(): String { + return "`Object1Dbo`.`intVal`" +} +``` + +Returned value will be injected as-is to final SQL statement when copying/updating that field. + +# Todos + + - Add table and column names escaping + - Add foreign key support (currently they are completely ignored) + - Add OnMigrationStart and OnMigrationEnd annotated callbacks + - Add to Maven Central (if anyone will use this library at all) + - Some internal optimizations + +# License + +``` +MIT License + +Copyright (c) 2018 Rostyslav Lesovyi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +``` diff --git a/RoomigrantTest/schemas/dev.matrix.roomigrant.test.Database/5.json b/RoomigrantTest/schemas/dev.matrix.roomigrant.test.Database/5.json index 6db12ef..0366c89 100644 --- a/RoomigrantTest/schemas/dev.matrix.roomigrant.test.Database/5.json +++ b/RoomigrantTest/schemas/dev.matrix.roomigrant.test.Database/5.json @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 5, - "identityHash": "bc0fa74c1813d4ced25801545540915a", + "identityHash": "d51066cdc9a5e865378f2c5cb2f61699", "entities": [ { "tableName": "Object1Dbo", @@ -47,11 +47,31 @@ }, "indices": [], "foreignKeys": [] + }, + { + "tableName": "Object2Dbo", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] } ], "setupQueries": [ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", - "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"bc0fa74c1813d4ced25801545540915a\")" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"d51066cdc9a5e865378f2c5cb2f61699\")" ] } } \ No newline at end of file diff --git a/RoomigrantTest/src/main/java/dev/matrix/roomigrant/test/Database.kt b/RoomigrantTest/src/main/java/dev/matrix/roomigrant/test/Database.kt index 6eeeb59..026055b 100644 --- a/RoomigrantTest/src/main/java/dev/matrix/roomigrant/test/Database.kt +++ b/RoomigrantTest/src/main/java/dev/matrix/roomigrant/test/Database.kt @@ -7,8 +7,9 @@ import dev.matrix.roomigrant.GenerateRoomMigrations /** * @author matrixdev */ -@Database(version = 5, entities = [Object1Dbo::class]) +@Database(version = 5, entities = [Object1Dbo::class, Object2Dbo::class]) @GenerateRoomMigrations(Rules::class) abstract class Database : RoomDatabase() { abstract val object1Dao: Object1Dao + abstract val object2Dao: Object2Dao }