From 44670dcc0fba3a1160f2e03269568a751e3d68f9 Mon Sep 17 00:00:00 2001 From: Christian Melchior Date: Thu, 9 Feb 2017 14:49:56 +0100 Subject: [PATCH 1/2] Add RFC for Primitive List API --- rfcs/primitive_lists_api.md | 271 ++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 rfcs/primitive_lists_api.md diff --git a/rfcs/primitive_lists_api.md b/rfcs/primitive_lists_api.md new file mode 100644 index 0000000000..9ebed4539b --- /dev/null +++ b/rfcs/primitive_lists_api.md @@ -0,0 +1,271 @@ +- Feature Name: Primitive List API +- Start Date: 2017-02-07 +- RFC PR: +- Version: 1 + +# Summary + +Currently Realm only supports lists of Realm Objects, but we should also support lists +of primitive types like `int`, `String` and `boolean`. This document describes how such +an API might look like. + +# Motivation + +With Core working on support for primitive lists, we need to consider how the public API is going to look like as it +might influence some of the design choices for the underlying implementation. This RFC is mostly to explore the +possible options for the public API and elicit feedback. + +# Variant 1: Relax generic type arguments + +In this variant, we relax the type requirement on RealmList, RealmQuery and RealmResults to `Object`. + +1) Relax type requirement for `RealmCollection`, `OrderedRealmCollection`, `RealmResults`, `RealmList` and `RealmQuery` + +``` +// Current signature +public class RealmList extends AbstractList implements OrderedRealmCollection +public class RealmQuery { +public class RealmResults extends AbstractList implements OrderedRealmCollection +public interface OrderedRealmCollection extends List, RealmCollection +public interface RealmCollection extends Collection + +// New signature +public class RealmList extends AbstractList implements OrderedRealmCollection +public class RealmQuery +public class RealmResults extends AbstractList implements OrderedRealmCollection +public interface OrderedRealmCollection extends List, RealmCollection +public interface RealmCollection extends Collection +``` + +2) New optional methods in `RealmCollection` + +``` +average(); +max(); +min(); +maxDate(); +minDate(); +sum() +``` + +3) New optional methods in `OrderedRealmCollection` + +``` +sort(); +sort(Sort); +``` + + +4a) Add new query methods for querying primitive arrays, i.e only accept value, not column name. + +``` +// New RealmQuery methods (leaving out the column name) +RealmQuery query = obj.getList().where(); + +beginsWith(String) +beginsWith(String, Case) +between(Date, Date) +between(long, long) +between(float, float) +between(double, double) +contains(String) +contains(String, Case) +distinct() +endsWith(String) +endsWith(String, Case) +equalTo(Boolean) +equalTo(Byte) +equalTo(byte[]) +equalTo(Date) +equalTo(Double) +equalTo(Float) +equalTo(Integer) +equalTo(Long) +equalTo(Short) +equalTo(String) +equalTo(String, Case) +findAllSorted() +findAllSortedAsync() +greaterThan(Date) +greaterThan(double) +greaterThan(float) +greaterThan(long) +greaterThanOrEqualTo(Date) +greaterThanOrEqualTo(double) +greaterThanOrEqualTo(float) +greaterThanOrEqualTo(long) +in(Boolean[]) +in(Byte[]) +in(Date[]) +in(Double[]) +in(Float[]) +in(Integer[]) +in(Long[]) +in(Short[]) +in(String[]) +in(String[], Case) +isEmpty() +isNotEmpty() +isNotNull() +isNull() +lessThan(Date) +lessThan(double) +lessThan(float) +lessThan(long) +lessThanOrEqualTo(Date) +lessThanOrEqualTo(double) +lessThanOrEqualTo(float) +lessThanOrEqualTo(long) +like(String) +max() +maximumDate() +min() +minimumDate() +notEqualTo(Boolean) +notEqualTo(Byte) +notEqualTo(byte[]) +notEqualTo(Date) +notEqualTo(Double) +notEqualTo(Float) +notEqualTo(Integer) +notEqualTo(Long) +notEqualTo(Short) +notEqualTo(String) +notEqualTo(String, Case) +sum() +``` + +Benefit: Intent expressed in method params. All queries use the same class Downside: Ton of new methods. More chances for +people to use the "wrong" method. Today people still have to remember not to call e.g. `sum` on a String field though. + + +4b) Add support for a special keyword for column names. NSPredicate apparently uses `SELF`, `$` could also work. + +Benefit: No need to add a lot of new methods. Easier to upgrade from existing workaround where people reference +a field inside a `RealmInt` type (search-replace-done). Downside: Would not work if people used the restricted name for +an actual field name. Syntax would also be a bit awkward and "hidden". + + +# Design 2: PrimitiveRealmList + +In this variant, we add 3 new classes `PrimitiveRealmList`, `PrimitiveRealmQuery`, `PrimitiveRealmResults` + +1a) Add new classes + +``` +// New classes for supporting primitive arrays +public class PrimitiveRealmList extends AbstractList implements OrderedRealmCollection +public class PrimitiveRealmQuery +public class RealmResults implements OrderedRealmCollection + +// We need to relax the Collection Interface methods unless we want to create a completely new Collection hierarchy for +// primitive types. +public interface OrderedRealmCollection extends List, RealmCollection +public interface RealmCollection extends Collection +``` + +1b) Add new classes with `Primitive*` as an abstract super class: + +Precedence: SparseIntArray, SparseBooleanArray, etc. + +``` +protected abstract class PrimitiveRealmQuery +public class PrimitiveIntegerRealmQuery extends PrimitiveRealmQuery +public class PrimitiveFloatRealmQuery extends PrimitiveRealmQuery +public class PrimitiveDoubleRealmQuery extends PrimitiveRealmQuery +public class PrimitiveStringRealmQuery extends PrimitiveRealmQuery +public class PrimitiveBooleanRealmQuery extends PrimitiveRealmQuery + +protected abstract class PrimitiveRealmList extends OrderedRealmCollection +public class PrimitiveIntegerRealmList extends PrimitiveRealmList +public class PrimitiveFloatRealmList extends PrimitiveRealmList +public class PrimitiveDoubleRealmList extends PrimitiveRealmList +public class PrimitiveStringRealmList extends PrimitiveRealmList +public class PrimitiveBooleanRealmList extends PrimitiveRealmList + +protected abstract class PrimitiveRealmResults extends OrderedRealmCollection +public class PrimitiveIntegerRealmResults extends PrimitiveRealmResults +public class PrimitiveFloatRealmResults extends PrimitiveRealmResults +public class PrimitiveDoubleRealmResults extends PrimitiveRealmResults +public class PrimitiveStringRealmResults extends PrimitiveRealmResults +public class PrimitiveBooleanRealmResults extends PrimitiveRealmResults +``` + +2) We need the same optional methods in `RealmCollection` and `OrderedRealmCollection` unless we we create an entirely + new collection hierarchy. + +3) `PrimitiveRealmQuery` will only contain the features supported by primitive arrays. If using 1b, we can even ensure + that all methods are useful + +``` +beginsWith // Only String +between // Only numbers, date +contains // Only String +distinct +endsWith // Only String +equalTo +findAllSorted +findAllSortedAsync +greaterThan // Only numbers, date +greaterThanOrEqualTo // only numbers, date +in +isEmpty +isNotEmpty +isNotNull +isNull +lessThan // only numbers, date +lessThanOrEqualTo // only numbers, date +like // only String +max // only numbers, date +maximumDate // only numbers, date +min // only numbers, date +minimumDate // only numbers, date +notEqualTo +sum // only numbers // only numbers +```` + +# Discussion + +## Design 1: Relax type requirements + +**Advantages** +* No need to add new types. +* RealmQuery/RealmResults already contain methods that doesn't work in certain circumstances. +* Schemas can already be restrict using modules, making `` inaccurate anyway. +* RealmCollection will have to contain optional methods no matter what, so adding them to RealmQuery doesn't break + that pattern. + +**Disadvantages** +* People can now accidentally try to save non-realm classes, which will not break before runtime (IntelliJ plugin might + help here). +* `RealmQuery` will suddenly have a ton of new methods that will only work for primitive arrays (lint check?) + + +## Design 2: New collection classes: + +**Advantages** +* Intent is more clear in the type system. +* `RealmQuery` is not flooded with a lot of new methods. +* No changes to existing code. Primitive arrays will be a complete new addon. +* With 1b) we statically check everything using the type system on compile time. + +**Disadvantages** +* Explosion in classes in the Realm API. Maintenance and test will be problematic. +* It is not clear how to handle primitive arrays in the current Collection hierarchy. It seems a bit pointless to allow + optional methods for primitive lists in the interface if we go to great lengths in the actual class to make it type + safe. +* Type safety is not guaranteed anyway if we allow ``` as generic. + + +# Unresolved questions + +We need more feedback on the two proposals. + +* Unclear how we are going to support lists-of-lists, e.g. what kind of queries do you want to run on a `int[][]` + (if any) ? + +None. + +# Version history + +1: Initial version. From 84b7f4f2dc7126575582cba607de1a4a9a567ae8 Mon Sep 17 00:00:00 2001 From: Christian Melchior Date: Thu, 9 Feb 2017 14:59:48 +0100 Subject: [PATCH 2/2] Added a few more comments + Cleanup --- rfcs/primitive_lists_api.md | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/rfcs/primitive_lists_api.md b/rfcs/primitive_lists_api.md index 9ebed4539b..a7290e8eac 100644 --- a/rfcs/primitive_lists_api.md +++ b/rfcs/primitive_lists_api.md @@ -234,10 +234,11 @@ sum // only numbers // only numbers * Schemas can already be restrict using modules, making `` inaccurate anyway. * RealmCollection will have to contain optional methods no matter what, so adding them to RealmQuery doesn't break that pattern. +* Would allow us to remove the requirement that people implements `RealmModel`, they could just use the `@RealmClass` + annotation. **Disadvantages** -* People can now accidentally try to save non-realm classes, which will not break before runtime (IntelliJ plugin might - help here). +* API gets a lot less type safe (IntelliJ plugin might help here). * `RealmQuery` will suddenly have a ton of new methods that will only work for primitive arrays (lint check?) @@ -257,14 +258,25 @@ sum // only numbers // only numbers * Type safety is not guaranteed anyway if we allow ``` as generic. +# Work required + +- [ ] Extend JSON API to support primitive lists. +- [ ] Extend RealmObjectSchema to support primitive lists +- [ ] Extend DynamicRealmObject to support primitive lists (Design required). +- [ ] Annotation processor must be updated +- [ ] Add support for primitive arrays using RealmTransformer (maybe not part of this RFC?) +- [ ] Implement new classes (depends on chosen solution). +- [ ] Refactor current Collection API's + unit tests. + # Unresolved questions -We need more feedback on the two proposals. +1. We need more feedback on the two proposals. -* Unclear how we are going to support lists-of-lists, e.g. what kind of queries do you want to run on a `int[][]` +2. Unclear how we are going to support lists-of-lists, e.g. what kind of queries do you want to run on a `int[][]` (if any) ? -None. +3. Should we support `int[]` using bytecode transformation? Basically replace `int[]` and friends with `RealmList` ? + # Version history