api-tools-0.8.0.1: DSL for generating API boilerplate and docs

Safe HaskellNone
LanguageHaskell2010

Data.API.Changes

Contents

Description

This module deals with validating API changelogs and migrating JSON data between different versions of a schema.

Synopsis

Documentation

migrateDataDump Source #

Arguments

:: (Read db, Read rec, Read fld) 
=> (API, Version)

Starting schema and version

-> (API, VersionExtra)

Ending schema and version

-> APIChangelog

Log of changes, containing both versions

-> CustomMigrations Object Value db rec fld

Custom migration functions

-> TypeName

Name of the dataset's type

-> DataChecks

How thoroughly to validate changes

-> Value

Dataset to be migrated

-> Either MigrateFailure (Value, [MigrateWarning]) 

Migrate a dataset from one version of an API schema to another. The data must be described by a named type, the name of which is assumed not to change.

The db, rec and fld types must be enumerations of all the custom migration tags in the changelog, as generated by generateMigrationKind.

migrateDataDump' Source #

Arguments

:: (Read db, Read rec, Read fld) 
=> (API, Version)

Starting schema and version

-> (API, VersionExtra)

Ending schema and version

-> APIChangelog

Log of changes, containing both versions

-> CustomMigrations Record Value db rec fld

Custom migration functions

-> TypeName

Name of the dataset's type

-> DataChecks

How thoroughly to validate changes

-> Value

Dataset to be migrated

-> Either MigrateFailure (Value, [MigrateWarning]) 

Validating changelogs

validateChanges Source #

Arguments

:: (Read db, Read rec, Read fld) 
=> (API, Version)

Starting schema and version

-> (API, VersionExtra)

Ending schema and version

-> APIChangelog

Changelog to be validated

-> CustomMigrations o v db rec fld

Custom migration functions

-> TypeName

Name of the dataset's type

-> DataChecks

How thoroughly to validate changes

-> Either ValidateFailure [ValidateWarning] 

Check that a changelog adequately describes how to migrate from one version to another.

dataMatchesAPI :: TypeName -> API -> Value -> Either (ValueError, Position) () Source #

Check that a dataset matches an API, which is necessary for succesful migration. The name of the dataset's type must be specified.

data DataChecks Source #

When to validate the data against the schema (each level implies the preceding levels):

Constructors

NoChecks

Not at all

CheckStartAndEnd

At start and end of the migration

CheckCustom

After custom migrations

CheckAll

After every change

Changelog representation

data APIChangelog Source #

An API changelog, consisting of a list of versions with the changes from one version to the next. The versions must be in descending order (according to the Ord Version instance).

Constructors

ChangesUpTo VersionExtra [APIChange] APIChangelog

The changes from the previous version up to this version.

ChangesStart Version

The initial version

data VersionExtra Source #

Represents either a released version (with a version number) or the version under development, which is newer than any release

Constructors

Release Version 
DevVersion 

changelogStartVersion :: APIChangelog -> Version Source #

The earliest version in the changelog

changelogVersion :: APIChangelog -> VersionExtra Source #

The latest version in the changelog

Custom migrations

data CustomMigrations o v db ty fld Source #

Custom migrations used in the changelog must be implemented in Haskell, and supplied in this record. There are three kinds:

  • Whole-database migrations, which may arbitrarily change the API schema and the data to match;
  • Type migrations, which may change the schema of a single type; and
  • Single field migrations, which may change only the type of the field (with the new type specified in the changelog).

For database and type migrations, if the schema is unchanged, the corresponding function should return Nothing.

The db, ty and fld parameters should be instantiated with the enumeration types generated by generateMigrationKinds, which correspond to the exact set of custom migration tags used in the changelog.

mkRecordMigration :: (Object -> Either ValueError Object) -> Value -> Either ValueError Value Source #

Lift a custom record migration to work on arbitrary values

mkRecordMigrationSchema :: TypeName -> (NormRecordType -> Either ApplyFailure (Maybe NormRecordType)) -> NormTypeDecl -> Either ApplyFailure (Maybe NormTypeDecl) Source #

Lift a schema change on record types to work on arbitrary type declarations

noDataChanges :: a -> Either ValueError a Source #

Use for databaseMigration, typeMigration or fieldMigration to indicate that changes to the data are not required

noSchemaChanges :: a -> Either ApplyFailure (Maybe a) Source #

Use for databaseMigrationSchema or typeMigrationSchema to indicate that the schema should not be changed

generateMigrationKinds :: APIChangelog -> String -> String -> String -> Q [Dec] Source #

Generate enumeration datatypes corresponding to the custom migrations used in an API migration changelog.

type MigrationTag = String Source #

Within the changelog, custom migrations are represented as strings, so we have less type-safety.

API normal forms

type NormAPI = Map TypeName NormTypeDecl Source #

The API type has too much extra info for us to be able to simply compare them with (==). Our strategy is to strip out ancillary information and normalise into a canonical form, and then we can use a simple (==) compare.

Our normalised API discards most of the details of each type, keeping just essential information about each type. We discard order of types and fields, so we can use just associative maps.

data NormTypeDecl Source #

The normal or canonical form for a type declaration, an APINode. Equality of the normal form indicates equivalence of APIs.

We track all types.

type NormRecordType = Map FieldName APIType Source #

The canonical form of a record type is a map from fields to values...

type NormUnionType = Map FieldName APIType Source #

...similarly a union is a map from fields to alternatives...

type NormEnumType = Set FieldName Source #

...and an enum is a set of values.

apiNormalForm :: API -> NormAPI Source #

Compute the normal form of an API, discarding extraneous information.

declNF :: Spec -> NormTypeDecl Source #

Compute the normal form of a single type declaration.

Migration errors

data ValidateFailure Source #

Errors that may be discovered when validating a changelog

Constructors

ChangelogOutOfOrder

the changelog must be in descending order of versions

CannotDowngrade

forbid migrating from one version to an earlier version

ApiInvalid

an API uses types that are not declared

ChangelogEntryInvalid

changelog entry does not apply

ChangelogIncomplete

changelog is incomplete (ie all entries apply ok but result isn't the target api)

data ApplyFailure Source #

Errors that may occur applying a single API change

Constructors

TypeExists

for adding or renaming type

TypeDoesNotExist

for deleting or renaming a type

TypeWrongKind

e.g. it's not a record type

TypeInUse

cannot delete/modify types that are still used

Fields

TypeMalformed

type refers to a non-existent type

DeclMalformed

decl refers to a non-existent type

FieldExists

for adding or renaming a field

FieldDoesNotExist

for deleting or renaming a field

FieldBadDefaultValue

for adding a field, must be a default value compatible with the type

DefaultMissing

for adding a field to a table

TableChangeError

custom error in tableChange

data MergeResult a b Source #

Constructors

OnlyInLeft a 
InBoth a b 
OnlyInRight b 

Instances

(Eq b, Eq a) => Eq (MergeResult a b) Source # 

Methods

(==) :: MergeResult a b -> MergeResult a b -> Bool #

(/=) :: MergeResult a b -> MergeResult a b -> Bool #

(Show b, Show a) => Show (MergeResult a b) Source # 

Methods

showsPrec :: Int -> MergeResult a b -> ShowS #

show :: MergeResult a b -> String #

showList :: [MergeResult a b] -> ShowS #

data ValueError Source #

Errors that can be discovered when migrating data values

Constructors

JSONError JSONError

Data doesn't match schema

CustomMigrationError String Value

Error generated during custom migration

InvalidAPI ApplyFailure

An API change was invalid