Versioning.Schema (Versioning v0.4.1) View Source
Defines a versioning schema.
A versioning schema is used to change data through a series of steps from a "current" version to a "target" version. This is useful in maintaining backwards compatability with older versions of API's without enormous complication.
Example
defmodule MyApp.Versioning do
use Versioning.Schema, adapter: Versioning.Adapter.Semantic
version("2.0.0", do: [])
version "1.1.0" do
type "User" do
change(MyApp.Changes.SomeUserChange)
end
end
version "1.0.1" do
type "Post" do
change(MyApp.Changes.SomePostChange))
end
type "All!" do
change(MyApp.Changes.SomeAllChange)
end
end
version("1.0.0", do: [])
end
When creating a schema, an adapter must be specified. The adapter determines how
versions are parsed and compared. For more information on adapters, please see
Versioning.Adapter
.
In the example above, we have 4 versions. Our current version is represented by
the top version - "2.0.0"
. Our oldest version is at the bottom - "1.0.0"
.
We define a version with the version/2
macro. Within a version, we specify types
that have been manipulated. We define a type with the type/2
macro. Within
a type, we specify changes that have occured. We define a change with the change/2
macro.
Running Schemas
Lets say we have a %Post{}
struct that we would like to run through our schema.
post = %Post{status: :enabled}
Versioning.new(post, "2.0.0", "1.0.0")
We have created a new versioning of our post struct. The versioning sets the data, current version, target version, as well as type. We can now run our versioning through our schema.
{:ok, versioning} = MyApp.Versioning.run(versioning)
With the above, our versioning struct will first be run through our MyApp.Changes.SomePostChange
change module as the type matches our versioning type. It will then be run through
our MyApp.Changes.SomeAllChange as it also matches on the "All!
type (more detail
available at the change/2
macro).
With the above, we are transforming our data "down" through our schema. But we can also transform it "up".
post = %{"status" => "some_status"}
Versioning.new(post, "1.0.0", "2.0.0", "Post")
If we were to run our new versioning through the schema, the same change modules would be run, but in reverse order.
Change Modules
At the heart of versioning schemas are change modules. You can find more information
about creating change modules at the Versioning.Change
documentation.
Schema attributes
Supported attributes for configuring the defined schema. They must be
set after the use Versioning.Schema
call.
These attributes are:
@latest
- configures the schema latest version. By default, this will be the version at the top of your schema. But if you do not wish to have this behaviour, you can set it here.
Reflection
Any schema module will generate the __schema__
function that can be
used for runtime introspection of the schema:
__schema__(:down)
- Returns the data structure representing a downward versioning.__schema__(:up)
- Returns the data structure representing an upward versioning.__schema__(:adapter)
- Returns the versioning adapter used by the schema.__schema__(:latest, :string)
- Returns the latest version in string format.__schema__(:latest, :parsed)
- Returns the latest version in parsed format.
Link to this section Summary
Functions
Defines a change within a type.
Defines a type within a version.
Defines a version in the schema.
Link to this section Types
Specs
Specs
direction() :: :up | :down
Specs
result() :: Versioning.t() | [Versioning.t()] | no_return()
Specs
schema() :: [version()]
Specs
t() :: module()
Specs
Specs
Link to this section Functions
Defines a change within a type.
A change must be represented by a module that implements the Versioning.Change
behaviour. You can also set options that will be passed along to the change module.
Changes are run in the order they are placed, based on the direction of the version change. For instance, if a schema was being run "down" for the example below, MyChangeModule would be run first, followed by MyOtherChangeModule. This would be reversed if running "up" a schema.
Example
version "1.0.1" do
type "Foo" do
change(MyChangeModule)
change(MyOtherChangeModule, [foo: :bar])
end
end
Defines a type within a version.
A type can only be represented once within a version, and must be a string. Any
issue with this will raise a Versioning.CompileError
during compilation.
Typically, it should be represented in "CamelCase"
format.
Any changes within a type that matches the type on a Versioning
struct will
be run. There is also the special case "All!"
type, which lets you define
changes that will be run against all versionings - regardless of type.
Example
version "1.0.1" do
type "All!" do
end
type "Foo" do
end
end
Defines a version in the schema.
A version must be in string format, and must adhere to requirements of the
Elixir Version
module. This means SemVer 2.0.
A version can only be represented once within a schema. The most recent version should be at the top of your schema, and the oldest at the bottom.
Any issue with the above will raise a Versioning.CompileError
during schema
compilation.
Example
version "1.0.1" do
end
version("1.0.0", do: [])