/* * Copyright 2017 Realm Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.realm; import io.realm.internal.Collection; import io.realm.internal.UncheckedRow; /** * An {@link OrderedRealmCollectionSnapshot} is a special type of {@link OrderedRealmCollection}. It can be created by * calling {@link OrderedRealmCollection#createSnapshot()}. Unlike {@link RealmResults} and {@link RealmList}, its * size and order of elements will never be changed after creation. * <p> * {@link OrderedRealmCollectionSnapshot} is useful when making changes which may impact the size or order of the * collection in simple loops. For example: * <pre> * {@code * final RealmResults<Dog> dogs = realm.where(Dog.class).findAll(); * final OrderedRealmCollectionSnapshot<Dog> snapshot = dogs.createSnapshot(); * final int dogsCount = snapshot.size(); // dogs.size() == snapshot.size() == 10 * realm.executeTransaction(new Realm.Transaction() { * /@Override * public void execute(Realm realm) { * for (int i = 0; i < dogsCount; i++) { * // This won't work since RealmResults is always up-to-date, its size gets decreased by 1 after every loop. An * // IndexOutOfBoundsException will be thrown after 5 loops. * // dogs.deleteFromRealm(i); * snapshot.deleteFromRealm(i); // Deletion on OrderedRealmCollectionSnapshot won't change the size of it. * } * } * }); * } * </pre> */ public class OrderedRealmCollectionSnapshot<E extends RealmModel> extends OrderedRealmCollectionImpl<E> { private int size = -1; OrderedRealmCollectionSnapshot(BaseRealm realm, Collection collection, Class<E> clazz) { super(realm, collection.createSnapshot(), clazz); } OrderedRealmCollectionSnapshot(BaseRealm realm, Collection collection, String className) { super(realm, collection.createSnapshot(), className); } /** * {@inheritDoc} */ @Override public int size() { // Optimization for simple loops. The size of snapshot will never be changed. if (size == -1) { size = super.size(); } return size; } /** * Not supported by {@link OrderedRealmCollectionSnapshot}. Use 'sort()' on the original * {@link OrderedRealmCollection} instead. * * @throws UnsupportedOperationException */ @Override public RealmResults<E> sort(String fieldName) { throw getUnsupportedException("sort"); } /** * Not supported by {@link OrderedRealmCollectionSnapshot}. Use 'sort()' on the original * {@link OrderedRealmCollection} instead. * * @throws UnsupportedOperationException */ @Override public RealmResults<E> sort(String fieldName, Sort sortOrder) { throw getUnsupportedException("sort"); } /** * Not supported by {@link OrderedRealmCollectionSnapshot}. Use 'sort()' on the original * {@link OrderedRealmCollection} instead. * * @throws UnsupportedOperationException */ @Override public RealmResults<E> sort(String fieldName1, Sort sortOrder1, String fieldName2, Sort sortOrder2) { throw getUnsupportedException("sort"); } /** * Not supported by {@link OrderedRealmCollectionSnapshot}. Use 'sort()' on the original * {@link OrderedRealmCollection} instead. * * @throws UnsupportedOperationException */ @Override public RealmResults<E> sort(String[] fieldNames, Sort[] sortOrders) { throw getUnsupportedException("sort"); } /** * Not supported by {@link OrderedRealmCollectionSnapshot}. Use 'where()' on the original * {@link OrderedRealmCollection} instead. * * @throws UnsupportedOperationException */ @Deprecated @Override public RealmQuery<E> where() { throw getUnsupportedException("where"); } private UnsupportedOperationException getUnsupportedException(String methodName) { return new UnsupportedOperationException( String.format("'%s()' is not supported by OrderedRealmCollectionSnapshot. " + "Call '%s()' on the original 'RealmCollection' instead.", methodName, methodName)); } /** * {@inheritDoc} */ @Override public boolean isLoaded() { return true; } /** * {@inheritDoc} */ @Override public boolean load() { return true; } /** * {@inheritDoc} */ @Override public OrderedRealmCollectionSnapshot<E> createSnapshot() { realm.checkIfValid(); return this; } /** * Deletes the object at the given index from the Realm. The object at the given index will become invalid. Just * returns if the object is invalid already. * * @param location the array index identifying the object to be removed. * @throws IndexOutOfBoundsException if {@code location < 0 || location >= size()}. * @throws java.lang.IllegalStateException if the Realm is closed or the method is called from the wrong thread. */ @Override public void deleteFromRealm(int location) { realm.checkIfValidAndInTransaction(); UncheckedRow row = collection.getUncheckedRow(location); if (row.isAttached()) { collection.delete(location); } } /** * Deletes the first object from the Realm. The first object will become invalid. * * @return {@code true} if an object was deleted, {@code false} otherwise. * @throws java.lang.IllegalStateException if the Realm is closed or the method is called on the wrong thread. */ @Override public boolean deleteFirstFromRealm() { realm.checkIfValidAndInTransaction(); UncheckedRow row = collection.firstUncheckedRow(); return row != null && row.isAttached() && collection.deleteFirst(); } /** * Deletes the last object from the Realm. The last object will become invalid. * * @return {@code true} if an object was deleted, {@code false} otherwise. * @throws java.lang.IllegalStateException if the Realm is closed or the method is called from the wrong thread. */ @Override public boolean deleteLastFromRealm() { realm.checkIfValidAndInTransaction(); UncheckedRow row = collection.lastUncheckedRow(); return row != null && row.isAttached() && collection.deleteLast(); } /** * This deletes all objects in the collection from the underlying Realm. All objects in the collection snapshot * will become invalid. * * @return {@code true} if objects was deleted, {@code false} otherwise. * @throws IllegalStateException if the corresponding Realm is closed or in an incorrect thread. * @throws java.lang.IllegalStateException if the Realm has been closed or called from an incorrect thread. */ @Override public boolean deleteAllFromRealm() { return super.deleteAllFromRealm(); } }