/** * This test surfaces a bunch of problems, most of them seem to be around caching of the schema * during a transaction * * 1) Removing the primary key do not invalidate the cache in RealmSchema and those cached * are ImmutableRealmObjectSchema so do not change when the primary key is removed. * * 2) Addding `schema.refresh()` to RealmObjectSchema.removePrimaryKey()` causes * RealmPrimaryKeyConstraintException anyway. Unclear why. */ @Test public void removingPrimaryKeyRemovesConstraint_typeSetters() { RealmConfiguration config = configFactory.createConfigurationBuilder() .name("removeConstraints").build(); DynamicRealm realm = DynamicRealm.getInstance(config); RealmSchema realmSchema = realm.getSchema(); realm.beginTransaction(); RealmObjectSchema tableSchema = realmSchema.create("Employee") .addField("name", String.class, FieldAttribute.PRIMARY_KEY); realm.createObject("Employee", "Foo"); DynamicRealmObject obj = realm.createObject("Employee", "Foo2"); try { // Tries to create 2nd entry with name Foo. obj.setString("name", "Foo"); } catch (IllegalArgumentException e) { tableSchema.removePrimaryKey(); obj.setString("name", "Foo"); } finally { realm.close(); } }
@Override public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { // During a migration, a DynamicRealm is exposed. A DynamicRealm is an untyped variant of a normal Realm, but // with the same object creation and query capabilities. // A DynamicRealm uses Strings instead of Class references because the Classes might not even exist or have been // renamed. // Access the Realm schema in order to create, modify or delete classes and their fields. RealmSchema schema = realm.getSchema(); // Migrate from version 0 to version 1 if (oldVersion == 0) { oldVersion++; } // Migrate from version 1 to version 2 if (oldVersion == 1) { RealmObjectSchema bloodGlucoseDataSchema = schema.get("BloodGlucoseData"); bloodGlucoseDataSchema .addField("timezoneOffsetInMinutes", int.class) .transform(timezoneTransformFunction); //oldVersion++; } }
private static void changeFieldType(RealmObjectSchema objectSchema, String fieldName, Class newType, @Nullable FieldAttribute attribute, Action3<DynamicRealmObject, String, String> transformation) { String tempFieldName = fieldName + "_temp"; if (attribute != null) { if (attribute == FieldAttribute.PRIMARY_KEY && objectSchema.hasPrimaryKey()) { // remove existing primary key objectSchema.removePrimaryKey(); } objectSchema.addField(tempFieldName, newType, attribute); } else { objectSchema.addField(tempFieldName, newType); } objectSchema .transform(obj -> { transformation.call(obj, fieldName, tempFieldName); }) .removeField(fieldName) .renameField(tempFieldName, fieldName); }
private List<TableStructure> loadTables() { if (!isLoaded) { for (RealmObjectSchema tables : mRealm.getSchema().getAll()) { TableStructure table = new TableStructure(); table.setName(tables.getClassName()); List<Column> columns = new ArrayList<>(); for (String f : tables.getFieldNames()) { Column column = new Column(); column.setName(f); column.setRequired(tables.isRequired(f)); if (tables.hasPrimaryKey()) { column.setPrimaryKey(tables.isPrimaryKey(f)); } column.setType(tables.getFieldType(f)); columns.add(column); } table.setColumns(columns); this.mTables.add(table); } String s = new Gson().toJson(mTables); L.i("execute: " + s); } return mTables; }
@Override public void migrate(DynamicRealm dynamicRealm, long oldVersion, long newVersion) { if (oldVersion == 0) { dynamicRealm.getSchema().get("Invitation").addField("email", String.class); oldVersion++; } if (oldVersion == 1) { dynamicRealm.getSchema().get("Message").addField("receiptorsStr", String.class); dynamicRealm.getSchema().get("Member").addField("service", String.class); dynamicRealm.getSchema().create("IdeaDraft") .addField("title", String.class) .addField("description", String.class); dynamicRealm.getSchema().rename("TeamInfo", "Team"); dynamicRealm.getSchema().get("Team").addField("source", String.class); dynamicRealm.getSchema().get("Team").addField("sourceId", String.class); dynamicRealm.getSchema().get("Team").addField("signCode", String.class); dynamicRealm.getSchema().get("Team").addField("inviteCode", String.class); dynamicRealm.getSchema().get("Team").addField("inviteUrl", String.class); dynamicRealm.getSchema().get("Team").addField("isQuit", boolean.class); dynamicRealm.getSchema().get("Team").addField("nonJoinable", boolean.class); dynamicRealm.getSchema().get("Team").addField("hasUnread", boolean.class); dynamicRealm.getSchema().get("Team").addField("unread", int.class); dynamicRealm.getSchema().get("Team").addPrimaryKey("_id"); RealmObjectSchema roomSchema = dynamicRealm.getSchema().get("Room"); dynamicRealm.getSchema().get("Notification").addRealmObjectField("room", roomSchema); RealmObjectSchema memberSchema = dynamicRealm.getSchema().get("Member"); dynamicRealm.getSchema().get("Notification").addRealmObjectField("member", memberSchema); RealmObjectSchema storySchema = dynamicRealm.getSchema().get("Story"); dynamicRealm.getSchema().get("Notification").addRealmObjectField("story", storySchema); oldVersion++; } }
@Override public void migrate(final DynamicRealm realm, long oldVersion, long newVersion) { // During a migration, a DynamicRealm is exposed. A DynamicRealm is an untyped variant of a normal Realm, but // with the same object creation and query capabilities. // A DynamicRealm uses Strings instead of Class references because the Classes might not even exist or have been // renamed. // Access the Realm schema in order to create, modify or delete classes and their fields. RealmSchema schema = realm.getSchema(); if(oldVersion==1){ RealmObjectSchema settingSchema = schema.get("Setting"); settingSchema.addField("locale",String.class) .transform(new RealmObjectSchema.Function() { @Override public void apply(DynamicRealmObject obj) { obj.set("locale","Auto"); } }); oldVersion++; } if(oldVersion==2){ RealmObjectSchema cacheSchema = schema.get("NetWorkCache"); cacheSchema.removeField("record").addField("record",String.class); oldVersion++; } }
public void showTableStructure(DynamicRealm dynamicRealm) { RealmObjectSchema realmObjectSchema = dynamicRealm.getSchema().get(simpleTableName); Set<String> fieldNames = realmObjectSchema.getFieldNames(); stringBuilder.append("<div class=\"content\">").append("<table class=\"dataTable\">") .append("<th>Column Name</th><th>Type</th>"); for (String fieldName : fieldNames) { RealmFieldType realmFieldType = realmObjectSchema.getFieldType(fieldName); stringBuilder.append("<tr>") .append("<td>").append(fieldName).append("</td>") .append("<td>").append(realmFieldType.name()).append("</td>") .append("</tr>"); } stringBuilder.append("</table></div>"); }
private static void matchMigratedField(RealmObjectSchema objectSchema, String modelFieldName, Field field) { boolean isIndexed = false; boolean isRequired = false; boolean isPrimaryKey = false; if(field.isAnnotationPresent(Index.class)) { isIndexed = true; } if(field.isAnnotationPresent(Required.class)) { isRequired = true; } if(field.isAnnotationPresent(PrimaryKey.class)) { isPrimaryKey = true; } if(isPrimaryKey && !objectSchema.isPrimaryKey(modelFieldName)) { if(objectSchema.hasPrimaryKey()) { objectSchema.removePrimaryKey(); } objectSchema.addPrimaryKey(modelFieldName); } if(!isPrimaryKey && objectSchema.isPrimaryKey(modelFieldName)) { objectSchema.removePrimaryKey(); } // index management must be after primary key because removePrimaryKey() removes index as well. if((isIndexed || isPrimaryKey) && !objectSchema.hasIndex(modelFieldName)) { objectSchema.addIndex(modelFieldName); } if(!isIndexed && !isPrimaryKey /* primary key is indexed by default! */ && objectSchema.hasIndex(modelFieldName)) { objectSchema.removeIndex(modelFieldName); } if(isNonNullPrimitive(field.getType())) { if(!objectSchema.isRequired(modelFieldName)) { objectSchema.setNullable(modelFieldName, false); } } else { if(isRequired && objectSchema.isNullable(modelFieldName)) { objectSchema.setNullable(modelFieldName, false); } if(!isRequired && !objectSchema.isNullable(modelFieldName)) { objectSchema.setNullable(modelFieldName, true); } } }
@Override public void migrate(@NonNull final DynamicRealm realm, long oldVersion, long newVersion) { Log.d(TAG, "Starting migration from " + oldVersion + " to " + newVersion); // Migration from versions < 9 not supported, versions prior 9 were missing the // contentHash for items if(oldVersion < 9) { throw new IllegalStateException("Migration from Schema < 9 not supported"); } RealmSchema schema = realm.getSchema(); /* 9 -> 10 - Add primary key ID to TemporaryFeed - Rename TemporaryFeed id to treeItemId - add TemporaryFeed object for list and pager activities */ if(oldVersion == 9) { realm.delete("TemporaryFeed"); final RealmObjectSchema temporaryFeedSchema = schema.get("TemporaryFeed"); if(temporaryFeedSchema == null) throw new IllegalStateException("TemporaryFeed schema not found"); temporaryFeedSchema .renameField(TemporaryFeed.ID, TemporaryFeed.TREE_ITEM_ID) .addField(TemporaryFeed.ID, long.class, FieldAttribute.PRIMARY_KEY); realm.createObject("TemporaryFeed", TemporaryFeed.LIST_ID); realm.createObject("TemporaryFeed", TemporaryFeed.PAGER_ID); oldVersion++; } /* 10 -> 11 - Make sure every item has updatedAt != null, set updatedAt = pubDate if not */ if(oldVersion == 10) { for(DynamicRealmObject object: realm.where("Item").isNull(Item.UPDATED_AT).findAll()) { object.setDate(Item.UPDATED_AT, object.getDate(Item.PUB_DATE)); } oldVersion++; } /* 11 -> 12 - Add active property to Item */ if(oldVersion == 11) { final RealmObjectSchema itemSchema = schema.get("Item"); if(itemSchema == null) throw new IllegalStateException("Item schema not found"); itemSchema .addField(Item.ACTIVE, boolean.class, FieldAttribute.INDEXED); //noinspection UnusedAssignment oldVersion++; } }