Migrations
Migrations are what makes your Stately Schema Elastic! They allow you to evolve your schema over time without breaking existing clients. A powerful feature of Stately’s Elastic Schema is that every version of your schema is active all the time. This means that you can read or write items from any version of your schema, and Stately will automatically apply the necessary migrations.
To get started with migrations, use the migrate
function in either the same schema file or a separate TypeScript file. The migration
function accepts the version you’re migrating from, a human-readable description, and a Migrator
function.
A Migrator
function lets you define any number of actions to take the current schema that Stately knows about to
an updated version. You may wish to compose all your actions in one
migrate
block, or split them up for clarity/documentation. However, the order of actions and the migration
blocks are important.
migrate
Example
The following examples represent the same migration from version 1
while demonstrating several ways to structure your migrations.
These are by no means the only way to structure your migrations. You can mix and match these actions in any order
that makes sense for your schema evolution.
One Block
Separate Blocks
Separate Files
You may also find it useful to move migrations into separate file(s) and order them in an index file.
Now that you have your migrations defined in a separate file, you can order them in an index.ts
file.
Actions
Actions are instructions that tells Stately how to change the shape of your schema. They are persisted when you call stately schema put
and instruct
Stately how to migrate items between versions when reading or writing. You may find references to all the available actions below.
AddType
Adding a new objectType
, itemType
, or enumType
is as simple as passing the name of your new type to the
addType
migration. This type must exist in your new schema version and not the old version.
Newer versions can read/write to this new type, while older versions won’t. Stately will handle filtering this new type out of list/sync calls from older versions.
RemoveType
Similar to AddType, removing an objectType
, itemType
or enumType
is just as easy. Pass the name of the type
you want to remove to the removeType
migration.
When you remove a type from your schema, newer schema versions will no longer see this type. In other words, the items or fields that reference the removed type are still accessible for older versions of the schema but newer versions of the schema cannot.
RenameType
This action will rename an existing type in the schema. If you reference this type in subsequent migration actions, you
must use the NewType
name.
When you rename a type, the wire format for the type will not change, only the name of the type. This means that older and newer versions of the schema can still read/write to the type.
AddField
Adds a new field to a type. Only required: false
fields can be added for now.
Support for adding required fields will be added in a future release.
Newer versions can read/write to this new field, while older versions won’t see this field. If a client uses an older version to update an item that has new fields in other schema versions, those fields will be untouched. In other words, there is no way to replace the whole object, Stately only replaces the fields known to the caller’s schema version. We will be adding more flexibility to the merge semantics in the future.
RemoveField
Removes an existing field from a type. Only required: false
fields can be removed for now.
Support for removing required fields will be added in a future release.
Newer versions can read/write to this type without the field, while older versions will still see the field untouched. In other words, there’s currently no way for a newer client to zero out this removed field for older clients. We will be adding more flexibility to the merge semantics in the future.
RenameField
Renames an existing field from a type. If you reference this field in subsequent migration actions
you must use the newName
.
When you rename a field, the wire format for the field will not change, only the name of the field. This means that older and newer versions of the schema can still read/write to the field.