Schema Migration Reference Guide

Schema migration allows us to move schema and instance data together automatically in a replayable fashion. This is essential for allowing flexible schemas to co-exist nicely with change-requests and merges.

The schema operations can be performed directly on the branch of interest, or you can target the schema of a given branch in another branch, allowing the migrations to be re-performed such that a new common schema is obtained.

In addition, schema migrations can be inferred in some cases, and TerminusCMS will attempt to silently infer migrations which will not impact instance data.

However, some schema operations require instance data to change, and such alterations must be asked for explicitly.

Schema Migration Operations

There are a number of schema operations which can be performed which will change one schema into another. These are specified by passing an ordered list of operations. The operations are sometimes order dependent so different operations orders can lead to different changes to the instance data.

Some operations are known as weakening operations, as they can always be performed without altering the existing instance data. These are essentially backward compatible operations. This includes changing a range to a less specific or optional range, adding new optional fields, or adding new classes.

DeleteClass

The DeleteClass operation will remove a class from a schema. This does not change the range of properties, so these properties must first be dropped before deleting a class is possible.

Due to the fact that existing instance data of this class will be deleted, this is not a weakening operation.

{ "@type" : "DeleteClass",
  "class" : <ClassName> }

An example of the operation would be:

{ "@type" : "DeleteClass",
  "class" : "Person" }

Which would take the schema:

{ "@id" : "Dog",
  "@type" : "Class",
  "name" : "xsd:string"}
{ "@id" : "Person",
  "@type" : "Class",
  "name" : "xsd:string" }

to:

{ "@id" : "Dog",
  "@type" : "Class",
  "name" : "xsd:string"}

CreateClass

The CreateClass operation specifies the entire class to be created. This operation is always a weakening operation.

{ "@type" : "CreateClass",
  "class_document" : <ClassDocument> }

Example

The migration:

{ "@type" : "CreateClass",
  "class_document" :
  { "@id" : "Person",
    "@type" : "Class",
    "name" : "xsd:string" } }

Would take the schema:

{ "@id" : "Dog",
  "@type" : "Class",
  "name" : "xsd:string" }

to:

{ "@id" : "Dog",
  "@type" : "Class",
  "name" : "xsd:string"}
{ "@id" : "Person",
  "@type" : "Class",
  "name" : "xsd:string" }

MoveClass

The MoveClass operation renames a class and all of the URIs of instance data associated with that class. Due to the side-effects on instance data, this is not a weakening operation.

{ "@type" : "MoveClass",
  "from" : <FromClassName>,
  "to" : <ToClassName> }

Example

{ "@type" : "MoveClass",
  "from" : "Person",
  "to" : "Dog" }

Would take the schema:

{ "@id" : "Person",
  "@type" : "Class",
  "name" : "xsd:string"}

to:

{ "@id" : "Dog",
  "@type" : "Class",
  "name" : "xsd:string"}

ReplaceClassMetadata

The ReplaceClassMetadata operation replaces the metadata on a class (if it exists). This operation is always a weakening operation and has no effect on instance data.

{ "@type" : "ReplaceClassMetadata",
  "class" : <ClassName>
  "metadata" : <Metadata> }

Example

The operation:

{ "@type" : "ReplaceClassMetadata",
  "class" : "Person",
  "metadata" : { "ui_preferences" : { "colour" : "blue" } } }

Would take the schema:

{ "@id" : "Person",
  "@type" : "Class",
  "@metadata" : { "ui_preferences" : { "colour" : "red" } },
  "name" : "xsd:string"}

to:

{ "@id" : "Dog",
  "@type" : "Class",
  "@metadata" : { "ui_preferences" : { "colour" : "blue" } },
  "name" : "xsd:string" }

ReplaceClassDocumentation

The ReplaceClassDocumentation operation replaces the documentation on a class (if it exists). This operation is always a weakening operation and has no effect on instance data.

{ "@type" : "ReplaceClassDocumentation",
  "class" : <ClassName>
  "documentation" : <Documentation> }

Example

The operation:

{ "@type" : "ReplaceClassDocumentation",
  "class" : "Person",
  "documentation" : { "@comment" : "This is a person class",
                      "@properties" : { "name" : { "@comment" : "The name of a person",
                                                    "@label" : "name" } },
                      "@label" : "Person" } }

