api-tools-0.2: 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 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.

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 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 db rec 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;
  • Record migrations, which may change the schema of a single record; and
  • Single field migrations, which may change only the type of the field (with the new type specified in the changelog).

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

The db, rec 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.

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; similarly a union is a map from fields to alternatives 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

afTypeName :: TypeName
 
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 a, Eq b) => Eq (MergeResult a b) 
(Show a, Show b) => Show (MergeResult a b) 

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