arangom is an ArangoDB migration tool written in Go. It is heavily inspired by ArangoMiGo which is already a great tool.
Using brew
$ brew tap gabor-boros/brew
$ brew install arangom
Manual install
To install arangom
, use one of the release artifacts. If you have go
installed, you can build from source as well.
go get github.com/gabor-boros/arangom
Migrations are a set of operations that are executed in a given order. The operations are executed in the order they are defined in the migration.
When a migration is executed, depending on the status of the operations, the
migration is marked as missing
, running
, done
or failed
. If a migration
is marked as missing
or running
, that means that the migration is not
executed yet, therefore those migrations will be executed. If a migration is
marked as done
, it is skipped. In the case of a failed
migration, the
migration is skipped along with all the migrations that follow it and an error
is returned.
The lifecycle of a migration is the following:
- The migration is marked as
missing
. - When executing the migration, the migration is marked as
running
. - When the migration is marked as
done
orfailed
based on the result of the operations.
Every migration has a checksum that is calculated based on a unique ID and the
operations of the migration. The checksum is used to determine if a migration
has changed since the last execution. If the checksum of a migration has changed
since the last execution, the migration is marked as missing
and will be
executed again.
Migrations are stored in YAML files and are executed in alphabetical order. The files are expected to be in the following schema:
id: <numerical ID> # unique identifier of the migration, only used for checksum
operations: # list of operations to execute in the given order
- kind: <operation kind> # the kind of the operation
collection: <collection name> # the name of the collection to operate on
options: <options> # the options of the operation
# ...
Example:
id: 1677564649
operations:
- kind: createCollection
collection: mycollection
options:
waitForSync: true
cacheEnabled: true
schema:
level: moderate
message: The document does not match the schema.
rule:
properties:
kind:
type: string
maximum: 12
additionalProperties:
type: string
required:
- kind
The files are expected to be in a migrations
directory in the current
working directory, but this can be changed with the -migration-dir
command line flag.
The migration directory can be structured in subdirectories as desired, arangom will recursively search for migration files.
package main
import (
"context"
"os"
arangoDriver "github.com/arangodb/go-driver"
arangoHTTP "github.com/arangodb/go-driver/http"
arangoMigrate "github.com/gabor-boros/arangom"
)
func main() {
conn, _ := arangoHTTP.NewConnection(arangoHTTP.ConnectionConfig{
Endpoints: []string{os.Getenv("ARANGO_URL")},
})
client, _ := arangoDriver.NewClient(arangoDriver.ClientConfig{
Connection: conn,
Authentication: arangoDriver.BasicAuthentication(os.Getenv("ARANGO_USER"), os.Getenv("ARANGO_PASSWORD")),
})
db, _ := client.Database(context.Background(), os.Getenv("ARANGO_DB"))
migrations := []*arangom.Migration{
{
Path: "0001.initial", // any unique identifier
Operations: []arangom.Operation{
{
Kind: arangom.OperationKindCollectionCreate,
Collection: os.Getenv("ARANGO_MIGRATION_COLLECTION"),
Options: map[string]any{
"waitForSync": true,
},
},
},
},
}
executor, _ := arangom.NewExecutor(
arangom.WithDatabase(db),
arangom.WithCollection(os.Getenv("ARANGO_MIGRATION_COLLECTION")),
arangom.WithMigrations(migrations),
)
if err := executor.Execute(context.Background()); err != nil {
panic(err)
}
}
$ arangom -username "root" -password "openSesame" -database "mydb" -migration-dir "migrations"
2023/02/28 06:47:43 [INFO] connecting to the migration collection "migrations"
2023/02/28 06:47:43 [INFO] [1677564649] fetching migration status
2023/02/28 06:47:43 [INFO] [1677564649] executing migration
2023/02/28 06:47:43 [INFO] [1677564649] migration executed successfully
2023/02/28 06:47:43 [INFO] [1677564650] fetching migration status
2023/02/28 06:47:43 [INFO] [1677564650] executing migration
2023/02/28 06:47:43 [INFO] [1677564650] migration executed successfully
2023/02/28 06:47:43 [INFO] all migrations executed successfully
Usage of arangom:
-collection string
Migration collection (default "migrations")
-create-collection
Create migration collection if it does not exist (default true)
-database string
Database name
-endpoints string
Comma-separated list of database endpoints (default "http://localhost:8529")
-migration-dir string
Migration directory (default "migrations")
-password string
Database password
-username string
Database user
-version
Print version and exit
The options of the operations are the same as the request body options of the corresponding ArangoDB operations. However, some operations have additional options that are not supported by ArangoDB. These options are documented in the table below with the caveat column. For more information about operation options, please refer to the ArangoDB documentation.
Operation kind | Description | Caveats |
---|---|---|
executeAQL |
Executes an AQL query. | executeAQL |
createCollection |
Creates a new collection. | - |
updateCollection |
Updates an existing collection. | - |
deleteCollection |
Deletes an existing collection. | - |
createGraph |
Creates a new graph. | createGraph |
addVertexToGraph |
Adds a vertex collection to a graph. | addVertexToGraph |
removeVertexFromGraph |
Removes a vertex collection from a graph. | removeVertexFromGraph |
addEdgeToGraph |
Adds an edge definition to a graph. | addEdgeToGraph |
removeEdgeFromGraph |
Removes an edge definition from a graph. | removeEdgeFromGraph |
deleteGraph |
Deletes an existing graph. | deleteGraph |
createView |
Creates a new search view. | createView |
updateView |
Updates an existing search view. | updateView |
deleteView |
Deletes an existing search view. | deleteView |
createFulltextIndex |
Creates a fulltext index. | createFulltextIndex |
createGeoSpatialIndex |
Creates a Geo-spatial index. | createGeoSpatialIndex |
createHashIndex |
Creates a hash index. | createHashIndex |
createInvertedIndex |
Creates an inverted index. | - |
createPersistentIndex |
Creates a persistent index. | createPersistentIndex |
createSkipListIndex |
Creates a skiplist index. | createSkipListIndex |
createTTLIndex |
Creates a TTL index. | createTTLIndex |
createZKDIndex |
Creates a ZKD index. | createZKDIndex |
deleteIndex |
Deletes an index. | deleteIndex |
createAnalyzer |
Creates an analyzer. | createAnalyzer |
deleteAnalyzer |
Deletes an analyzer. | deleteIndex |
Database operations are intentionally not supported. To apply migrations on a database, create the database first. Feature requests and/or pull requests are welcomed for other missing operations.
Executing AQL queries has no options defined by ArangoDB, though it is possible
to bind variables to the query. The executeAQL
operation therefore has the
following options:
Option name | Description |
---|---|
query |
The AQL query to execute. |
bindVars |
The bind variables of the query. |
The graph name is defined in the collection
field of the operation.
The graph name is defined in the collection
field of the operation. The
options of the operation is extended with the following options:
Option name | Description |
---|---|
collection |
The name of the vertex collection to add to the graph. |
The graph name is defined in the collection
field of the operation. The
options of the operation is extended with the following options:
Option name | Description |
---|---|
collection |
The name of the vertex collection to remove from the graph. |
The graph name is defined in the collection
field of the operation. The
options of the operation is extended with the following options:
Option name | Description |
---|---|
collection |
The name of the edge definition to add to the graph. |
constraints |
The edge constraints of the edge definition. |
The edge constraints
are defined as follows:
Option name | Description |
---|---|
from |
The list of name of the vertex collections that the edge definition starts from. |
to |
The list of name of the vertex collections that the edge definition ends to. |
The graph name is defined in the collection
field of the operation. The
options of the operation is extended with the following options:
Option name | Description |
---|---|
collection |
The name of the edge definition to add to the graph. |
The graph name is defined in the collection
field of the operation.
The view name is defined in the collection
field of the operation.
The view name is defined in the collection
field of the operation.
The options of the operation is extended with the following options:
Option name | Description |
---|---|
fields |
The list of fields to index. |
The options of the operation is extended with the following options:
Option name | Description |
---|---|
fields |
The list of fields to index. |
The options of the operation is extended with the following options:
Option name | Description |
---|---|
fields |
The list of fields to index. |
The options of the operation is extended with the following options:
Option name | Description |
---|---|
fields |
The list of fields to index. |
The options of the operation is extended with the following options:
Option name | Description |
---|---|
fields |
The list of fields to index. |
The options of the operation is extended with the following options:
Option name | Description |
---|---|
field |
The field to index. |
expireAfter |
The expiration time in seconds. |
The options of the operation is extended with the following options:
Option name | Description |
---|---|
fields |
The list of fields to index. |
The options of the operation is extended with the following options:
Option name | Description |
---|---|
name |
The name of the index to delete. |
In case analyzer with the same name already exists, the operation will fail.
Option name | Description |
---|---|
name |
The name of the analyzer to create. |
type |
The type of the analyzer to create. |
properties |
The properties of the analyzer to create. |
features |
The array of features of the analyzer to create. |
Option name | Description |
---|---|
name |
The name of the analyzer to delete. |
force |
Delete even if in use. |
The compatibility of arangom is equal to the compatibility of the ArangoDB Go driver. For more information, please refer to the ArangoDB Go driver documentation.
ArangoMiGo is a great tool, but it is highly opinionated and has design decisions that are not flexible enough. Refactoring ArangoMiGo to be more flexible would be a huge effort, almost a rewrite. Therefore, I created a new project instead.
The naming is indeed confusing, and I am open to suggestions.
Contributions are welcomed! Please open an issue or a pull request.
This project is licensed under the MIT License - see the LICENSE file for details.