diff options
author | Rahul Ravikumar <rahulrav@google.com> | 2018-07-09 14:48:45 -0700 |
---|---|---|
committer | Rahul Ravikumar <rahulrav@google.com> | 2018-07-09 16:36:09 -0700 |
commit | 58441a2f2a843411833650f4ac8c438003b9cfcd (patch) | |
tree | cb51b26b150a57879624dcc9a9d2a92d0409d312 | |
parent | fe793bcf625c2dbbd33e979b12ed72735c96c6dc (diff) | |
download | support-58441a2f2a843411833650f4ac8c438003b9cfcd.tar.gz |
Add a migration that updates the SCHEDULE_REQUESTED_AT bit for PeriodicWork in API >= 23.
Related CL: https://googleplex-android-review.googlesource.com/c/platform/frameworks/support/+/4492517
Test: Added migration tests.
Change-Id: I720d76238916c4f7eb258912ce9cbbd095e458bc
4 files changed, 488 insertions, 40 deletions
diff --git a/work/workmanager/src/androidTest/java/androidx/work/WorkDatabaseMigrationTest.java b/work/workmanager/src/androidTest/java/androidx/work/WorkDatabaseMigrationTest.java index 4e62cedb677..0cba3cf0c6c 100644 --- a/work/workmanager/src/androidTest/java/androidx/work/WorkDatabaseMigrationTest.java +++ b/work/workmanager/src/androidTest/java/androidx/work/WorkDatabaseMigrationTest.java @@ -18,6 +18,12 @@ package androidx.work; import static android.database.sqlite.SQLiteDatabase.CONFLICT_FAIL; +import static androidx.work.impl.WorkDatabaseMigrations.MIGRATION_3_4; +import static androidx.work.impl.WorkDatabaseMigrations.VERSION_1; +import static androidx.work.impl.WorkDatabaseMigrations.VERSION_2; +import static androidx.work.impl.WorkDatabaseMigrations.VERSION_3; +import static androidx.work.impl.WorkDatabaseMigrations.VERSION_4; + import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @@ -28,12 +34,15 @@ import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteException; +import android.os.Build; +import android.support.annotation.NonNull; import android.support.test.InstrumentationRegistry; import android.support.test.filters.MediumTest; import android.support.test.runner.AndroidJUnit4; import androidx.work.impl.WorkDatabase; import androidx.work.impl.WorkDatabaseMigrations; +import androidx.work.impl.WorkManagerImpl; import androidx.work.impl.model.WorkSpec; import androidx.work.impl.model.WorkTypeConverters; import androidx.work.impl.utils.Preferences; @@ -53,9 +62,6 @@ public class WorkDatabaseMigrationTest { private static final String TEST_DATABASE = "workdatabase-test"; private static final boolean VALIDATE_DROPPED_TABLES = true; - private static final int VERSION_1 = 1; - private static final int VERSION_2 = 2; - private static final int VERSION_3 = 3; private static final String COLUMN_WORKSPEC_ID = "work_spec_id"; private static final String COLUMN_SYSTEM_ID = "system_id"; private static final String COLUMN_ALARM_ID = "alarm_id"; @@ -97,35 +103,12 @@ public class WorkDatabaseMigrationTest { SupportSQLiteDatabase database = mMigrationTestHelper.createDatabase(TEST_DATABASE, VERSION_1); - String[] prepopulatedWorkSpecIds = new String[] { + String[] prepopulatedWorkSpecIds = new String[]{ UUID.randomUUID().toString(), UUID.randomUUID().toString() }; for (String workSpecId : prepopulatedWorkSpecIds) { - ContentValues contentValues = new ContentValues(); - contentValues.put("id", workSpecId); - contentValues.put("state", WorkTypeConverters.StateIds.ENQUEUED); - contentValues.put("worker_class_name", TestWorker.class.getName()); - contentValues.put("input_merger_class_name", OverwritingInputMerger.class.getName()); - contentValues.put("input", Data.toByteArray(Data.EMPTY)); - contentValues.put("output", Data.toByteArray(Data.EMPTY)); - contentValues.put("initial_delay", 0L); - contentValues.put("interval_duration", 0L); - contentValues.put("flex_duration", 0L); - contentValues.put("required_network_type", false); - contentValues.put("requires_charging", false); - contentValues.put("requires_device_idle", false); - contentValues.put("requires_battery_not_low", false); - contentValues.put("requires_storage_not_low", false); - contentValues.put("content_uri_triggers", - WorkTypeConverters.contentUriTriggersToByteArray(new ContentUriTriggers())); - contentValues.put("run_attempt_count", 0); - contentValues.put("backoff_policy", - WorkTypeConverters.backoffPolicyToInt(BackoffPolicy.EXPONENTIAL)); - contentValues.put("backoff_delay_duration", WorkRequest.DEFAULT_BACKOFF_DELAY_MILLIS); - contentValues.put("period_start_time", 0L); - contentValues.put("minimum_retention_duration", 0L); - contentValues.put("schedule_requested_at", WorkSpec.SCHEDULE_NOT_REQUESTED_YET); + ContentValues contentValues = contentValues(workSpecId); database.insert("workspec", CONFLICT_FAIL, contentValues); if (workSpecId.equals(prepopulatedWorkSpecIds[0])) { @@ -193,8 +176,8 @@ public class WorkDatabaseMigrationTest { public void testMigrationVersion2To3() throws IOException { SupportSQLiteDatabase database = mMigrationTestHelper.createDatabase(TEST_DATABASE, VERSION_2); - WorkDatabaseMigrations.Migration2To3 migration2To3 = new WorkDatabaseMigrations - .Migration2To3(mContext); + WorkDatabaseMigrations.WorkMigration migration2To3 = + new WorkDatabaseMigrations.WorkMigration(mContext, VERSION_2, VERSION_3); database = mMigrationTestHelper.runMigrationsAndValidate( TEST_DATABASE, @@ -207,6 +190,79 @@ public class WorkDatabaseMigrationTest { database.close(); } + @Test + @MediumTest + public void testMigrationVersion3To4() throws IOException { + SupportSQLiteDatabase database = + mMigrationTestHelper.createDatabase(TEST_DATABASE, VERSION_3); + + String oneTimeWorkSpecId = UUID.randomUUID().toString(); + long scheduleRequestedAt = System.currentTimeMillis(); + ContentValues oneTimeWorkSpecContentValues = contentValues(oneTimeWorkSpecId); + oneTimeWorkSpecContentValues.put("schedule_requested_at", scheduleRequestedAt); + + String periodicWorkSpecId = UUID.randomUUID().toString(); + ContentValues periodicWorkSpecContentValues = contentValues(periodicWorkSpecId); + periodicWorkSpecContentValues.put("interval_duration", 15 * 60 * 1000L); + + database.insert("workspec", CONFLICT_FAIL, oneTimeWorkSpecContentValues); + database.insert("workspec", CONFLICT_FAIL, periodicWorkSpecContentValues); + + database = mMigrationTestHelper.runMigrationsAndValidate( + TEST_DATABASE, + VERSION_4, + VALIDATE_DROPPED_TABLES, + MIGRATION_3_4); + + Cursor cursor = database.query("SELECT * from workspec"); + assertThat(cursor.getCount(), is(2)); + cursor.moveToFirst(); + assertThat(cursor.getString(cursor.getColumnIndex("id")), + is(oneTimeWorkSpecId)); + assertThat(cursor.getLong(cursor.getColumnIndex("schedule_requested_at")), + is(scheduleRequestedAt)); + cursor.moveToNext(); + assertThat(cursor.getString(cursor.getColumnIndex("id")), + is(periodicWorkSpecId)); + if (Build.VERSION.SDK_INT >= WorkManagerImpl.MIN_JOB_SCHEDULER_API_LEVEL) { + assertThat(cursor.getLong(cursor.getColumnIndex("schedule_requested_at")), + is(0L)); + } else { + assertThat(cursor.getLong(cursor.getColumnIndex("schedule_requested_at")), + is(WorkSpec.SCHEDULE_NOT_REQUESTED_YET)); + } + database.close(); + } + + @NonNull + private ContentValues contentValues(String workSpecId) { + ContentValues contentValues = new ContentValues(); + contentValues.put("id", workSpecId); + contentValues.put("state", WorkTypeConverters.StateIds.ENQUEUED); + contentValues.put("worker_class_name", TestWorker.class.getName()); + contentValues.put("input_merger_class_name", OverwritingInputMerger.class.getName()); + contentValues.put("input", Data.toByteArray(Data.EMPTY)); + contentValues.put("output", Data.toByteArray(Data.EMPTY)); + contentValues.put("initial_delay", 0L); + contentValues.put("interval_duration", 0L); + contentValues.put("flex_duration", 0L); + contentValues.put("required_network_type", false); + contentValues.put("requires_charging", false); + contentValues.put("requires_device_idle", false); + contentValues.put("requires_battery_not_low", false); + contentValues.put("requires_storage_not_low", false); + contentValues.put("content_uri_triggers", + WorkTypeConverters.contentUriTriggersToByteArray(new ContentUriTriggers())); + contentValues.put("run_attempt_count", 0); + contentValues.put("backoff_policy", + WorkTypeConverters.backoffPolicyToInt(BackoffPolicy.EXPONENTIAL)); + contentValues.put("backoff_delay_duration", WorkRequest.DEFAULT_BACKOFF_DELAY_MILLIS); + contentValues.put("period_start_time", 0L); + contentValues.put("minimum_retention_duration", 0L); + contentValues.put("schedule_requested_at", WorkSpec.SCHEDULE_NOT_REQUESTED_YET); + return contentValues; + } + private boolean checkExists(SupportSQLiteDatabase database, String tableName) { Cursor cursor = null; try { diff --git a/work/workmanager/src/main/java/androidx/work/impl/WorkDatabase.java b/work/workmanager/src/main/java/androidx/work/impl/WorkDatabase.java index e918906b113..853322fdb03 100644 --- a/work/workmanager/src/main/java/androidx/work/impl/WorkDatabase.java +++ b/work/workmanager/src/main/java/androidx/work/impl/WorkDatabase.java @@ -16,6 +16,9 @@ package androidx.work.impl; +import static androidx.work.impl.WorkDatabaseMigrations.MIGRATION_3_4; +import static androidx.work.impl.WorkDatabaseMigrations.VERSION_2; +import static androidx.work.impl.WorkDatabaseMigrations.VERSION_3; import static androidx.work.impl.model.WorkTypeConverters.StateIds.COMPLETED_STATES; import static androidx.work.impl.model.WorkTypeConverters.StateIds.ENQUEUED; import static androidx.work.impl.model.WorkTypeConverters.StateIds.RUNNING; @@ -56,7 +59,7 @@ import java.util.concurrent.TimeUnit; WorkTag.class, SystemIdInfo.class, WorkName.class}, - version = 3) + version = 4) @TypeConverters(value = {Data.class, WorkTypeConverters.class}) public abstract class WorkDatabase extends RoomDatabase { @@ -84,7 +87,7 @@ public abstract class WorkDatabase extends RoomDatabase { /** * Creates an instance of the WorkDatabase. * - * @param context A context (this method will use the application context from it) + * @param context A context (this method will use the application context from it) * @param useTestDatabase {@code true} to generate an in-memory database that allows main thread * access * @return The created WorkDatabase @@ -97,9 +100,12 @@ public abstract class WorkDatabase extends RoomDatabase { } else { builder = Room.databaseBuilder(context, WorkDatabase.class, DB_NAME); } + return builder.addCallback(generateCleanupCallback()) .addMigrations(WorkDatabaseMigrations.MIGRATION_1_2) - .addMigrations(new WorkDatabaseMigrations.Migration2To3(context)) + .addMigrations( + new WorkDatabaseMigrations.WorkMigration(context, VERSION_2, VERSION_3)) + .addMigrations(MIGRATION_3_4) .fallbackToDestructiveMigration() .build(); } diff --git a/work/workmanager/src/main/java/androidx/work/impl/WorkDatabaseMigrations.java b/work/workmanager/src/main/java/androidx/work/impl/WorkDatabaseMigrations.java index 86d503deb4c..d75b51473ea 100644 --- a/work/workmanager/src/main/java/androidx/work/impl/WorkDatabaseMigrations.java +++ b/work/workmanager/src/main/java/androidx/work/impl/WorkDatabaseMigrations.java @@ -19,9 +19,12 @@ package androidx.work.impl; import android.arch.persistence.db.SupportSQLiteDatabase; import android.arch.persistence.room.migration.Migration; import android.content.Context; +import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.RestrictTo; +import androidx.work.impl.model.WorkSpec; +import androidx.work.impl.model.WorkTypeConverters; import androidx.work.impl.utils.Preferences; /** @@ -37,9 +40,10 @@ public class WorkDatabaseMigrations { } // Known WorkDatabase versions - private static final int VERSION_1 = 1; - private static final int VERSION_2 = 2; - private static final int VERSION_3 = 3; + public static final int VERSION_1 = 1; + public static final int VERSION_2 = 2; + public static final int VERSION_3 = 3; + public static final int VERSION_4 = 4; private static final String CREATE_SYSTEM_ID_INFO = "CREATE TABLE IF NOT EXISTS `SystemIdInfo` (`work_spec_id` TEXT NOT NULL, `system_id`" @@ -50,6 +54,12 @@ public class WorkDatabaseMigrations { "INSERT INTO SystemIdInfo(work_spec_id, system_id) " + "SELECT work_spec_id, alarm_id AS system_id FROM alarmInfo"; + private static final String PERIODIC_WORK_SET_SCHEDULE_REQUESTED_AT = + "UPDATE workspec SET schedule_requested_at=0" + + " WHERE state NOT IN " + WorkTypeConverters.StateIds.COMPLETED_STATES + + " AND schedule_requested_at=" + WorkSpec.SCHEDULE_NOT_REQUESTED_YET + + " AND interval_duration<>0"; + private static final String REMOVE_ALARM_INFO = "DROP TABLE IF EXISTS alarmInfo"; /** @@ -69,13 +79,13 @@ public class WorkDatabaseMigrations { }; /** - * Migrates {@link WorkDatabase} version 2 to 3. + * A {@link WorkDatabase} migration that reschedules all eligible Workers. */ - public static class Migration2To3 extends Migration { + public static class WorkMigration extends Migration { final Context mContext; - public Migration2To3(@NonNull Context context) { - super(VERSION_2, VERSION_3); + public WorkMigration(@NonNull Context context, int startVersion, int endVersion) { + super(startVersion, endVersion); mContext = context; } @@ -85,4 +95,17 @@ public class WorkDatabaseMigrations { preferences.setNeedsReschedule(true); } } + + /** + * Marks {@code SCHEDULE_REQUESTED_AT} to something other than + * {@code SCHEDULE_NOT_REQUESTED_AT}. + */ + public static Migration MIGRATION_3_4 = new Migration(VERSION_3, VERSION_4) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + if (Build.VERSION.SDK_INT >= WorkManagerImpl.MIN_JOB_SCHEDULER_API_LEVEL) { + database.execSQL(PERIODIC_WORK_SET_SCHEDULE_REQUESTED_AT); + } + } + }; } diff --git a/work/workmanager/src/schemas/androidx.work.impl.WorkDatabase/4.json b/work/workmanager/src/schemas/androidx.work.impl.WorkDatabase/4.json new file mode 100644 index 00000000000..63c3005deda --- /dev/null +++ b/work/workmanager/src/schemas/androidx.work.impl.WorkDatabase/4.json @@ -0,0 +1,363 @@ +{ + "formatVersion": 1, + "database": { + "version": 4, + "identityHash": "c45e5fcbdf3824dead9778f19e2fd8af", + "entities": [ + { + "tableName": "Dependency", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`work_spec_id` TEXT NOT NULL, `prerequisite_id` TEXT NOT NULL, PRIMARY KEY(`work_spec_id`, `prerequisite_id`), FOREIGN KEY(`work_spec_id`) REFERENCES `WorkSpec`(`id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`prerequisite_id`) REFERENCES `WorkSpec`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "workSpecId", + "columnName": "work_spec_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "prerequisiteId", + "columnName": "prerequisite_id", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "work_spec_id", + "prerequisite_id" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_Dependency_work_spec_id", + "unique": false, + "columnNames": [ + "work_spec_id" + ], + "createSql": "CREATE INDEX `index_Dependency_work_spec_id` ON `${TABLE_NAME}` (`work_spec_id`)" + }, + { + "name": "index_Dependency_prerequisite_id", + "unique": false, + "columnNames": [ + "prerequisite_id" + ], + "createSql": "CREATE INDEX `index_Dependency_prerequisite_id` ON `${TABLE_NAME}` (`prerequisite_id`)" + } + ], + "foreignKeys": [ + { + "table": "WorkSpec", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "work_spec_id" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "WorkSpec", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "prerequisite_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "WorkSpec", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `state` INTEGER NOT NULL, `worker_class_name` TEXT NOT NULL, `input_merger_class_name` TEXT, `input` BLOB NOT NULL, `output` BLOB NOT NULL, `initial_delay` INTEGER NOT NULL, `interval_duration` INTEGER NOT NULL, `flex_duration` INTEGER NOT NULL, `run_attempt_count` INTEGER NOT NULL, `backoff_policy` INTEGER NOT NULL, `backoff_delay_duration` INTEGER NOT NULL, `period_start_time` INTEGER NOT NULL, `minimum_retention_duration` INTEGER NOT NULL, `schedule_requested_at` INTEGER NOT NULL, `required_network_type` INTEGER, `requires_charging` INTEGER NOT NULL, `requires_device_idle` INTEGER NOT NULL, `requires_battery_not_low` INTEGER NOT NULL, `requires_storage_not_low` INTEGER NOT NULL, `content_uri_triggers` BLOB, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "state", + "columnName": "state", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "workerClassName", + "columnName": "worker_class_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "inputMergerClassName", + "columnName": "input_merger_class_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "input", + "columnName": "input", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "output", + "columnName": "output", + "affinity": "BLOB", + "notNull": true + }, + { + "fieldPath": "initialDelay", + "columnName": "initial_delay", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "intervalDuration", + "columnName": "interval_duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "flexDuration", + "columnName": "flex_duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "runAttemptCount", + "columnName": "run_attempt_count", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "backoffPolicy", + "columnName": "backoff_policy", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "backoffDelayDuration", + "columnName": "backoff_delay_duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "periodStartTime", + "columnName": "period_start_time", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "minimumRetentionDuration", + "columnName": "minimum_retention_duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "scheduleRequestedAt", + "columnName": "schedule_requested_at", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "constraints.mRequiredNetworkType", + "columnName": "required_network_type", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "constraints.mRequiresCharging", + "columnName": "requires_charging", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "constraints.mRequiresDeviceIdle", + "columnName": "requires_device_idle", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "constraints.mRequiresBatteryNotLow", + "columnName": "requires_battery_not_low", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "constraints.mRequiresStorageNotLow", + "columnName": "requires_storage_not_low", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "constraints.mContentUriTriggers", + "columnName": "content_uri_triggers", + "affinity": "BLOB", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_WorkSpec_schedule_requested_at", + "unique": false, + "columnNames": [ + "schedule_requested_at" + ], + "createSql": "CREATE INDEX `index_WorkSpec_schedule_requested_at` ON `${TABLE_NAME}` (`schedule_requested_at`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "WorkTag", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tag` TEXT NOT NULL, `work_spec_id` TEXT NOT NULL, PRIMARY KEY(`tag`, `work_spec_id`), FOREIGN KEY(`work_spec_id`) REFERENCES `WorkSpec`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "tag", + "columnName": "tag", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "workSpecId", + "columnName": "work_spec_id", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "tag", + "work_spec_id" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_WorkTag_work_spec_id", + "unique": false, + "columnNames": [ + "work_spec_id" + ], + "createSql": "CREATE INDEX `index_WorkTag_work_spec_id` ON `${TABLE_NAME}` (`work_spec_id`)" + } + ], + "foreignKeys": [ + { + "table": "WorkSpec", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "work_spec_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "SystemIdInfo", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`work_spec_id` TEXT NOT NULL, `system_id` INTEGER NOT NULL, PRIMARY KEY(`work_spec_id`), FOREIGN KEY(`work_spec_id`) REFERENCES `WorkSpec`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "workSpecId", + "columnName": "work_spec_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "systemId", + "columnName": "system_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "work_spec_id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [ + { + "table": "WorkSpec", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "work_spec_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "WorkName", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `work_spec_id` TEXT NOT NULL, PRIMARY KEY(`name`, `work_spec_id`), FOREIGN KEY(`work_spec_id`) REFERENCES `WorkSpec`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "workSpecId", + "columnName": "work_spec_id", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "name", + "work_spec_id" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_WorkName_work_spec_id", + "unique": false, + "columnNames": [ + "work_spec_id" + ], + "createSql": "CREATE INDEX `index_WorkName_work_spec_id` ON `${TABLE_NAME}` (`work_spec_id`)" + } + ], + "foreignKeys": [ + { + "table": "WorkSpec", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "work_spec_id" + ], + "referencedColumns": [ + "id" + ] + } + ] + } + ], + "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, \"c45e5fcbdf3824dead9778f19e2fd8af\")" + ] + } +}
\ No newline at end of file |