Skip to content

(DOCSP-26985): @realm/reactify: UUID - React Native SDK #2443

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions examples/react-native/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module.exports = {
'no-undef': 'off',
'no-new': 'off',
'jsx-quotes': 0, // do not remove this line, this removes the requirement for double quotes in jsx/tsx. The single quotes in jsx help bluehawk replace testIDs in the generated snippets for the docs
'react-hooks/exhaustive-deps': 0,
'react/jsx-max-props-per-line': [0, {'maximum': 4, 'when': 'multiline'}],
},
};
14 changes: 14 additions & 0 deletions examples/react-native/__tests__/js/models/Profile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Realm from 'realm';
// :snippet-start: js-profile-schema
class Profile extends Realm.Object {
static schema = {
name: 'Profile',
primaryKey: '_id',
properties: {
_id: 'uuid',
name: 'string',
},
};
}
// :snippet-end:
export default Profile;
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React, {useState} from 'react';
import {Button, TextInput, View} from 'react-native';
import {render, fireEvent, waitFor, act} from '@testing-library/react-native';
import Realm from 'realm';
import {createRealmContext} from '@realm/react';
import Profile from '../../models/Profile';

const realmConfig = {
schema: [Profile],
deleteRealmIfMigrationNeeded: true,
};

const {RealmProvider, useRealm} = createRealmContext(realmConfig);

let assertionRealm;

// test describe block for the uuid schema
describe('uuid schema', () => {
beforeEach(async () => {
// we will use this Realm for assertions to access Realm Objects outside of a Functional Component (like required by @realm/react)
assertionRealm = await Realm.open(realmConfig);

// delete every object in the realmConfig in the Realm to make test idempotent
assertionRealm.write(() => {
assertionRealm.delete(assertionRealm.objects(Profile));

new Profile(assertionRealm, {
name: 'Tony Stark',
_id: new Realm.BSON.UUID(),
});
});
});
afterAll(() => {
if (!assertionRealm.isClosed) {
assertionRealm.close();
}
});

it('should be able to create a new uuid', async () => {
// :snippet-start: create-uuid-object
// :replace-start: {
// "terms": {
// " testID='nameInput'": "",
// " testID='createProfileButton'": ""
// }
// }
const CreateProfileInput = () => {
const realm = useRealm();
const [name, setName] = useState('');

// createProfile creates a new 'Profile' Realm Object with a new UUID based on user input
const createProfile = () => {
realm.write(() => {
new Profile(realm, {
name,
_id: new Realm.BSON.UUID(),
});
});
};
return (
<View>
<TextInput testID='nameInput' placeholder='Name' onChangeText={setName} />
<Button testID='createProfileButton' title='Create Profile' onPress={createProfile} />
</View>
);
// :replace-end:
// :snippet-end:
};
const App = () => (
<RealmProvider>
<CreateProfileInput />
</RealmProvider>
);

const {getByTestId} = render(<App />);

// Test that the createProfileButton's onPress method creates a new Profile Object with a new UUID
const nameInput = await waitFor(() => getByTestId('nameInput'), {
timeout: 5000,
});
const createProfileButton = await waitFor(() => getByTestId('createProfileButton'), {timeout: 5000});

await act(() => {
fireEvent.changeText(nameInput, 'Steve Rogers');
});
await act(() => {
fireEvent.press(createProfileButton);
});

// Test that the Profile Object with the new UUID was created using the assertionRealm and that the name is correct
const profiles = assertionRealm.objects(Profile);
expect(profiles.length).toBe(2);
expect(profiles[1].name).toBe('Steve Rogers');
});
});
18 changes: 18 additions & 0 deletions examples/react-native/__tests__/ts/models/Profile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Realm from 'realm';
// TODO: Replace `static schema` with TS-first models + realm-babel-plugin (https://www.npmjs.com/package/@realm/babel-plugin) approach once realm-babel-plugin version 0.1.2 releases with bug fixes
// :snippet-start: ts-profile-schema
class Profile extends Realm.Object<Profile> {
_id!: Realm.BSON.UUID;
name!: string;

static schema = {
name: 'Profile',
primaryKey: '_id',
properties: {
_id: 'uuid',
name: 'string',
},
};
}
// :snippet-end:
export default Profile;
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React, {useState} from 'react';
import {Button, TextInput, View} from 'react-native';
import {render, fireEvent, waitFor, act} from '@testing-library/react-native';
import Realm from 'realm';
import {createRealmContext} from '@realm/react';
import Profile from '../../models/Profile';

const realmConfig = {
schema: [Profile],
deleteRealmIfMigrationNeeded: true,
};

const {RealmProvider, useRealm} = createRealmContext(realmConfig);

let assertionRealm: Realm;

