/** * 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(); } }
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); }
@Override public BarEntry buildEntryFromResultObject(T realmObject, int xIndex) { DynamicRealmObject dynamicObject = new DynamicRealmObject(realmObject); if (dynamicObject.getFieldType(mValuesField) == RealmFieldType.LIST) { RealmList<DynamicRealmObject> list = dynamicObject.getList(mValuesField); float[] values = new float[list.size()]; int i = 0; for (DynamicRealmObject o : list) { values[i] = o.getFloat(mStackValueFieldName); i++; } return new BarEntry(values, mIndexField == null ? xIndex : dynamicObject.getInt(mIndexField)); } else { float value = dynamicObject.getFloat(mValuesField); return new BarEntry(value, mIndexField == null ? xIndex : dynamicObject.getInt(mIndexField)); } }
@Override public void onItemClickListener(final Position position) { final Object value = mDBController.getValue(position); if (value.getClass().equals(RealmList.class)) { alert("Value", "RealmList<" + ((DynamicRealmObject) ((RealmList) value).first()).getType() + ">", DataViewerActivity.this); } else { AlertEdit.buider(this) .setTitle(mDBController.getActiveTable().getColumns().get(position.x).getName()) .setContent(value.toString()) .setOnClickListener(new AlertEdit.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which, Editable text) { mDBController.alterValue(position, text.toString()); va.generateData(); va.refreshView(); } }).buildAndShow(); } }
private ArrayList<ArrayList<String>> createContent() { int row = mItens.size(); int column = mTable.getColumns().size(); ArrayList<ArrayList<String>> results = new ArrayList<>(); for (int i = 0; i < row; i++) { ArrayList<String> strings = new ArrayList<>(); DynamicRealmObject object = realm.where(mTable.getName()).findAll().get(i); for (int j = 0; j < column; j++) { String cel = ""; try { if (object.get(mTable.getColumns().get(j).getName()) != null) if (mTable.getColumns().get(j).getType() == RealmFieldType.LIST) { cel = "RealmList<" + object.getList(mTable.getColumns().get(j).getName()).first().getType() + '>'; } else { cel = object.get(mTable.getColumns().get(j).getName()).toString(); } } catch (NullPointerException e) { L.e("Except > row size: " + row + " column size: " + column + " " + i + "/" + j); } strings.add(cel); } results.add(strings); } return results; }
@Override public BarEntry buildEntryFromResultObject(T realmObject, float x) { DynamicRealmObject dynamicObject = new DynamicRealmObject(realmObject); if (dynamicObject.getFieldType(mYValuesField) == RealmFieldType.LIST) { RealmList<DynamicRealmObject> list = dynamicObject.getList(mYValuesField); float[] values = new float[list.size()]; int i = 0; for (DynamicRealmObject o : list) { values[i] = o.getFloat(mStackValueFieldName); i++; } return new BarEntry( mXValuesField == null ? x : dynamicObject.getFloat(mXValuesField), values); } else { float value = dynamicObject.getFloat(mYValuesField); return new BarEntry(mXValuesField == null ? x : dynamicObject.getFloat(mXValuesField), value); } }
@Override public Flowable<DynamicRealmObject> from(DynamicRealm realm, final DynamicRealmObject object) { final RealmConfiguration realmConfig = realm.getConfiguration(); return Flowable.create(new FlowableOnSubscribe<DynamicRealmObject>() { @Override public void subscribe(final FlowableEmitter<DynamicRealmObject> emitter) throws Exception { // Gets instance to make sure that the Realm is open for as long as the // Observable is subscribed to it. final DynamicRealm observableRealm = DynamicRealm.getInstance(realmConfig); objectRefs.get().acquireReference(object); final RealmChangeListener<DynamicRealmObject> listener = new RealmChangeListener<DynamicRealmObject>() { @Override public void onChange(DynamicRealmObject obj) { if (!emitter.isCancelled()) { emitter.onNext(obj); } } }; RealmObject.addChangeListener(object, listener); // Cleanup when stream is disposed emitter.setDisposable(Disposables.fromRunnable(new Runnable() { @Override public void run() { RealmObject.removeChangeListener(object, listener); observableRealm.close(); objectRefs.get().releaseReference(object); } })); // Emit current value immediately emitter.onNext(object); } }, BACK_PRESSURE_STRATEGY); }
@Override public Observable<ObjectChange<DynamicRealmObject>> changesetsFrom(DynamicRealm realm, final DynamicRealmObject object) { final RealmConfiguration realmConfig = realm.getConfiguration(); return Observable.create(new ObservableOnSubscribe<ObjectChange<DynamicRealmObject>>() { @Override public void subscribe(final ObservableEmitter<ObjectChange<DynamicRealmObject>> emitter) throws Exception { // Gets instance to make sure that the Realm is open for as long as the // Observable is subscribed to it. final DynamicRealm observableRealm = DynamicRealm.getInstance(realmConfig); objectRefs.get().acquireReference(object); final RealmObjectChangeListener<DynamicRealmObject> listener = new RealmObjectChangeListener<DynamicRealmObject>() { @Override public void onChange(DynamicRealmObject obj, ObjectChangeSet changeSet) { if (!emitter.isDisposed()) { emitter.onNext(new ObjectChange<>(obj, changeSet)); } } }; object.addChangeListener(listener); // Cleanup when stream is disposed emitter.setDisposable(Disposables.fromRunnable(new Runnable() { @Override public void run() { object.removeChangeListener(listener); observableRealm.close(); objectRefs.get().releaseReference(object); } })); // Emit current value immediately emitter.onNext(new ObjectChange<>(object, null)); } }); }
@Override public void apply(DynamicRealmObject obj) { // set timezone offset value long date = obj.getLong("date"); Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/Berlin")); cal.set(2017, Calendar.JANUARY, 30, 0, 0, 0); TimeZone timeZone; // the timezone during data aquisition was not saved before schema version 2, so we have to guess the correct value for old data if (date < cal.getTime().getTime()) { // before 30.01.2017 the only existing app installation was exclusively used in germany... timeZone = TimeZone.getTimeZone("Europe/Berlin"); } else { timeZone = TimeZone.getDefault(); // after that, use the device's current timezone } int timezoneOffsetInMinutes = timeZone.getOffset(date) / 1000 / 60; obj.set("timezoneOffsetInMinutes", timezoneOffsetInMinutes); }
@Override public void build(RealmResults<T> results) { for (T realmObject : results) { DynamicRealmObject dynamicObject = new DynamicRealmObject(realmObject); try { // normal entry float value = dynamicObject.getFloat(mValuesField); mValues.add(new BarEntry(value, dynamicObject.getInt(mIndexField))); } catch (IllegalArgumentException e) { // stacked entry RealmList<DynamicRealmObject> list = dynamicObject.getList(mValuesField); float[] values = new float[list.size()]; int i = 0; for (DynamicRealmObject o : list) { values[i] = o.getFloat(mStackValueFieldName); i++; } mValues.add(new BarEntry(values, dynamicObject.getInt(mIndexField))); } } calcStackSize(); }
@Override public BubbleEntry buildEntryFromResultObject(T realmObject, int xIndex) { DynamicRealmObject dynamicObject = new DynamicRealmObject(realmObject); return new BubbleEntry( mIndexField == null ? xIndex : dynamicObject.getInt(mIndexField), dynamicObject.getFloat(mValuesField), dynamicObject.getFloat(mSizeField)); }
public CandleEntry buildEntryFromResultObject(T realmObject, int xIndex) { DynamicRealmObject dynamicObject = new DynamicRealmObject(realmObject); return new CandleEntry( mIndexField == null ? xIndex : dynamicObject.getInt(mIndexField), dynamicObject.getFloat(mHighField), dynamicObject.getFloat(mLowField), dynamicObject.getFloat(mOpenField), dynamicObject.getFloat(mCloseField)); }
public void alterValue(final Position position, final String s) { mRealm.executeTransaction(new DynamicRealm.Transaction() { @Override public void execute(DynamicRealm realm) { DynamicRealmObject dynamicRealmObject = realm.where(mActiveTable.getName()) .findAll().get(position.y); dynamicRealmObject.set(mActiveTable.getColumns().get(position.x).getName(), s); } }); }
public void deleteRow(final Position position) { mRealm.executeTransaction(new DynamicRealm.Transaction() { @Override public void execute(DynamicRealm realm) { DynamicRealmObject object = realm.where(mActiveTable.getName()).findAll().get(position.y); object.deleteFromRealm(); } }); }
@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++; } }
@Override public BubbleEntry buildEntryFromResultObject(T realmObject, float x) { DynamicRealmObject dynamicObject = new DynamicRealmObject(realmObject); return new BubbleEntry( mXValuesField == null ? x : dynamicObject.getFloat(mXValuesField), dynamicObject.getFloat(mYValuesField), dynamicObject.getFloat(mSizeField)); }
@Override public CandleEntry buildEntryFromResultObject(T realmObject, float x) { DynamicRealmObject dynamicObject = new DynamicRealmObject(realmObject); return new CandleEntry( mXValuesField == null ? x : dynamicObject.getFloat(mXValuesField), dynamicObject.getFloat(mHighField), dynamicObject.getFloat(mLowField), dynamicObject.getFloat(mOpenField), dynamicObject.getFloat(mCloseField)); }
@Override public PieEntry buildEntryFromResultObject(T realmObject, float x) { DynamicRealmObject dynamicObject = new DynamicRealmObject(realmObject); if (mLabelField == null) { return new PieEntry(dynamicObject.getFloat(mYValuesField)); } else { return new PieEntry(dynamicObject.getFloat(mYValuesField), dynamicObject.getString(mLabelField)); } }
public S buildEntryFromResultObject(T realmObject, int xIndex) { DynamicRealmObject dynamicObject = new DynamicRealmObject(realmObject); return (S)new Entry(dynamicObject.getFloat(mValuesField), mIndexField == null ? xIndex : dynamicObject.getInt(mIndexField)); }
@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++; } }
public DynamicRealmObject getRow(Position position) { return mRealm.where(mActiveTable.getName()).findAll().get(position.y); }
public S buildEntryFromResultObject(T realmObject, float x) { DynamicRealmObject dynamicObject = new DynamicRealmObject(realmObject); return (S) new Entry(mXValuesField == null ? x : dynamicObject.getFloat(mXValuesField), dynamicObject.getFloat(mYValuesField)); }
@Override public RadarEntry buildEntryFromResultObject(T realmObject, float x) { DynamicRealmObject dynamicObject = new DynamicRealmObject(realmObject); return new RadarEntry(dynamicObject.getFloat(mYValuesField)); }
/** * Transforms the given Realm-ResultSet into a String array by using the provided xValuesField. * * @param result * @param xValuesField * @return */ public static List<String> toXVals(RealmResults<? extends RealmObject> result, String xValuesField) { List<String> xVals = new ArrayList<>(); for (RealmObject object : result) { DynamicRealmObject dynamicObject = new DynamicRealmObject(object); xVals.add(dynamicObject.getString(xValuesField)); } return xVals; }
/** * Transforms the given Realm-ResultSet into a String array by using the provided xValuesField. * * @param result * @param xValuesField * @return */ public static List<String> toXVals(RealmResults<? extends RealmObject> result, String xValuesField) { List<String> xVals = new ArrayList<String>(); for (RealmObject object : result) { DynamicRealmObject dynamicObject = new DynamicRealmObject(object); xVals.add(dynamicObject.getString(xValuesField)); } return xVals; }
/** * Creates a Flowable for a {@link DynamicRealmObject}. It should emit the initial object when subscribed to and * on each subsequent update of the object. * <p> * DynamicRealmObject observables are hot as DynamicRealmObjects automatically are kept up to date. * * @param object DynamicRealmObject to listen to changes for. * @param realm {@link DynamicRealm} instance object is coming from. */ Flowable<DynamicRealmObject> from(DynamicRealm realm, DynamicRealmObject object);
/** * Creates an Observable for a {@link RealmObject}. It should emit the initial object when subscribed to and on each * subsequent update of the object it should emit the object + the {@link io.realm.ObjectChangeSet} that describes * the update. * <p> * Changeset observables do not support backpressure as a changeset depends on the state of the previous * changeset. Handling backpressure should therefore be left to the user. * * @param object RealmObject to listen to changes for. * @param realm {@link Realm} instance object is coming from. */ Observable<ObjectChange<DynamicRealmObject>> changesetsFrom(DynamicRealm realm, DynamicRealmObject object);