{"action":"created","comment":{"url":"https://api.github.com/repos/realm/realm-java/pulls/comments/31538612","id":31538612,"diff_hunk":"@@ -0,0 +1,776 @@\n+/*\n+ * Copyright 2015 Realm Inc.\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ * http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+package io.realm.android;\n+\n+import android.content.ContentResolver;\n+import android.database.CharArrayBuffer;\n+import android.database.ContentObservable;\n+import android.database.ContentObserver;\n+import android.database.Cursor;\n+import android.database.CursorIndexOutOfBoundsException;\n+import android.database.DataSetObservable;\n+import android.database.DataSetObserver;\n+import android.net.Uri;\n+import android.os.Bundle;\n+\n+import io.realm.Realm;\n+import io.realm.RealmChangeListener;\n+import io.realm.RealmResults;\n+import io.realm.internal.ColumnType;\n+import io.realm.internal.TableOrView;\n+\n+/**\n+ * This class exposes {@link io.realm.RealmResults} as a cursor.\n+ * <p>\n+ * A RealmCursor has the same thread restrictions as RealmResults, so it is not possible to move a RealmCursor between\n+ * threads.\n+ * <p>\n+ * A RealmCursor is currently limited to only being able to display data from a single RealmClass, i.e. it is not\n+ * possible to follow links to other objects.\n+ */\n+public class RealmCursor implements Cursor {\n+\n+    private static final String DEFAULT_ID_COLUMN = \"_id\";\n+\n+    // Needed because constants are only available from API 11\n+    private static final int FIELD_TYPE_NULL;\n+    private static final int FIELD_TYPE_INTEGER;\n+    private static final int FIELD_TYPE_FLOAT;\n+    private static final int FIELD_TYPE_STRING;\n+    private static final int FIELD_TYPE_BLOB;\n+    static {\n+        if (android.os.Build.VERSION.SDK_INT >= 11) {\n+            FIELD_TYPE_NULL = Cursor.FIELD_TYPE_NULL;\n+            FIELD_TYPE_INTEGER = Cursor.FIELD_TYPE_INTEGER;\n+            FIELD_TYPE_FLOAT = Cursor.FIELD_TYPE_FLOAT;\n+            FIELD_TYPE_STRING = Cursor.FIELD_TYPE_STRING;\n+            FIELD_TYPE_BLOB = Cursor.FIELD_TYPE_BLOB;\n+        } else {\n+            FIELD_TYPE_NULL = 0;\n+            FIELD_TYPE_INTEGER = 1;\n+            FIELD_TYPE_FLOAT = 2;\n+            FIELD_TYPE_STRING = 3;\n+            FIELD_TYPE_BLOB = 4;\n+        }\n+    }\n+\n+    private final Realm realm;\n+    private TableOrView table;\n+    private int rowIndex;\n+    private boolean closed;\n+    private long idColumnIndex = -1; // Column index for the \"_id\" field. -1 means it hasn't been set\n+    private final DataSetObservable dataSetObservable = new DataSetObservable();\n+    private final ContentObservable contentObservable = new ContentObservable();\n+    private RealmChangeListener changeListener = new RealmChangeListener() {\n+        @Override\n+        public void onChange() {\n+            if (dataSetObservable != null) {\n+                dataSetObservable.notifyChanged(); // TODO Should be replaced with something more fine grained.\n+            }\n+        }\n+    };\n+\n+\n+    /**\n+     * Exposes a query result as a cursor. Use {@link RealmResults#getCursor()} instead of this\n+     * constructor\n+     *\n+     * @param table Table view representing the query results.\n+     */\n+    public RealmCursor(Realm realm, TableOrView table) {\n+        this.table = table;\n+        this.rowIndex = -1;\n+        this.realm = realm;\n+        realm.addChangeListener(changeListener);\n+    }\n+\n+    /**\n+     * Returns the numbers of rows in the cursor.\n+     *\n+     * @return the number of rows in the cursor.\n+     */\n+    @Override\n+    public int getCount() {\n+        checkClosed();\n+        return (int) table.size();\n+    }\n+\n+    /**\n+     * Returns the current position of the cursor in the row set.\n+     * The value is zero-based. When the row set is first returned the cursor\n+     * will be at position -1, which is before the first row. After the\n+     * last row is returned another call to {@link #moveToNext()} will leave the cursor past\n+     * the last entry, at a position of count().\n+     *\n+     * @return the current cursor position.\n+     */\n+    @Override\n+    public int getPosition() {\n+        checkClosed();\n+        return rowIndex;\n+    }\n+\n+    /**\n+     * Moves the cursor by a relative amount, forward or backward, from the\n+     * current position. Positive offsets move forwards, negative offsets move\n+     * backwards. If the calculated position is outside of the bounds of the result\n+     * set then the new position will be pinned to -1 or {@link #getCount()} depending\n+     * on whether the value is off the front or end of the set, respectively.\n+     *\n+     * <p>This method will return true if the requested destination is\n+     * reachable, otherwise, it returns false. For example, if the cursor is currently\n+     * at the second entry in the result set and move(-5) is called,\n+     * the position will be pinned at -1, and false will be returned.\n+     *\n+     * @param offset the offset to be applied from the current position.\n+     * @return whether the requested move fully succeeded.\n+     */\n+    @Override\n+    public final boolean move(int offset) {\n+        checkClosed();\n+        return moveToPosition(rowIndex + offset);\n+    }\n+\n+    /**\n+     * Moves the cursor to an absolute position. The valid\n+     * range of values is -1 &lt;= position &lt;= count.\n+     *\n+     * <p>This method will return true if the request destination is reachable,\n+     * otherwise, it returns false.\n+     *\n+     * @param position the zero-based position to move to.\n+     * @return whether the requested move fully succeeded.\n+     */\n+    @Override\n+    public boolean moveToPosition(int position) {\n+        checkClosed();\n+\n+        // Verify position is not beyond the end of the cursor.\n+        // This also captures moveToPosition(0) for the empty cursor.\n+        final int count = getCount();\n+        if (position >= count) {\n+            rowIndex = count;\n+            return false;\n+        }\n+\n+        // Verify position is not before the start of the cursor.\n+        if (position < 0) {\n+            rowIndex = -1;\n+            return false;\n+        }\n+\n+        rowIndex = position;\n+        return true;\n+    }\n+\n+    /**\n+     * Moves the cursor to the first row.\n+     *\n+     * <p>This method will return false if the cursor is empty.\n+     *\n+     * @return whether the move succeeded.\n+     */\n+    @Override\n+    public boolean moveToFirst() {\n+        return moveToPosition(0);\n+    }\n+\n+    /**\n+     * Moves the cursor to the last row.\n+     *\n+     * <p>This method will return false if the cursor is empty.\n+     *\n+     * @return whether the move succeeded.\n+     */\n+    @Override\n+    public boolean moveToLast() {\n+        return moveToPosition(getCount() - 1);\n+    }\n+\n+    /**\n+     * Moves the cursor to the next row.\n+     *\n+     * <p>This method will return false if the cursor is already past the\n+     * last entry in the result set.\n+     *\n+     * @return whether the move succeeded.\n+     */\n+    @Override\n+    public boolean moveToNext() {\n+        return moveToPosition(rowIndex + 1);\n+    }\n+\n+    /**\n+     * Moves the cursor to the previous row.\n+     *\n+     * <p>This method will return false if the cursor is already before the\n+     * first entry in the result set.\n+     *\n+     * @return whether the move succeeded.\n+     */\n+    @Override\n+    public boolean moveToPrevious() {\n+        return moveToPosition(rowIndex - 1);\n+    }\n+\n+    /**\n+     * Returns whether the cursor is pointing to the first row.\n+     *\n+     * @return whether the cursor is pointing at the first entry.\n+     */\n+    @Override\n+    public boolean isFirst() {\n+        checkClosed();\n+        return rowIndex == 0 && getCount() != 0;\n+    }\n+\n+    /**\n+     * Returns whether the cursor is pointing to the last row.\n+     *\n+     * @return whether the cursor is pointing at the last entry.\n+     */\n+    @Override\n+    public boolean isLast() {\n+        checkClosed();\n+        int count = getCount();\n+        return rowIndex == (count - 1) && count != 0;\n+    }\n+\n+    /**\n+     * Returns whether the cursor is pointing to the position before the first\n+     * row.\n+     *\n+     * @return whether the cursor is before the first result.\n+     */\n+    @Override\n+    public boolean isBeforeFirst() {\n+        checkClosed();\n+        if (getCount() == 0) {\n+            return true;\n+        }\n+        return rowIndex == -1;\n+    }\n+\n+    /**\n+     * Returns whether the cursor is pointing to the position after the last\n+     * row.\n+     *\n+     * @return whether the cursor is after the last result.\n+     */\n+    @Override\n+    public boolean isAfterLast() {\n+        checkClosed();\n+        if (getCount() == 0) {\n+            return true;\n+        }\n+        return rowIndex == getCount();\n+    }\n+\n+    /**\n+     * Returns the zero-based index for the given field name, or -1 if the field doesn't exist.\n+     * If you expect the field to exist use {@link #getColumnIndexOrThrow(String)} instead, which\n+     * will make the error more clear.\n+     *\n+     * @param fieldName the name of the target field.\n+     * @return the zero-based column index for the given column field, or -1 if\n+     * the field name does not exist.\n+     * @see #getColumnIndexOrThrow(String)\n+     */\n+    @Override\n+    public int getColumnIndex(String fieldName) {\n+        checkClosed();\n+        if (DEFAULT_ID_COLUMN.equals(fieldName)) {\n+            return (int) idColumnIndex;\n+        }\n+        return (int) table.getColumnIndex(fieldName);\n+    }\n+\n+    /**\n+     * Returns the zero-based index for the given field name, or throws\n+     * {@link IllegalArgumentException} if the field doesn't exist. If you're not sure if\n+     * a field will exist or not, then use {@link #getColumnIndex(String)} and check for -1. This\n+     * is more efficient than catching the exceptions.\n+     *\n+     * @param fieldName the name of the target column.\n+     * @return the zero-based column index for the given field name\n+     * @see #getColumnIndex(String)\n+     * @throws IllegalArgumentException if the column does not exist\n+     */\n+    @Override\n+    public int getColumnIndexOrThrow(String fieldName) throws IllegalArgumentException {\n+        checkClosed();\n+\n+        int index;\n+        if (DEFAULT_ID_COLUMN.equals(fieldName)) {\n+            index = (int) idColumnIndex;\n+        } else {\n+            index = (int) table.getColumnIndex(fieldName);\n+        }\n+        if (index == TableOrView.NO_MATCH) {\n+            throw new IllegalArgumentException(fieldName + \" not found in this cursor.\");\n+        }\n+        return index;\n+    }\n+\n+    /**\n+     * Returns the column name at the given zero-based column index.\n+     *\n+     * @param columnIndex the zero-based index of the target column.\n+     * @return the column name for the given column index.\n+     */\n+    @Override\n+    public String getColumnName(int columnIndex) {\n+        checkClosed();\n+        return table.getColumnName(columnIndex);\n+    }\n+\n+    /**\n+     * Returns a string array holding the names of all of the columns in the\n+     * result set in the order in which they were listed in the result.\n+     *\n+     * @return the names of the columns returned in this query.\n+     */\n+    @Override\n+    public String[] getColumnNames() {\n+        checkClosed();\n+        int columns = (int) table.getColumnCount();\n+        String[] columnNames = new String[columns];\n+        for (int i = 0; i < columns; i++) {\n+            columnNames[i] = table.getColumnName(i);\n+        }\n+        return columnNames;\n+    }\n+\n+    /**\n+     * Return total number of columns\n+     * @return number of columns\n+     */\n+    @Override\n+    public int getColumnCount() {\n+        checkClosed();\n+        return (int) table.getColumnCount();\n+    }\n+\n+    /**\n+     * Returns the value of the requested column as a byte array.\n+     *\n+     * @param columnIndex the zero-based index of the target column.\n+     * @return the value of that column as a byte array.\n+     * @throws IllegalArgumentException if the requested column is not a byte array.\n+     */\n+    @Override\n+    public byte[] getBlob(int columnIndex) {\n+        checkClosed();\n+        checkPosition();\n+        return table.getBinaryByteArray(columnIndex, rowIndex);\n+    }\n+\n+    /**\n+     * Returns the value of the requested column as a String.\n+     *\n+     * @param columnIndex the zero-based index of the target column.\n+     * @return the value of that column as a String.\n+     * @throws IllegalArgumentException if the requested column is not a String.\n+     */\n+    @Override\n+    public String getString(int columnIndex) {\n+        checkClosed();\n+        checkPosition();\n+        return table.getString(columnIndex, rowIndex);\n+    }\n+\n+    /**\n+     * Retrieves the requested column text and stores it in the buffer provided.\n+     * If the buffer size is not sufficient, a new char buffer will be allocated\n+     * and assigned to CharArrayBuffer.data\n+     * @param columnIndex the zero-based index of the target column.\n+     *        if the target column is null, return buffer\n+     * @param buffer the buffer to copy the text into.\n+     * @throws IllegalArgumentException if the requested column is not a String.\n+     */\n+    @Override\n+    public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {\n+        checkClosed();\n+        checkPosition();\n+        String result = getString(columnIndex);\n+        if (result != null) {\n+            char[] data = buffer.data;\n+            if (data == null || data.length < result.length()) {\n+                buffer.data = result.toCharArray();\n+            } else {\n+                result.getChars(0, result.length(), data, 0);\n+            }\n+            buffer.sizeCopied = result.length();\n+        } else {\n+            buffer.sizeCopied = 0;\n+        }\n+    }\n+\n+    /**\n+     * Returns the value of the requested column as a short.\n+     *\n+     * <p>Integer values outside the range [<code>Short.MIN_VALUE</code>,\n+     * <code>Short.MAX_VALUE</code>] will overflow.\n+     *\n+     * @param columnIndex the zero-based index of the target column.\n+     * @return the value of that column as a short.\n+     * @throws IllegalArgumentException if the requested column is not a short, int or long.\n+     */\n+    @Override\n+    public short getShort(int columnIndex) {\n+        checkClosed();\n+        checkPosition();\n+        return (short) mapRealmTypeToCursor(columnIndex, false);\n+    }\n+\n+    /**\n+     * Returns the value of the requested column as an int.\n+     *\n+     * <p>Integer values outside the range [<code>Integer.MIN_VALUE</code>,\n+     * <code>Integer.MAX_VALUE</code>] will overflow.\n+     *\n+     * @param columnIndex the zero-based index of the target column.\n+     * @return the value of that column as an int.\n+     * @throws IllegalArgumentException if the requested column is not a short, int or long.\n+     */\n+    @Override\n+    public int getInt(int columnIndex) {\n+        checkClosed();\n+        checkPosition();\n+        return (int) mapRealmTypeToCursor(columnIndex, false);\n+    }\n+\n+    /**\n+     * Returns the value of the requested column as a long.\n+     *\n+     * @param columnIndex the zero-based index of the target column.\n+     * @return the value of that column as a long.\n+     * @throws IllegalArgumentException if the requested column is not a short, int or long.\n+     */\n+    @Override\n+    public long getLong(int columnIndex) {\n+        checkClosed();\n+        checkPosition();\n+        return mapRealmTypeToCursor(columnIndex, true);\n+    }\n+\n+    private long mapRealmTypeToCursor(int columnIndex, boolean acceptLong) {\n+        ColumnType type = table.getColumnType(columnIndex);\n+        switch (type) {\n+            case BOOLEAN: return table.getBoolean(columnIndex, rowIndex) ? 1 : 0;\n+            case INTEGER: return table.getLong(columnIndex, rowIndex);\n+            case DATE:\n+                if (!acceptLong) {\n+                    throw new IllegalArgumentException(\"Use getLong() instead to get date values.\");\n+                } else {\n+                    return table.getDate(columnIndex, rowIndex).getTime();\n+                }\n+            default:\n+                throw new IllegalArgumentException(String.format(\"Column at index  %s is not a Boolean or an Integer but a %s\",\n+                        columnIndex, type));\n+        }\n+    }\n+\n+    /**\n+     * Returns the value of the requested column as a float. Note that {@link #getType(int)} will return\n+     * {@link Cursor#FIELD_TYPE_FLOAT} for both {@code float} and {@code double} columns.\n+     *\n+     * @param columnIndex the zero-based index of the target column.\n+     * @return the value of that column as a float.\n+     *\n+     * @throws IllegalArgumentException if the requested column is not a float.\n+     */\n+    @Override\n+    public float getFloat(int columnIndex) {\n+        checkClosed();\n+        checkPosition();\n+        return table.getFloat(columnIndex, rowIndex);\n+    }\n+\n+    /**\n+     * Returns the value of the requested column as a double. Note that {@link #getType(int)} will return\n+     * {@link Cursor#FIELD_TYPE_FLOAT} for both {@code float} and {@code double} columns.\n+     *\n+     * @param columnIndex the zero-based index of the target column.\n+     * @return the value of that column as a double.\n+     * @throws IllegalArgumentException if the requested column is not a double.\n+     */\n+    @Override\n+    public double getDouble(int columnIndex) {\n+        checkClosed();\n+        checkPosition();\n+        return table.getDouble(columnIndex, rowIndex);\n+    }\n+\n+    /**\n+     * Returns the SQLite Cursor type for a column index. Realm has more types than SQLite and some of them cannot be\n+     * mapped to any meaningful SQLite type. These will return -1 and cannot be accessed using a cursor.\n+     *\n+     * The following types are currently not supported:\n+     * <ul>\n+     *   <li>{@link ColumnType#TABLE}</li>\n+     *   <li>{@link ColumnType#MIXED}</li>\n+     *   <li>{@link ColumnType#LINK}</li>\n+     *   <li>{@link ColumnType#LINK_LIST}</li>\n+     * </ul>\n+     *\n+     * <p>\n+     * Some realm types are mapped to conform to the Cursor interface. These mappings are described below:\n+     * <ol>\n+     *   <li>boolean : Will return Cursor.FIELD_TYPE_INTEGER. {0 = false, 1 = true}, use getShort()/getInt()/getLong()</li>\n+     *   <li>double : Will return Cursor.FIELD_TYPE_FLOAT, but must be fetched using use getDouble()</li>\n+     *   <li>Date : Will return Cursor.FIELD_TYPE_INTEGER. Time in milliseconds since epoch, use getLong()</li>\n+     *</ol>\n+     *\n+     * @param columnIndex Get the data type for this column index or -1 if the column isn't accessible.\n+     * @return One of the {@code FIELD_TYPE_*}'s described in {@link Cursor}.\n+     */\n+    @Override\n+    public int getType(int columnIndex) {\n+        checkClosed();\n+        ColumnType realmType = table.getColumnType(columnIndex);\n+        switch (realmType) {\n+            case BOOLEAN: return FIELD_TYPE_INTEGER;\n+            case INTEGER: return FIELD_TYPE_INTEGER;\n+            case FLOAT: return FIELD_TYPE_FLOAT;\n+            case DOUBLE: return FIELD_TYPE_FLOAT;\n+            case STRING: return FIELD_TYPE_STRING;\n+            case BINARY: return FIELD_TYPE_BLOB;\n+            case DATE: return FIELD_TYPE_INTEGER;\n+            case TABLE:\n+            case MIXED:\n+            case LINK:\n+            case LINK_LIST:\n+            default:\n+                return -1;\n+        }\n+    }\n+\n+    /**\n+     * Realm currently doesn't support null. Calling this method will always throw an exception.\n+     *\n+     * @throws UnsupportedOperationException\n+     */\n+    @Override\n+    public boolean isNull(int columnIndex) {\n+        ColumnType realmType = table.getColumnType(columnIndex);\n+        switch(realmType) {\n+            case LINK: return table.isNullLink(columnIndex, rowIndex);\n+            case LINK_LIST:\n+            case BOOLEAN:\n+            case INTEGER:\n+            case FLOAT:\n+            case DOUBLE:\n+            case STRING:\n+            case BINARY:\n+            case DATE:\n+            case TABLE:\n+            case MIXED:\n+            default:\n+            throw new UnsupportedOperationException(\"isNull not yet supported by Realm for this type: \" + realmType);","path":"realm/src/main/java/io/realm/android/RealmCursor.java","position":584,"original_position":584,"commit_id":"4ee764e3a8bc8f9f01cb318461b5a4876f6eb2c5","original_commit_id":"4ee764e3a8bc8f9f01cb318461b5a4876f6eb2c5","user":{"login":"nhachicha","id":1793238,"avatar_url":"https://avatars.githubusercontent.com/u/1793238?v=3","gravatar_id":"","url":"https://api.github.com/users/nhachicha","html_url":"https://github.com/nhachicha","followers_url":"https://api.github.com/users/nhachicha/followers","following_url":"https://api.github.com/users/nhachicha/following{/other_user}","gists_url":"https://api.github.com/users/nhachicha/gists{/gist_id}","starred_url":"https://api.github.com/users/nhachicha/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nhachicha/subscriptions","organizations_url":"https://api.github.com/users/nhachicha/orgs","repos_url":"https://api.github.com/users/nhachicha/repos","events_url":"https://api.github.com/users/nhachicha/events{/privacy}","received_events_url":"https://api.github.com/users/nhachicha/received_events","type":"User","site_admin":false},"body":"IMO This is a *NotYetImplemented* kind of exception. Once it's available we may start using @Since/@Version","created_at":"2015-06-02T15:57:37Z","updated_at":"2015-06-02T15:57:37Z","html_url":"https://github.com/realm/realm-java/pull/1090#discussion_r31538612","pull_request_url":"https://api.github.com/repos/realm/realm-java/pulls/1090","_links":{"self":{"href":"https://api.github.com/repos/realm/realm-java/pulls/comments/31538612"},"html":{"href":"https://github.com/realm/realm-java/pull/1090#discussion_r31538612"},"pull_request":{"href":"https://api.github.com/repos/realm/realm-java/pulls/1090"}}},"pull_request":{"url":"https://api.github.com/repos/realm/realm-java/pulls/1090","id":34808074,"html_url":"https://github.com/realm/realm-java/pull/1090","diff_url":"https://github.com/realm/realm-java/pull/1090.diff","patch_url":"https://github.com/realm/realm-java/pull/1090.patch","issue_url":"https://api.github.com/repos/realm/realm-java/issues/1090","number":1090,"state":"open","locked":false,"title":"RealmCursor","user":{"login":"cmelchior","id":406066,"avatar_url":"https://avatars.githubusercontent.com/u/406066?v=3","gravatar_id":"","url":"https://api.github.com/users/cmelchior","html_url":"https://github.com/cmelchior","followers_url":"https://api.github.com/users/cmelchior/followers","following_url":"https://api.github.com/users/cmelchior/following{/other_user}","gists_url":"https://api.github.com/users/cmelchior/gists{/gist_id}","starred_url":"https://api.github.com/users/cmelchior/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cmelchior/subscriptions","organizations_url":"https://api.github.com/users/cmelchior/orgs","repos_url":"https://api.github.com/users/cmelchior/repos","events_url":"https://api.github.com/users/cmelchior/events{/privacy}","received_events_url":"https://api.github.com/users/cmelchior/received_events","type":"User","site_admin":false},"body":"Fixes #438 \r\n\r\n**Missing**\r\nContentProviders exposes a cursor, which works fine if used within a app. However it breaks if shared with another app:\r\n\r\n- Accessing an ContentProvider in another app is done using IPC (Blocked by #1091)\r\n- The ContentProvider is started on App1 main thread\r\n- App2 is accessing ContentProvider using a Binder thread, meaning that opening the Realm in onCreate causes Thread exceptions.\r\n\r\nWe can ship RealmCursor with the explicit caveat that it doesn't work with ContentProviders across apps, but it is not ideal.\r\n\r\n**Description**\r\nThis adds a Cursor implementation for Realm data. The main challenge is mapping the very limited types in SQLite to the more expressive types in Realm.\r\n\r\nThe current approach is to respect the Cursor interface as much as possible as that is what will be exposed in ContentProviders and other framework classes.\r\n\r\nThis has the following implications:\r\n```\r\n// Simple types\r\nBoolean:  becomes a Cursor.INTEGER and will return 0 or 1 when calling Cursor.getInt()\r\nDate: becomes a Cursor.INTEGER. getLong() return ms. since epoch. getInt() and getShort() will throw exception.\r\n\r\n// Links/LinkLists: No immediately good solution is available. Suggestion is adding support  for the following syntax. Disallowing accessing RealmLists might also be an option as it doesn't map well to a table layout anyway?\r\nint calculatedIndex = cursor.getIndex(\"foo.columnString\");\r\nint calculatedIndex = cursor.getIndex(\"fooList[0].columnString\");\r\n```\r\n\r\nI have a single new method ```setIdColumn(String columnName)``` that creates a virtual \"_id\" field used by many framework classes. This should be acceptable as it is defined when the Cursor is created and the developer know it is a ReamCursor. Adding other nice methods like ```getDate()``` should be avoided as client code should only interact with the cursor using the Interface.\r\n\r\nNote that RealmCursor just reuses the tableview backing the RealmResults. This means that any changes to RealmResults will be reflected in the RealmCursor. I am not sure this behaviour is developer friendly but AFAIK we cannot lock the tableview until we start implementing Async queries.\r\n\r\n@emanuelez @kneth @bmunkholm \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n","created_at":"2015-05-06T11:19:06Z","updated_at":"2015-06-02T15:57:37Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8150d10bfd966d498403a647bc349825d41ada95","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/realm/realm-java/pulls/1090/commits","review_comments_url":"https://api.github.com/repos/realm/realm-java/pulls/1090/comments","review_comment_url":"https://api.github.com/repos/realm/realm-java/pulls/comments{/number}","comments_url":"https://api.github.com/repos/realm/realm-java/issues/1090/comments","statuses_url":"https://api.github.com/repos/realm/realm-java/statuses/4ee764e3a8bc8f9f01cb318461b5a4876f6eb2c5","head":{"label":"realm:cm-cursor","ref":"cm-cursor","sha":"4ee764e3a8bc8f9f01cb318461b5a4876f6eb2c5","user":{"login":"realm","id":7575099,"avatar_url":"https://avatars.githubusercontent.com/u/7575099?v=3","gravatar_id":"","url":"https://api.github.com/users/realm","html_url":"https://github.com/realm","followers_url":"https://api.github.com/users/realm/followers","following_url":"https://api.github.com/users/realm/following{/other_user}","gists_url":"https://api.github.com/users/realm/gists{/gist_id}","starred_url":"https://api.github.com/users/realm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/realm/subscriptions","organizations_url":"https://api.github.com/users/realm/orgs","repos_url":"https://api.github.com/users/realm/repos","events_url":"https://api.github.com/users/realm/events{/privacy}","received_events_url":"https://api.github.com/users/realm/received_events","type":"Organization","site_admin":false},"repo":{"id":4084908,"name":"realm-java","full_name":"realm/realm-java","owner":{"login":"realm","id":7575099,"avatar_url":"https://avatars.githubusercontent.com/u/7575099?v=3","gravatar_id":"","url":"https://api.github.com/users/realm","html_url":"https://github.com/realm","followers_url":"https://api.github.com/users/realm/followers","following_url":"https://api.github.com/users/realm/following{/other_user}","gists_url":"https://api.github.com/users/realm/gists{/gist_id}","starred_url":"https://api.github.com/users/realm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/realm/subscriptions","organizations_url":"https://api.github.com/users/realm/orgs","repos_url":"https://api.github.com/users/realm/repos","events_url":"https://api.github.com/users/realm/events{/privacy}","received_events_url":"https://api.github.com/users/realm/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/realm/realm-java","description":"Realm is a mobile database: a replacement for SQLite & ORMs","fork":false,"url":"https://api.github.com/repos/realm/realm-java","forks_url":"https://api.github.com/repos/realm/realm-java/forks","keys_url":"https://api.github.com/repos/realm/realm-java/keys{/key_id}","collaborators_url":"https://api.github.com/repos/realm/realm-java/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/realm/realm-java/teams","hooks_url":"https://api.github.com/repos/realm/realm-java/hooks","issue_events_url":"https://api.github.com/repos/realm/realm-java/issues/events{/number}","events_url":"https://api.github.com/repos/realm/realm-java/events","assignees_url":"https://api.github.com/repos/realm/realm-java/assignees{/user}","branches_url":"https://api.github.com/repos/realm/realm-java/branches{/branch}","tags_url":"https://api.github.com/repos/realm/realm-java/tags","blobs_url":"https://api.github.com/repos/realm/realm-java/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/realm/realm-java/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/realm/realm-java/git/refs{/sha}","trees_url":"https://api.github.com/repos/realm/realm-java/git/trees{/sha}","statuses_url":"https://api.github.com/repos/realm/realm-java/statuses/{sha}","languages_url":"https://api.github.com/repos/realm/realm-java/languages","stargazers_url":"https://api.github.com/repos/realm/realm-java/stargazers","contributors_url":"https://api.github.com/repos/realm/realm-java/contributors","subscribers_url":"https://api.github.com/repos/realm/realm-java/subscribers","subscription_url":"https://api.github.com/repos/realm/realm-java/subscription","commits_url":"https://api.github.com/repos/realm/realm-java/commits{/sha}","git_commits_url":"https://api.github.com/repos/realm/realm-java/git/commits{/sha}","comments_url":"https://api.github.com/repos/realm/realm-java/comments{/number}","issue_comment_url":"https://api.github.com/repos/realm/realm-java/issues/comments{/number}","contents_url":"https://api.github.com/repos/realm/realm-java/contents/{+path}","compare_url":"https://api.github.com/repos/realm/realm-java/compare/{base}...{head}","merges_url":"https://api.github.com/repos/realm/realm-java/merges","archive_url":"https://api.github.com/repos/realm/realm-java/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/realm/realm-java/downloads","issues_url":"https://api.github.com/repos/realm/realm-java/issues{/number}","pulls_url":"https://api.github.com/repos/realm/realm-java/pulls{/number}","milestones_url":"https://api.github.com/repos/realm/realm-java/milestones{/number}","notifications_url":"https://api.github.com/repos/realm/realm-java/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/realm/realm-java/labels{/name}","releases_url":"https://api.github.com/repos/realm/realm-java/releases{/id}","created_at":"2012-04-20T09:18:42Z","updated_at":"2015-06-02T10:37:54Z","pushed_at":"2015-06-02T14:00:37Z","git_url":"git://github.com/realm/realm-java.git","ssh_url":"git@github.com:realm/realm-java.git","clone_url":"https://github.com/realm/realm-java.git","svn_url":"https://github.com/realm/realm-java","homepage":"http://realm.io","size":57620,"stargazers_count":1847,"watchers_count":1847,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":162,"mirror_url":null,"open_issues_count":123,"forks":162,"open_issues":123,"watchers":1847,"default_branch":"master"}},"base":{"label":"realm:master","ref":"master","sha":"ef57434d0333ca16386bd2072709ee6f23874dfe","user":{"login":"realm","id":7575099,"avatar_url":"https://avatars.githubusercontent.com/u/7575099?v=3","gravatar_id":"","url":"https://api.github.com/users/realm","html_url":"https://github.com/realm","followers_url":"https://api.github.com/users/realm/followers","following_url":"https://api.github.com/users/realm/following{/other_user}","gists_url":"https://api.github.com/users/realm/gists{/gist_id}","starred_url":"https://api.github.com/users/realm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/realm/subscriptions","organizations_url":"https://api.github.com/users/realm/orgs","repos_url":"https://api.github.com/users/realm/repos","events_url":"https://api.github.com/users/realm/events{/privacy}","received_events_url":"https://api.github.com/users/realm/received_events","type":"Organization","site_admin":false},"repo":{"id":4084908,"name":"realm-java","full_name":"realm/realm-java","owner":{"login":"realm","id":7575099,"avatar_url":"https://avatars.githubusercontent.com/u/7575099?v=3","gravatar_id":"","url":"https://api.github.com/users/realm","html_url":"https://github.com/realm","followers_url":"https://api.github.com/users/realm/followers","following_url":"https://api.github.com/users/realm/following{/other_user}","gists_url":"https://api.github.com/users/realm/gists{/gist_id}","starred_url":"https://api.github.com/users/realm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/realm/subscriptions","organizations_url":"https://api.github.com/users/realm/orgs","repos_url":"https://api.github.com/users/realm/repos","events_url":"https://api.github.com/users/realm/events{/privacy}","received_events_url":"https://api.github.com/users/realm/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/realm/realm-java","description":"Realm is a mobile database: a replacement for SQLite & ORMs","fork":false,"url":"https://api.github.com/repos/realm/realm-java","forks_url":"https://api.github.com/repos/realm/realm-java/forks","keys_url":"https://api.github.com/repos/realm/realm-java/keys{/key_id}","collaborators_url":"https://api.github.com/repos/realm/realm-java/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/realm/realm-java/teams","hooks_url":"https://api.github.com/repos/realm/realm-java/hooks","issue_events_url":"https://api.github.com/repos/realm/realm-java/issues/events{/number}","events_url":"https://api.github.com/repos/realm/realm-java/events","assignees_url":"https://api.github.com/repos/realm/realm-java/assignees{/user}","branches_url":"https://api.github.com/repos/realm/realm-java/branches{/branch}","tags_url":"https://api.github.com/repos/realm/realm-java/tags","blobs_url":"https://api.github.com/repos/realm/realm-java/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/realm/realm-java/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/realm/realm-java/git/refs{/sha}","trees_url":"https://api.github.com/repos/realm/realm-java/git/trees{/sha}","statuses_url":"https://api.github.com/repos/realm/realm-java/statuses/{sha}","languages_url":"https://api.github.com/repos/realm/realm-java/languages","stargazers_url":"https://api.github.com/repos/realm/realm-java/stargazers","contributors_url":"https://api.github.com/repos/realm/realm-java/contributors","subscribers_url":"https://api.github.com/repos/realm/realm-java/subscribers","subscription_url":"https://api.github.com/repos/realm/realm-java/subscription","commits_url":"https://api.github.com/repos/realm/realm-java/commits{/sha}","git_commits_url":"https://api.github.com/repos/realm/realm-java/git/commits{/sha}","comments_url":"https://api.github.com/repos/realm/realm-java/comments{/number}","issue_comment_url":"https://api.github.com/repos/realm/realm-java/issues/comments{/number}","contents_url":"https://api.github.com/repos/realm/realm-java/contents/{+path}","compare_url":"https://api.github.com/repos/realm/realm-java/compare/{base}...{head}","merges_url":"https://api.github.com/repos/realm/realm-java/merges","archive_url":"https://api.github.com/repos/realm/realm-java/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/realm/realm-java/downloads","issues_url":"https://api.github.com/repos/realm/realm-java/issues{/number}","pulls_url":"https://api.github.com/repos/realm/realm-java/pulls{/number}","milestones_url":"https://api.github.com/repos/realm/realm-java/milestones{/number}","notifications_url":"https://api.github.com/repos/realm/realm-java/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/realm/realm-java/labels{/name}","releases_url":"https://api.github.com/repos/realm/realm-java/releases{/id}","created_at":"2012-04-20T09:18:42Z","updated_at":"2015-06-02T10:37:54Z","pushed_at":"2015-06-02T14:00:37Z","git_url":"git://github.com/realm/realm-java.git","ssh_url":"git@github.com:realm/realm-java.git","clone_url":"https://github.com/realm/realm-java.git","svn_url":"https://github.com/realm/realm-java","homepage":"http://realm.io","size":57620,"stargazers_count":1847,"watchers_count":1847,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":162,"mirror_url":null,"open_issues_count":123,"forks":162,"open_issues":123,"watchers":1847,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/realm/realm-java/pulls/1090"},"html":{"href":"https://github.com/realm/realm-java/pull/1090"},"issue":{"href":"https://api.github.com/repos/realm/realm-java/issues/1090"},"comments":{"href":"https://api.github.com/repos/realm/realm-java/issues/1090/comments"},"review_comments":{"href":"https://api.github.com/repos/realm/realm-java/pulls/1090/comments"},"review_comment":{"href":"https://api.github.com/repos/realm/realm-java/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/realm/realm-java/pulls/1090/commits"},"statuses":{"href":"https://api.github.com/repos/realm/realm-java/statuses/4ee764e3a8bc8f9f01cb318461b5a4876f6eb2c5"}}}}