// test describe block for the uuid schema
describe('uuid schema', () => {
beforeEach(async () => {
// we will use this Realm for assertions to access Realm Objects outside of a Functional Component (like required by @realm/react)
assertionRealm = await Realm.open(realmConfig);

// delete every object in the realmConfig in the Realm to make test idempotent
assertionRealm.write(() => {
assertionRealm.delete(assertionRealm.objects(Profile));

new Profile(assertionRealm, {
name: 'Tony Stark',
_id: new Realm.BSON.UUID(),
});
});
});
afterAll(() => {
if (!assertionRealm.isClosed) {
assertionRealm.close();
}
});

it('should be able to create a new uuid', async () => {
// :snippet-start: create-uuid-object
// :replace-start: {
// "terms": {
// " testID='nameInput'": "",
// " testID='createProfileButton'": ""
// }
// }
const CreateProfileInput = () => {
const realm = useRealm();
const [name, setName] = useState('');

// createProfile creates a new 'Profile' Realm Object with a new UUID based on user input
const createProfile = () => {
realm.write(() => {
new Profile(realm, {
name,
_id: new Realm.BSON.UUID(),
});
});
};
return (
<View>
<TextInput testID='nameInput' placeholder='Name' onChangeText={setName} />
<Button testID='createProfileButton' title='Create Profile' onPress={createProfile} />
</View>
);
// :replace-end:
// :snippet-end:
};
const App = () => (
<RealmProvider>
<CreateProfileInput />
</RealmProvider>
);

const {getByTestId} = render(<App />);

// Test that the createProfileButton's onPress method creates a new Profile Object with a new UUID
const nameInput = await waitFor(() => getByTestId('nameInput'), {
timeout: 5000,
});
const createProfileButton = await waitFor(() => getByTestId('createProfileButton'), {timeout: 5000});

await act(() => {
fireEvent.changeText(nameInput, 'Steve Rogers');
});
await act(() => {
fireEvent.press(createProfileButton);
});

// Test that the Profile Object with the new UUID was created using the assertionRealm and that the name is correct
const profiles = assertionRealm.objects(Profile);
expect(profiles.length).toBe(2);
expect(profiles[1].name).toBe('Steve Rogers');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class Profile extends Realm.Object {
static schema = {
name: 'Profile',
primaryKey: '_id',
properties: {
_id: 'uuid',
name: 'string',
},
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const CreateProfileInput = () => {
const realm = useRealm();
const [name, setName] = useState('');

// createProfile creates a new 'Profile' Realm Object with a new UUID based on user input
const createProfile = () => {
realm.write(() => {
new Profile(realm, {
name,
_id: new Realm.BSON.UUID(),
});
});
};
return (
<View>
<TextInput placeholder='Name' onChangeText={setName} />
<Button title='Create Profile' onPress={createProfile} />
</View>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class Profile extends Realm.Object<Profile> {
_id!: Realm.BSON.UUID;
name!: string;

static schema = {
name: 'Profile',
primaryKey: '_id',
properties: {
_id: 'uuid',
name: 'string',
},
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const CreateProfileInput = () => {
const realm = useRealm();
const [name, setName] = useState('');

// createProfile creates a new 'Profile' Realm Object with a new UUID based on user input
const createProfile = () => {
realm.write(() => {
new Profile(realm, {
name,
_id: new Realm.BSON.UUID(),
});
});
};
return (
<View>
<TextInput placeholder='Name' onChangeText={setName} />
<Button title='Create Profile' onPress={createProfile} />
</View>
);
61 changes: 51 additions & 10 deletions source/sdk/react-native/realm-database/schemas/uuid.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,59 @@ Overview

``UUID`` (Universal Unique Identifier) is a 16-byte :wikipedia:`unique value
<Universally_unique_identifier>`. You can use ``UUID`` as an identifier for
objects. ``UUID`` is :ref:`indexable <react-native-indexes>` and you can use it as a
objects. ``UUID`` is :ref:`indexable <react-native-indexes>`, and you can use it as a
:ref:`primary key <react-native-primary-keys>`.

.. include:: /includes/note-using-uuid-instead-of-objectid.rst
.. tabs-realm-languages::

.. tab::
:tabid: typescript

.. literalinclude:: /examples/generated/react-native/ts/Profile.snippet.ts-profile-schema.ts
:language: typescript

.. tab::
:tabid: javascript

.. literalinclude:: /examples/generated/react-native/js/Profile.snippet.js-profile-schema.js
:language: javascript

Usage
-----
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[minor] I know you didn't change line 38 in this PR, but we may want to remove "the string". I think readers will understand its a string, and mentioning it here may confuse some readers - make them think that the object type is a string.

To define a property as a ``UUID``, set its type to the string ``"uuid"`` in
your :ref:`object model <react-native-object-schemas>`. Create a Realm
object within a write transaction. To set any unique identifier properties of
your object to a random value, call ``new UUID()``. Alternatively, pass a string
to ``new UUID()`` to set the unique identifier property to a specific value.

.. literalinclude:: /examples/generated/node/data-types.snippet.work-with-uuid.js
:language: javascript
To define a property as a ``UUID``, set its type to ``"uuid"`` in your
:ref:`object model <react-native-object-schemas>`. Create a Realm object within
a write transaction. To set any unique identifier properties of your object to a
random value, call ``new UUID()``. Alternatively, pass a string to ``new
UUID()`` to set the unique identifier property to a specific value.

Example
~~~~~~~

In the following ``CreateProfileInput`` example, we create a ``Profile``
:js-sdk:`Realm.Object <Realm.Object.html>` with a ``uuid`` type for the ``_id``
field.

The ``CreateProfileInput`` component does the following:

- Gets access to the opened realm instance by calling the ``useRealm()`` hook.
- Creates a name `state variable <https://reactjs.org/docs/hooks-state.html>`__ called "name" that represents the name of the profile.
- Creates a ``createProfile`` method that performs a write transaction. Within that write transaction, we :ref:`create <react-native-create-a-new-object>` a ``Profile`` object with the ``name`` value of the "name" state variable and an ``_id`` value of a new ``UUID`` object.
- Renders a ``TextInput`` component that allows the user to enter a name for the profile. When the user presses the "Create Profile" button, the ``createProfile`` method is called and creates a ``Profile`` object.

.. tabs-realm-languages::

.. tab::
:tabid: typescript

.. literalinclude:: /examples/generated/react-native/ts/uuid.test.snippet.create-uuid-object.tsx
:language: typescript
:emphasize-lines: 2, 7-12
:linenos:

.. tab::
:tabid: javascript

.. literalinclude:: /examples/generated/react-native/js/uuid.test.snippet.create-uuid-object.jsx
:language: javascript
:emphasize-lines: 2, 7-12
:linenos: