generator-realm-migration

1.1.7 • Public • Published

Realm Migration Generator

A generator for creating linear migrations for realm-js projects

Example Source Code

Index

Summary

  • This generator will created a mirgrations directory.
  • In that directory there will be sub directories for each migration that contain previous versions of the ObjectSchema for each Model.
  • The subdirectories are named after the schema description for that migration and the computed schema version(i.e. 0-added-dogs_object_schema).
  • In addition there is a migration.js file generated in each sub directory that is responsible for doing the migration business logic to reach that schema version.
  • The scaffolded migrations directory is intended to expose an array of linear migrations that could consumed by client code.

Getting Started

  1. Install yeoman globally: npm i -g yeoman
  2. Install generator-realm-migration: npm i --save generator-realm-migration
  3. From your React Native project dir run: yo realm-migration:init
  4. Then after adding some Models to your models directory, run: yo realm-migration --schemaDesc="updated_one_of_my_tables"

Usage

Requirements

  • MODELS DIRECTORY : You must have one. In that directory you should have Realm.ObjectClass files only. An index.js file in the only exception.
  • MODEL FILES : Each must have named export for an Realm.ObjectClass that matches the file name minus the extension.
  • MIGRATIONS DIRECTORY : You will have one after running the init command: yo realm-migration:init. This default command(i.e yo realm-migration) will scaffold migration directories in there and update the index.js file for the benefit of importing the export of each migration directory.

User Input for Default Command

  • The default command will ask you to delete a temp Directory. This is normal because we create that directory for transpilation purposes so that we can consume the output.
  • The default command will ask you to overwrite the migrations/index.js file. This is normal because you will continue to add more migrations which necessitates an update of that file.

Example Command Usage

  • Default Command
    • All option defaults: yo realm-migration
    • With schema change description option: yo realm-migration --schemaDesc="added-dog_object_schema"
    • With all options specified:
      yo realm-migration --schemaDesc="added-dog_object_schema" --objectSchemaFileSuffix='Model' --schemaVersion="0" --isTypescript=1 --sourceDir="source/" --modelDir='resources/models/' --migrationDir="config/migrations/"
  • Init Command
    • All option defaults: yo realm-migration:init
    • With all options specified: yo realm-migration:init --migrationDir="source/config/migrations/" --isTypescript=1

Full Example with Source and Output Files

Structure

  • Beggining Structure

    /
      /src
        /models
          Dog.ts
          index.js
      migrateRealm.js
      index.js
      ...
    
  • Structure after yo realm-migration:init

    /
      /src
        /models
          Dog.js
          index.js
        /migrations
          index.js
      migrateRealm.js
      index.js
      ...
    
  • Structure after yo realm-migration --schemaDesc='added-dog_object_schema'

    /
      /src
        /models
          Dog.ts
          index.js
        /migrations
          index.js
          /0-added-dog_object_schema
            Dog.js
            migration.js
            index.js
      migrateRealm.js
      index.js
      ...
    

Files

models/Dog.js
  const schema = {
      name: 'Dog',
      properties: {
          name: {type: 'string'},
      },
  };
  
  export class Dog {
      static schema = schema;
      name = '';
  }
models/index.js
  import { Dog } from './Dog';
  export const Models = [Dog];
migrations/index.js
  const migrations = [];
 
  import migration1 from './0-added-dog_object_schema/';
  migrations.push(migration1);
 
  export default migrations;
migrations/0-added-dog_object_schema/Dog.js
  export default {
      name: 'Dog',
      properties: {
          name: {type: 'string'},
      },
  };
migrations/0-added-dog_object_schema/migration.js

(Example here)

  export default (oldRealm, newRealm) => {
      // TODO: Do something in here for the migration!
  }
migrations/0-added-dog_object_schema/index.js
  import migrationCallback from './migration';
 
  const schemas = [];
  
  import Dog from './Dog';
  
  schemas.push(Dog);
  
  export default {
    schema: schemas,
    schemaVersion: 0,
    migration: migrationCallback,
  };
