Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional tests for collections in mixed #6648

Draft
wants to merge 44 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
aa5b287
Implement support for flat collections in `Mixed` (#6364)
elle-j Feb 1, 2024
f27d77e
RJS-2680: Implement support for `Mixed` data type with nested collect…
elle-j Apr 2, 2024
aeb1749
Temporarily comment out failing filtering tests from Core upgrade.
elle-j Apr 11, 2024
b7d21e7
Add links to Core issue.
elle-j Apr 12, 2024
c20dede
Update example in CHANGELOG.
elle-j Apr 12, 2024
1dca996
Update PR link in CHANGELOG to the combined PR.
elle-j Apr 12, 2024
e675112
Add more links to Core issue.
elle-j Apr 12, 2024
ec9f30f
Injecting Symbol_for (#6616)
kraenhansen Apr 15, 2024
42f6814
Basic synced collections in mixed tests
papafe Apr 15, 2024
5a6b8c4
Removed previous method
papafe Apr 15, 2024
b960fd5
Various corrections
papafe Apr 15, 2024
3991bec
Removed only
papafe Apr 15, 2024
5502110
Testing
papafe Apr 19, 2024
6e4e18c
Corrected types
papafe Apr 19, 2024
889fcfe
Various fixes
papafe Apr 19, 2024
0b8ff49
Various fixes
papafe Apr 22, 2024
f303fda
Fixed equality [skip-ci]
papafe Apr 22, 2024
883d26c
Added list modification
papafe Apr 22, 2024
71c341c
Adding tests
papafe Apr 22, 2024
3bf02b3
Added dictionary tests
papafe Apr 23, 2024
5808ee6
Reinstated tests
papafe Apr 23, 2024
f305970
Various improvements
papafe Apr 23, 2024
51bbdf1
Moved function up
papafe Apr 24, 2024
46150ae
Removed additional tests and modifications
papafe Apr 24, 2024
ab512bb
Small fixes
papafe Apr 24, 2024
d2c1a4e
Removed todo
papafe Apr 24, 2024
105054d
Removed unused
papafe Apr 24, 2024
ba5ec50
Apply suggestions from code review
papafe Apr 25, 2024
b9c7470
Small corrections
papafe Apr 25, 2024
ba48135
Reinstated tests
papafe Apr 29, 2024
89de282
Small correction
papafe Apr 29, 2024
2711dd8
Logging to file
papafe Apr 29, 2024
e56b233
Improvements
papafe Apr 29, 2024
71e8524
Remove unused
papafe Apr 29, 2024
fa9d2ea
Removed realm use
papafe Apr 29, 2024
14e9a32
trying to improve testing
papafe Apr 29, 2024
2ec8d25
Corrected testing
papafe Apr 29, 2024
f7894f4
Removed only
papafe Apr 29, 2024
8f81629
Added comment
papafe Apr 29, 2024
6c51611
Merge branch 'fp/collections-mixed-sync-tests' into fp/collections-mi…
papafe May 1, 2024
4aeb008
Reinstated missing
papafe May 2, 2024
67abfe9
Removed unused
papafe May 2, 2024
f0c3ffc
Small corrections
papafe May 2, 2024
3c3bde9
Removed comment
papafe May 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,79 @@
## vNext (TBD)

### Enhancements
* 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. ([#6613](https://github.com/realm/realm-js/pull/6613))
```typescript
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'.");
}
}
```

### Fixed
* <How to hit and notice issue? what was the impact?> ([#????](https://github.com/realm/realm-js/issues/????), since v?.?.?)
* None

### Compatibility
* React Native >= v0.71.4
* Realm Studio v15.0.0.
* File format: generates Realms with format v24 (reads and upgrades file format v10 or later).

### Internal
<!-- * Either mention core version or upgrade -->
<!-- * Using Realm Core vX.Y.Z -->
<!-- * Upgraded Realm Core from vX.Y.Z to vA.B.C -->

## 12.7.1 (2024-04-19)

### Fixed
Expand Down
5 changes: 3 additions & 2 deletions integration-tests/tests/src/hooks/open-realm-before.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,10 @@ export function openRealmHook(config: OpenRealmConfiguration = {}) {
export function closeThisRealm(this: RealmContext & Mocha.Context): void {
if (this.closeRealm) {
this.closeRealm({ clearTestState: true, deleteFile: true });
} else {
// Clearing the test state to ensure the sync session gets completely reset and nothing is cached between tests
Realm.clearTestState();
}
// Clearing the test state to ensure the sync session gets completely reset and nothing is cached between tests
Realm.clearTestState();
}

export function openRealmBeforeEach(config: OpenRealmConfiguration = {}): void {
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: Enable when self-assignment is solved (https://github.com/realm/realm-core/issues/7422).
// 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