Skip to content

Commit

Permalink
Merge 07136e7 into 6bb845c
Browse files Browse the repository at this point in the history
  • Loading branch information
elle-j committed Apr 2, 2024
2 parents 6bb845c + 07136e7 commit c40fb0c
Show file tree
Hide file tree
Showing 23 changed files with 3,879 additions and 1,024 deletions.
48 changes: 47 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,53 @@
* None

### Enhancements
* None
* A `mixed` value can now hold a `Realm.List` and `Realm.Dictionary` with nested collections. Note that `Realm.Set` is not supported as a `mixed` value. ([#6513](https://github.com/realm/realm-js/pull/6513))

```typescript
class CustomObject extends Realm.Object {
value!: Realm.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: [
{
dict: {
string: "world",
},
},
],
},
});
});

// Accessing the collection value returns the managed collection.
// The default generic type argument is `unknown` (mixed).
const dictionary = realmObject.value as Realm.Dictionary;
const list = dictionary.list as Realm.List;
const leafDictionary = (list[0] as Realm.Dictionary).dict as Realm.Dictionary;
console.log(leafDictionary.string); // "world"

// Update the Mixed property to a list.
realm.write(() => {
realmObject.value = [1, "hello", { newKey: "new value" }];
});
```

### Fixed
* Fixed `User#callFunction` to correctly pass arguments to the server. Previously they would be sent as an array, so if your server-side function used to handle the unwrapping of arguments, it would need an update too. The "functions factory" pattern of calling `user.functions.sum(1, 2, 3)` wasn't affected by this bug. Thanks to @deckyfx for finding this and suggesting the fix! ([#6447](https://github.com/realm/realm-js/issues/6447), since v12.0.0)
Expand Down
37 changes: 7 additions & 30 deletions integration-tests/tests/src/tests/dictionary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { expect } from "chai";
import Realm, { PropertySchema } from "realm";

import { openRealmBefore, openRealmBeforeEach } from "../hooks";
import { sleep } from "../utils/sleep";

type Item<ValueType = Realm.Mixed> = {
dict: Realm.Dictionary<ValueType>;
Expand Down Expand Up @@ -60,17 +59,6 @@ const DictTypedSchema: Realm.ObjectSchema = {
},
};

const DictMixedSchema = {
name: "MixedDictionary",
properties: {
dict1: "mixed{}",
dict2: "mixed{}",
},
};

type IDictSchema = {
fields: Record<any, any>;
};
type ITwoDictSchema = {
dict1: Record<any, any>;
dict2: Record<any, any>;
Expand Down Expand Up @@ -307,17 +295,17 @@ describe("Dictionary", () => {
});
});

// This is currently not supported
it.skip("can store dictionary values using string keys", function (this: RealmContext) {
it("can store dictionary values using string keys", function (this: RealmContext) {
const item = this.realm.write(() => {
const item = this.realm.create<Item>("Item", {});
const item2 = this.realm.create<Item>("Item", {});
item2.dict.key1 = "Hello";
item.dict.key1 = item2.dict;
item2.dict.key1 = "hello";
item.dict.key1 = item2;
return item;
});
// @ts-expect-error We expect a dictionary inside dictionary
expect(item.dict.key1.dict.key1).equals("hello");
const innerObject = item.dict.key1 as Realm.Object<Item> & Item;
expect(innerObject).instanceOf(Realm.Object);
expect(innerObject.dict).deep.equals({ key1: "hello" });
});

it("can store a reference to itself using string keys", function (this: RealmContext) {
Expand Down Expand Up @@ -599,7 +587,7 @@ describe("Dictionary", () => {
});

describe("embedded models", () => {
openRealmBeforeEach({ schema: [DictTypedSchema, DictMixedSchema, EmbeddedChild] });
openRealmBeforeEach({ schema: [DictTypedSchema, EmbeddedChild] });
it("inserts correctly", function (this: RealmContext) {
this.realm.write(() => {
this.realm.create(DictTypedSchema.name, {
Expand All @@ -615,16 +603,5 @@ describe("Dictionary", () => {
expect(dict_2.children1?.num).equal(4, "We expect children1#4");
expect(dict_2.children2?.num).equal(5, "We expect children2#5");
});

it("throws on invalid input", function (this: RealmContext) {
this.realm.write(() => {
expect(() => {
this.realm.create(DictMixedSchema.name, {
dict1: { children1: { num: 2 }, children2: { num: 3 } },
dict2: { children1: { num: 4 }, children2: { num: 5 } },
});
}).throws("Unable to convert an object with ctor 'Object' to a Mixed");
});
});
});
});
50 changes: 32 additions & 18 deletions integration-tests/tests/src/tests/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,7 @@ describe("Lists", () => {
Error,
"Requested index 2 calling set() on list 'LinkTypesObject.arrayCol' when max is 1",
);
expect(() => (array[-1] = { doubleCol: 1 })).throws(Error, "Index -1 cannot be less than zero.");
expect(() => (array[-1] = { doubleCol: 1 })).throws(Error, "Cannot set item at negative index -1");

//@ts-expect-error TYPEBUG: our List type-definition expects index accesses to be done with a number , should probably be extended.
array["foo"] = "bar";
Expand Down Expand Up @@ -772,6 +772,7 @@ describe("Lists", () => {
openRealmBeforeEach({
schema: [LinkTypeSchema, TestObjectSchema, PersonListSchema, PersonSchema, PrimitiveArraysSchema],
});

it("are typesafe", function (this: RealmContext) {
let obj: ILinkTypeSchema;
let prim: IPrimitiveArraysSchema;
Expand All @@ -792,8 +793,10 @@ describe("Lists", () => {
//@ts-expect-error TYPEBUG: type missmatch, forcecasting shouldn't be done
obj.arrayCol = [this.realm.create<ITestObjectSchema>(TestObjectSchema.name, { doubleCol: 1.0 })];
expect(obj.arrayCol[0].doubleCol).equals(1.0);
obj.arrayCol = obj.arrayCol; // eslint-disable-line no-self-assign
expect(obj.arrayCol[0].doubleCol).equals(1.0);

// TODO: Solve the "removeAll()" case for self-assignment.
// obj.arrayCol = obj.arrayCol; // eslint-disable-line no-self-assign
// expect(obj.arrayCol[0].doubleCol).equals(1.0);

//@ts-expect-error Person is not assignable to boolean.
expect(() => (prim.bool = [person])).throws(
Expand Down Expand Up @@ -868,21 +871,6 @@ describe("Lists", () => {
testAssign("data", DATA1);
testAssign("date", DATE1);

function testAssignNull(name: string, expected: string) {
//@ts-expect-error TYPEBUG: our List type-definition expects index accesses to be done with a number , should probably be extended.
expect(() => (prim[name] = [null])).throws(Error, `Expected '${name}[0]' to be ${expected}, got null`);
//@ts-expect-error TYPEBUG: our List type-definition expects index accesses to be done with a number , should probably be extended.
expect(prim[name].length).equals(1);
}

testAssignNull("bool", "a boolean");
testAssignNull("int", "a number or bigint");
testAssignNull("float", "a number");
testAssignNull("double", "a number");
testAssignNull("string", "a string");
testAssignNull("data", "an instance of ArrayBuffer");
testAssignNull("date", "an instance of Date");

testAssign("optBool", true);
testAssign("optInt", 1);
testAssign("optFloat", 1.1);
Expand All @@ -905,7 +893,33 @@ describe("Lists", () => {
//@ts-expect-error throws on modification outside of transaction.
expect(() => (prim.bool = [])).throws("Cannot modify managed objects outside of a write transaction.");
});

it("throws when assigning null to non-nullable", function (this: RealmContext) {
const realm = this.realm;
const prim = realm.write(() => realm.create<IPrimitiveArraysSchema>(PrimitiveArraysSchema.name, {}));

function testAssignNull(name: string, expected: string) {
expect(() => {
realm.write(() => {
// @ts-expect-error TYPEBUG: our List type-definition expects index accesses to be done with a number , should probably be extended.
prim[name] = [null];
});
}).throws(Error, `Expected '${name}[0]' to be ${expected}, got null`);

// @ts-expect-error TYPEBUG: our List type-definition expects index accesses to be done with a number , should probably be extended.
expect(prim[name].length).equals(0);
}

testAssignNull("bool", "a boolean");
testAssignNull("int", "a number or bigint");
testAssignNull("float", "a number");
testAssignNull("double", "a number");
testAssignNull("string", "a string");
testAssignNull("data", "an instance of ArrayBuffer");
testAssignNull("date", "an instance of Date");
});
});

describe("operations", () => {
openRealmBeforeEach({ schema: [LinkTypeSchema, TestObjectSchema, PersonSchema, PersonListSchema] });
it("supports enumeration", function (this: RealmContext) {
Expand Down
Loading

0 comments on commit c40fb0c

Please sign in to comment.