Would take the schema:

{ "@id" : "Person",
  "@type" : "Class",
  "@documentation" : { "@comment" : "A Person",
                       "@properties" : { "name" : { "@comment" : "Name of a person",
                                                    "@label" : "name" } },
                       "@label" : "Person" },
  "name" : "xsd:string"}

to:

{ "@id" : "Person",
  "@type" : "Class",
  "@documentation" : { "@comment" : "This is a person class",
                      "@properties" : { "name" : { "@comment" : "The name of a person",
                                                   "@label" : "name" } },
                      "@label" : "Person" },
  "name" : "xsd:string"}

ReplaceContext

The ReplaceContext operation will update the context object, which will change how URIs are compressed when returning data.

This operation is a weakening operation only when prefixes other than @base and @schema are changed. Otherwise, all data in the database will be moved to the new @base and @schema designations.

{ "@type" : "ReplaceContext",
  "context" : <Context> }

ExpandEnum

The ExpandEnum operation will allow new fields to be added to an Enum. This operation is always a weakening operation.

{ "@type" : "ExpandEnum",
  "enum" : <EnumName>,
  "values" : [<Value0>, ... <ValueN>] }

Example

The command

{ "@type" : "ReplaceContext",
  "context" : { "@type" : "@context",
                "@base" : "iri://terminusdb.com/data",
                "@schema" : "iri://terminusdb.com/schema#" } }

Will take a schema:

{ "@type" : "@context",
  "@base" : "http://example.com/data",
  "@schema" : "http://example.com/schema#" }
{ "@id" : "Person",
  "@type" : "Class",
  "name" : "xsd:string"}

To the schema:

{ "@type" : "@context",
  "@base" : "iri://terminusdb.com/data",
  "@schema" : "iri://terminusdb.com/schema#" }
{ "@id" : "Person",
  "@type" : "Class",
  "name" : "xsd:string"}

DeleteClassProperty

The DeleteClassProperty command removes a property from the schema and deletes all associated data points in the instance graph. This is not a weakening operation.

{ "@type" : "DeleteClassProperty",
  "class" : <ClassName>
  "property" : <PropertyName> }

CreateClassProperty

The CreateClassProperty command creates a new property of a given name and type. It is a weakening operation only if the type is within a type family which includes:

  • Cardinality including zero
  • A Set
  • An Optional
  • An Array

Notably this excludes lists and required properties. With lists it will require the addition of the empty list resulting in a strengthening. The operation is impossible with a required property unless a default is specified.

{ "@type" : "CreateClassProperty",
  "class" : <ClassName>,
  "property" : <PropertyName>,
  "type" : <Type> }

Or

{ "@type" : "CreateClassProperty",
  "class" : <ClassName>,
  "property" : <PropertyName>,
  "type" : <Type>,
  "default" : <DefaultValue> }

MoveClassProperty

The MoveClassProperty command will move the name of a property from one name to another.

{ "@type" : "MoveClassProperty",
  "class" : <ClassName>,
  "from" : <PropertyName>,
  "to" : <PropertyName> }

This operation is never a weakening.

UpcastClassProperty

The UpcastClassProperty command will weaken a type to another type which is a supertype or inclusive type family (such as moving a required or Optional to Set).

This operation is always a weakening.

{ "@type" : "UpcastClassProperty",
  "class" : <ClassName>
  "property" : <PropertyName>,
  "type" : <TypeSpecification> }

CastClassProperty

The CastClassProperty command will attempt to cast a property type to another type (such as a string to a date). This operation is never a weakening operation as it requires changing the type layout of data.

{ "@type" : "CastClassProperty",
  "class" : <ClassName>
  "property" : <PropertyName>,
  "type" : <TypeSpecification>,
  "default" : <DefaultOrError> }

The `DefaultOrError document is of the form:

{ "@type" : "Error" }

Which will result in an error if casting is impossible, or:

{ "@type" : "Default",
  "value" : <Value> }

Where Value is the value within type TypeSpecification which will be used if casting is impossible.

ChangeKey (unimplemented)

ChangeParents (unimplemented)

ChangeCollection (unimplemented)