migrateRealm.js
  import { Models } from './models/';
  import Realm from 'realm';
  import migrations from './migrations/';
  
  
  export const migrateRealm = () => {
    // Will be -1 if the Realm at the path has never been opened before.
    let schemaVersion = Realm.schemaVersion('dogs-realm');
    schemaVersion = schemaVersion !== -1 ? schemaVersion : 0;
    if (migrations.length === 0) {
      return {schema: Models, path: 'dogs-realm', schemaVersion };
    }
    // 2. Get the index of the migration where we are currently at
    let nextMigrationsIndex = -1;
    for (let index = 0; index < migrations.length; index++) {
      const migration = migrations[index];
      if (migration.schemaVersion === schemaVersion) {
        nextMigrationsIndex = index;
        break;
      }
    }
    // 3. Lets move onto the next migration, since we know that this one has already been migrated to
    nextMigrationsIndex++;
    // 4. The next migration and all others that follow are going to be executed so that we incrementally migrate the Realm
    for (; nextMigrationsIndex < migrations.length; nextMigrationsIndex++) {
      const migratedRealm: Realm = new Realm({
        ...migrations[nextMigrationsIndex],
        path: 'dogs-realm',
      });
      migratedRealm.close();
    }
  
    // 5. Now that we have migrated the Realm up to the most current version let's return the proper configuration
    return {
      schema: Models,
      schemaVersion: migrations[migrations.length - 1].schemaVersion,
      path: 'dogs-realm'
    };
  };
 
index.js
import React, { Component } from 'react';
import { Text, View } from 'react-native';
import { migrateRealm } from './migrateRealm';
import Realm from 'realm';
 
export default class RealmMigrate extends Component {
    constructor(props) {
        super(props);
        this.state = { realm: undefined, status: 'Loading App...', version: -1 };
    }
 
    componentWillMount() {
        const configuration = migrateRealm();
        const version = configuration.schemaVersion;
        return Realm.open(configuration)
            .catch((e) => {
                const isTypeError = e instanceof TypeError;
                const isFailedNetworkRequest = e.message === 'Network request failed';
                if (isTypeError && isFailedNetworkRequest) {
                    this.setState({status: 'Server could not be reached.'});
                } else if (isTypeError) {
                    this.setState({status: e.message});
                } else {
                    this.setState({status: 'Unknown error'});
                }
            })
            .then((realm) => {
                this.setState({realm, version });
            })
            ;
    }
 
    render() {
        if (this.state.realm === undefined) {
            return (
                <View>
                    <Text>{this.state.status}</Text>
                </View>
            );
        }
        return (
            <View style={{flex: 1}}>
                <Text>{`Realm Migrations Example rendered for Version ${this.state.version}!`}</Text>
            </View>
        );
    }
}

Commands

Default command: realm-migration

NOTE - All <name>Dir options must include an ending slash(i.e. src/). sourceDir and modelDir must be relative.

Used for generating migrations after the init command has been executed.

Options

Name Default Purpose
isTypescript false Indicates whether or not Typescript should be consumed and outputted.
sourceDir src/ Indicates where the root of your Migration and Model directories reside.
modelDir models/ Indicates the directory relative to sourceDir where your Models reside.
migrationDir migrations/ Indicates the directory relative to sourceDir where your Migrations reside.
tempDir temp/ Indicates what the name of the temporary directory relative to where you run the command should be.
The dir gets deleted at the end of the generating a migration.
shcemaVersion 0 Explicitly specify the schema version number.
Good for when your first saved schema version is greater than 0.
This is the case if you have an exsiting project that uses Realm where the schema version is past 0.
schemaDesc '' Describes the migration that is going to be created
(i.e. (computed schema version)-(added/removed/updated)-(x)_object_schema)
objectSchemaFileSuffix '' Indicates what the suffix of the Realm.ObjectClass file should be
(i.e. object 'Event' would have a 'EventModel' class in a file named 'EventModel')
This will be DEPRECATED soon because it's actually not necessary.

Init command: realm-migration:init

NOTE - All <name>Dir options must include an ending slash(i.e. src/migrations/).

Used for scaffolding the initial migrations structure such that your code that depends on that structure won't fail if it's not there.

Options

Name Default Purpose
isTypescript false Indicates whether or not Typescript should be consumed and outputted.
migrationDir src/migrations Indicates where the migrations directory resides in your project

Todo

  1. Write tests
  2. More flexibility for options and how Realm ObjectSchemas can be defined/consumed by the generator
  3. Add code for sample React Native component that calls migrateRealm.

Package Sidebar

Install

npm i generator-realm-migration

Weekly Downloads

8

Version

1.1.7

License

GPL-3.0-or-later

Unpacked Size

62.9 kB

Total Files

10

Last publish

Collaborators

  • 509dave16