JavaScript Class Support

With Node v6.10 and higher, we've cross the chasm where we finally have full class support. Classes are one of the best and most versatile ways to represent structured data. If you're familiar with the Swift APIs, this should look incredibly familiar. First let's see how we used to get data and compare it with the new way.

The Old Way ☹️

const Realm = require('realm-js')
const uuid = require('uuid')

const CarSchema = {
    name: 'Car'
    properties: {
        _id: {type: 'string', optional: false, indexed: true, default: uuid.v4() },
        mileage: {type: 'int', optional: true, default: 0},
        make: {type: 'string', optional: true}
    }
}

class Car  {
    _id = uuid.v4()
    mileage = 0
    make = null
}

const realm = new Realm({
    schema: [CarSchema]
})

//write to the realm
const newCar = new Car()
newCar.make = 'toyota'
newCar.mileage = 483762
realm.write(() => {
    realm.create(
})

:Problems with this Approach:

  1. Constructing the Realm is noticeably different from the Swift APIs since you now have to feed it the schema every time
  2. The class Car is almost completely unknowing of the CarSchema yet they represent the same idea
  3. Developers are put in an awkward situation of repeating code

The New Way! 🙏

Let's take full advantage of ECMAScript Classes and also add some additional support for tooling like TypeScript and Babel. Don't worry, if you want to use vanilla JS we also got you covered!

import { Types, Optional, PrimaryKey, Object as RealmObject } from 'realm'

class Car {

    @PrimaryKey
    _id = uuid.v4()    

    @Types.Int32
    mileage = 0

    @Optional
    @Types.String
    make = null

}

const realm = new Realm() // 

//write to the realm
const newCar = new Car()
newCar.make = 'toyota'
newCar.mileage = 483762
realm.write(() => {
    realm.create(newCar)
})

With this new approach we have an API that is incredibly similar to the Swift API. Yet, we still respect a comfortable JavaScript development experience.

How did we achieve this?!

Realm always needs to know about the "name" of the object that it is trying to store as well as some information for the Schema. As we chose to use ECMAScript6 decorators, which are just helpful functions, we can achieve an API and a user-friendliness very much like our iOS SDK

ECMAScript Decorators are simply functions that you can use to edit the target object or property. Here's a great blog post from Google Developers that show the power of Decorators.

Let's just show what the @Optional decorator is really like

function Optional(target, key, descriptor) {
   let schemaPropertyRow = target.__schema.properties[key]
   if(schemaProperty){
      schemaProperty = {}
   }
   schemaProperty.optional = true
}

What if I don't have Babel or TypeScript?

Well now you can do something like this. This is actually the end code that the decorators end up generating anyway!

class Car {
    __schema = {
        name: 'Car'
        primaryKey: "_id",
        properties: {
            _id: {type: 'string', optional: false, indexed: true, default: uuid.v4() },
            mileage: {type: 'int', optional: true, default: 0},
            make: {type: 'string', optional: true}
        }
    }
    _id = uuid.v4()
    mileage = 0
    make = null
}

As you can see all we did was create a new property called __schema on our Model Class. Yes that's a double underscore, for extra private! 😈

How do we get the name of your class?

Before we had classes, it was really hard to get the name of your data structure. But the constructor function always allows you to get the name easily.

class Car { }
const car = new Car()
const nameOfClass = car.constructor.name // this will return 'Car'

What if I want to explicity state or override the name of my class?

You can do this in two flavors, with decorators or without decorators. Here's an example with decorators.

import { ObjectName } from 'realm'

@ObjectName('Automobile')
class Car {
    @Types.String
    _id: String
    //... your other properties
}

The above decorator will simply edit the __schema.name property and set it to "Automobile".

results matching ""

    No results matching ""