[!NOTE]
This feature has already been reviewed. New updates to review: CHANGELOG.md.
The branch can be merged whenever we want to make a release with this new feature.
Adds support for storing lists and dictionaries (with nested collections) as the underlying value of a Mixed property.
Sets are not supported as a Mixed value.
Test overview
Click to expand
```
Mixed
Collection types
CRUD operations
Create and access
List
✓ has all primitive types (input: JS Array)
✓ has all primitive types (input: Realm List)
✓ has all primitive types (input: Default value)
✓ has nested lists of all primitive types
✓ has nested dictionaries of all primitive types
✓ has mix of nested collections of all types
✓ inserts all primitive types via `push()`
✓ inserts nested lists of all primitive types via `push()`
✓ inserts nested dictionaries of all primitive types via `push()`
✓ inserts mix of nested collections of all types via `push()`
✓ returns different reference for each access
Dictionary
✓ has all primitive types (input: JS Object)
✓ has all primitive types (input: JS Object w/o proto)
✓ has all primitive types (input: Realm Dictionary)
✓ has all primitive types (input: Default value)
✓ can use the spread of embedded Realm object
✓ can use the spread of custom non-Realm object
✓ has nested lists of all primitive types
✓ has nested dictionaries of all primitive types
✓ has mix of nested collections of all types
✓ inserts all primitive types via setter
✓ inserts nested lists of all primitive types via setter
✓ inserts nested dictionaries of all primitive types via setter
✓ inserts mix of nested collections of all types via setter
✓ inserts mix of nested collections of all types via `set()` overloads
✓ returns different reference for each access
Results
from List
snapshot()
✓ has all primitive types
✓ has mix of nested collections of all types
objects().filtered()
✓ has all primitive types
✓ has mix of nested collections of all types
from Dictionary
objects().filtered()
✓ has all primitive types
✓ has mix of nested collections of all types
Update
List
✓ updates top-level item via setter
✓ updates nested item via setter
✓ updates itself to a new list
✓ updates nested list to a new list
✓ does not become invalidated when updated to a new list
- self assigns
- self assigns nested list
Dictionary
✓ updates top-level entry via setter
✓ updates nested entry via setter
✓ updates itself to a new dictionary
✓ updates nested dictionary to a new dictionary
✓ does not become invalidated when updated to a new dictionary
- self assigns
- self assigns nested dictionary
Remove
List
✓ removes top-level item via `remove()`
✓ removes nested item via `remove()`
Dictionary
✓ removes top-level entry via `remove()`
✓ removes nested entry via `remove()`
JS collection methods
List
✓ pop()
✓ shift()
✓ unshift()
✓ splice()
✓ indexOf()
Iterators
✓ values() - list
✓ values() - dictionary
✓ entries() - list
✓ entries() - dictionary
Filtering
✓ filters by query path on list of all primitive types
✓ filters by query path on nested list of all primitive types
✓ filters by query path on dictionary of all primitive types
✓ filters by query path on nested dictionary of all primitive types
Invalid operations
✓ throws when creating a Mixed with a set
✓ throws when creating a set with a list
✓ throws when creating a set with a dictionary
✓ throws when updating a list item to a set
✓ throws when updating a dictionary entry to a set
✓ throws when creating a list or dictionary with an embedded object
✓ throws when setting a list or dictionary item to an embedded object
✓ throws when setting a list or dictionary outside a transaction
✓ throws when setting a list item out of bounds
✓ throws when setting a nested list item out of bounds
✓ throws when assigning to list snapshot (Results)
✓ invalidates the list when removed
✓ invalidates the dictionary when removed
Observable
Collections in Mixed
Collection notifications
List
✓ fires when inserting, updating, and deleting at top-level
✓ fires when inserting, updating, and deleting in nested list
✓ fires when inserting, updating, and deleting in nested dictionary
✓ does not fire when updating object at top-level
Dictionary
✓ fires when inserting, updating, and deleting at top-level
✓ fires when inserting, updating, and deleting in nested list
✓ fires when inserting, updating, and deleting in nested dictionary
✓ does not fire when updating object at top-level
Object notifications
✓ fires when inserting, updating, and deleting in top-level list
✓ fires when inserting, updating, and deleting in nested list
✓ fires when inserting, updating, and deleting in top-level dictionary
✓ fires when inserting, updating, and deleting in nested dictionary
✓ fires when inserting, updating, and deleting in nested dictionary (using key-path)
```
Brief overview of usage
class CustomObject extends Realm.Object {
value!: Realm.Types.Mixed;
static schema: ObjectSchema = {
name: "CustomObject",
properties: {
value: "mixed",
},
};
}
const realm = await Realm.open({ schema: [CustomObject] });
// Create an object with a dictionary value as the Mixed
// property, containing primitives and a list.
const realmObject = realm.write(() => {
return realm.create(CustomObject, {
value: {
num: 1,
string: "hello",
bool: true,
list: [
{
string: "world",
},
],
},
});
});
// Accessing the collection value returns the managed collection.
const dictionary = realmObject.value;
expectDictionary(dictionary);
const list = dictionary.list;
expectList(list);
const leafDictionary = list[0];
expectDictionary(leafDictionary);
console.log(leafDictionary.string); // "world"
// Update the Mixed property to a list.
realm.write(() => {
realmObject.value = [1, "hello", { newKey: "new value" }];
});
// Useful custom helper functions. (Will be provided in a future release.)
function expectList(value: unknown): asserts value is Realm.List {
if (!(value instanceof Realm.List)) {
throw new Error("Expected a 'Realm.List'.");
}
}
function expectDictionary(value: unknown): asserts value is Realm.Dictionary {
if (!(value instanceof Realm.Dictionary)) {
throw new Error("Expected a 'Realm.Dictionary'.");
}
}
What, How & Why?
Adds support for storing lists and dictionaries (with nested collections) as the underlying value of a
Mixed
property.Sets are not supported as a Mixed value.
Test overview
Click to expand
``` Mixed Collection types CRUD operations Create and access List ✓ has all primitive types (input: JS Array) ✓ has all primitive types (input: Realm List) ✓ has all primitive types (input: Default value) ✓ has nested lists of all primitive types ✓ has nested dictionaries of all primitive types ✓ has mix of nested collections of all types ✓ inserts all primitive types via `push()` ✓ inserts nested lists of all primitive types via `push()` ✓ inserts nested dictionaries of all primitive types via `push()` ✓ inserts mix of nested collections of all types via `push()` ✓ returns different reference for each access Dictionary ✓ has all primitive types (input: JS Object) ✓ has all primitive types (input: JS Object w/o proto) ✓ has all primitive types (input: Realm Dictionary) ✓ has all primitive types (input: Default value) ✓ can use the spread of embedded Realm object ✓ can use the spread of custom non-Realm object ✓ has nested lists of all primitive types ✓ has nested dictionaries of all primitive types ✓ has mix of nested collections of all types ✓ inserts all primitive types via setter ✓ inserts nested lists of all primitive types via setter ✓ inserts nested dictionaries of all primitive types via setter ✓ inserts mix of nested collections of all types via setter ✓ inserts mix of nested collections of all types via `set()` overloads ✓ returns different reference for each access Results from List snapshot() ✓ has all primitive types ✓ has mix of nested collections of all types objects().filtered() ✓ has all primitive types ✓ has mix of nested collections of all types from Dictionary objects().filtered() ✓ has all primitive types ✓ has mix of nested collections of all types Update List ✓ updates top-level item via setter ✓ updates nested item via setter ✓ updates itself to a new list ✓ updates nested list to a new list ✓ does not become invalidated when updated to a new list - self assigns - self assigns nested list Dictionary ✓ updates top-level entry via setter ✓ updates nested entry via setter ✓ updates itself to a new dictionary ✓ updates nested dictionary to a new dictionary ✓ does not become invalidated when updated to a new dictionary - self assigns - self assigns nested dictionary Remove List ✓ removes top-level item via `remove()` ✓ removes nested item via `remove()` Dictionary ✓ removes top-level entry via `remove()` ✓ removes nested entry via `remove()` JS collection methods List ✓ pop() ✓ shift() ✓ unshift() ✓ splice() ✓ indexOf() Iterators ✓ values() - list ✓ values() - dictionary ✓ entries() - list ✓ entries() - dictionary Filtering ✓ filters by query path on list of all primitive types ✓ filters by query path on nested list of all primitive types ✓ filters by query path on dictionary of all primitive types ✓ filters by query path on nested dictionary of all primitive types Invalid operations ✓ throws when creating a Mixed with a set ✓ throws when creating a set with a list ✓ throws when creating a set with a dictionary ✓ throws when updating a list item to a set ✓ throws when updating a dictionary entry to a set ✓ throws when creating a list or dictionary with an embedded object ✓ throws when setting a list or dictionary item to an embedded object ✓ throws when setting a list or dictionary outside a transaction ✓ throws when setting a list item out of bounds ✓ throws when setting a nested list item out of bounds ✓ throws when assigning to list snapshot (Results) ✓ invalidates the list when removed ✓ invalidates the dictionary when removed Observable Collections in Mixed Collection notifications List ✓ fires when inserting, updating, and deleting at top-level ✓ fires when inserting, updating, and deleting in nested list ✓ fires when inserting, updating, and deleting in nested dictionary ✓ does not fire when updating object at top-level Dictionary ✓ fires when inserting, updating, and deleting at top-level ✓ fires when inserting, updating, and deleting in nested list ✓ fires when inserting, updating, and deleting in nested dictionary ✓ does not fire when updating object at top-level Object notifications ✓ fires when inserting, updating, and deleting in top-level list ✓ fires when inserting, updating, and deleting in nested list ✓ fires when inserting, updating, and deleting in top-level dictionary ✓ fires when inserting, updating, and deleting in nested dictionary ✓ fires when inserting, updating, and deleting in nested dictionary (using key-path) ```Brief overview of usage
☑️ ToDos