@realm/babel-plugin
v0.2.0
Published
Babel plugin making it easier to declare your Realm schema
Downloads
2,749
Readme
Realm Babel Plugin
Introduction
The Realm Babel plugin enables defining your Realm models using standard Typescript syntax - no need to define a separate schema.
class Task extends Realm.Object<Task, "description"> {
_id!: Realm.BSON.ObjectId;
description!: string;
isComplete!: boolean;
static schema = {
name: "Task",
primaryKey: "_id",
properties: {
_id: "objectId",
description: "string",
isComplete: {
type: "bool",
default: false,
indexed: true,
},
},
};
constructor(realm, description: string) {
super(realm, {
_id: new Realm.BSON.ObjectId(),
description,
});
}
}
class Task extends Realm.Object<Task, "description"> {
_id = new Realm.BSON.ObjectId();
description!: string;
@index
isComplete = false;
static primaryKey = "_id";
constructor(realm, description: string) {
super(realm, { description });
}
}
Features
- Schema properties can be defined as class properties by using standard TypeScript types or specific
Realm.Types
types, supporting every Realm type - Support for default values using property initialiser syntax
- Support for specifying additional schema properties (e.g. primary key) using class statics
- Support for indexing and remapping fields using decorators
Installation
Install the
@realm/babel-plugin
npm package:npm install --save-dev @realm/babel-plugin
If you don't already have it installed, install the
@babel/plugin-proposal-decorators
package (only required if you need to use the@index
or@mapTo
decorators):npm install --save-dev @babel/plugin-proposal-decorators
and enable decorators in your
tsconfig.json
by adding:"experimentalDecorators": true
to thecompilerOptions
.Update your project's
babel.config.js
to load these two plugins:// Existing babel.config.js content is commented out // module.exports = { // presets: ['module:metro-react-native-babel-preset'], // -------------------------- // Add the following plugins: plugins: [ '@realm/babel-plugin', ['@babel/plugin-proposal-decorators', { legacy: true }], ], // -------------------------- // };
If using React Native, you may need to clear your packager cache for it to pick up the new plugins:
npm start -- --reset-cache
Usage
Defining model properties
To define your Realm models when using this plugin, simply create classes which extend Realm.Object
, and define the model's properties using either supported TypeScript types or Realm.Types
types (see supported types). It is recommended that you use the non-null assertion operator (!
) after the property name, to tell TypeScript that the property will definitely have a value.
You can use property initialiser syntax to specify a default value for a property, which can either be a static value or a function call for dynamic values.
The recommended pattern for constructing new instances with specified values for properties is to define a constructor which takes the properties as additional arguments. The second type parameter of Realm.Object
can be used to specify any fields which are required to be specified in the second fields
when an instance is constructed with new
- all properties are optional by default.
import Realm from "realm";
// Specify that the name and description fields are required when creating an instance with `new`
export class Task extends Realm.Object<Task, "name" | "description"> {
// Property initialiser syntax with a dynamic value - each instance will have a unique ID
_id = new Realm.BSON.ObjectId();
name!: string;
description!: string;
// Property initializer syntax with a static value
isComplete = false;
// Specifying the type of number to be stored in the Realm using Realm.Types
count!: Realm.Types.Int = 0;
}
You can also import Object
and Types
directly from realm
:
import { Object, Types, BSON } from "realm";
export class Task extends Object<Task, "name" | "description"> {
_id = BSON.ObjectId();
name: string;
description!: string;
isComplete = false;
count!: Types.Int;
}
Supported types
This plugin supports standard TypeScript types wherever possible, to make defining your model as natural as possible. Some Realm types do not have a direct TypeScript equivalent (e.g. double
, int
and float
are all represented by number
in TypeScript), so in these cases you should use the types provided by Realm.Types
.
As a rule, we recommend using TypeScript types where possible, and using Realm.Types
where you cannot, but you can also exclusively use types from Realm.Types
if preferred.
Types which are provided by Realm (e.g. Realm.List
) are exported from both the top-level Realm
namespace, and from Realm.Types
- you can use either variant in your models.
The supported types are shown in the table below. See the Realm documentation and SDK documentation for more details on each type.
| Realm.Types type | Realm schema type | TypeScript type | Realm type | Notes |
| -------------------------------------------- | ----------------- | --------------- | ----------------------- | -------------------------------------------------------------------------------------- |
| Types.Bool
| bool
| boolean
| | |
| Types.String
| string
| string
| | |
| Types.Int
| int
| | | |
| Types.Float
| float
| | | |
| Types.Double
| double
| number
| | Double is the default number type |
| Types.Decimal128
| decimal128
| | Realm.BSON.Decimal128
| |
| Types.ObjectId
| objectId
| | Realm.BSON.ObjectId
| |
| Types.UUID
| uuid
| | Realm.BSON.UUID
| |
| Types.Date
| date
| Date
| | |
| Types.Data
| data
| ArrayBuffer
| | |
| Types.List<T>
| type[]
| | Realm.List<T>
| T
is the type of objects in the list |
| Types.Set<T>
| type<>
| | Realm.Set<T>
| T
is the type of objects in the set |
| Types.Dictionary<T>
| type{}
| | Realm.Dictionary<T>
| T
is the type of objects in the dictionary |
| Types.Mixed
| mixed
| | Realm.Mixed
| |
| Types.LinkingObjects<T, N> | linkingObjects
| | | T
is the type of objects, N
is the property name of the relationship (as a string) |
Specifying schema properties as static
s
Additional schema properties can be specified by adding static
properties to your class, as shown in the table below. See the Realm documentation for more details.
| Static property | Type | Notes |
| --------------- | --------- | -------------------------------------------------------------------------- |
| name
| string
| Specifies the name of the Realm schema. Defaults to your class name. |
| primaryKey
| string
| Specifies the name of a property to be used as the primary key. |
| embedded
| boolean
| Specifies this is an embedded schema. |
| asymmetric
| boolean
| Specifies this schema should sync unidirectionally if using flexible sync. |
For example:
import Realm from "realm";
export class Task extends Realm.Object<Task, "description"> {
_id = new Realm.BSON.ObjectId();
description!: string;
isComplete = false;
static primaryKey = "_id";
}
Using decorators to index and remap properties
The @realm/babel-plugin
package exports decorators to allow you to specify certain properties should be indexed (using the @index
decorators) or should remap to a Realm schema property with a different name (using the @mapTo
decorator). To learn more about this functionality, see the documentation.
Note that use of decorators requires using the @babel/plugin-proposal-decorators
plugin and for experimentalDecorators
to be enabled in your tsconfig.json
. There is currently no way to specifying properties to be indexed or remapped without using decorators.
This table shows the available decorators:
| Decorator | Parameters | Notes |
|-----------|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| index
| none or ("full-text")
| Specifies that the decorated property should be indexed by Realm. Providing the string "full-text" specifies that the property should be indexed for full-text search by Realm. |
| mapTo
| (realmPropertyName: string)
| Specifies that the decorated property should be stored as realmPropertyName
in the Realm database. |
The example below shows both decorators in use:
import Realm from "realm";
import { mapTo, index } from "@realm/babel-plugin";
export class Task extends Realm.Object {
_id!: Realm.BSON.ObjectId;
// Add an index to the `assignee` property
@index
assignee!: string;
// Specify that the `description` property should be indexed for full-text search
@index("full-text")
description!: string;
// Specify that the `isComplete` property should be stored as `complete` in the Realm database
@mapTo("complete")
isComplete = false;
}
Restrictions
All class properties will be added to the Realm schema
There is currently no way to specify a property on your class which should not be persisted to the Realm.
Classes extending Realm.Object cannot be constructed with new
outside of a write transaction
This plugin does not change the behaviour of Realm.Object
, which cannot be constructed using new
outside of a write transaction - there is no concept of a Realm.Object which is not stored in a Realm. Constructing a Realm object with new
inside a write transaction will create a new object in the Realm - see class-based models in the CHANGELOG.
Debugging your model
To generate the output for your model (let's say it's located in ./models/task.ts
) you can run the babel transpiler manually on the file:
npm install --save-dev @babel/cli @babel/preset-typescript
npx babel --presets @babel/preset-typescript --plugins @realm/babel-plugin ./models/task.ts