Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/marianozunino/morpheus

Morpheus is database migration tool for Neo4j written in Typescript.
https://github.com/marianozunino/morpheus

cli database database-migrations migration migrations neo4j nestjs nodejs typescript

Last synced: about 3 hours ago
JSON representation

Morpheus is database migration tool for Neo4j written in Typescript.

Awesome Lists containing this project

README

        

# Morpheus

[![build-deploy](https://github.com/marianozunino/morpheus/actions/workflows/build_deploy.yml/badge.svg)](https://github.com/marianozunino/morpheus/actions/workflows/build_deploy.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)

Coverage Status

![npm type definitions](https://img.shields.io/npm/types/morpheus4j)
[![Downloads/week](https://img.shields.io/npm/dw/morpheus4j.svg)](https://npmjs.org/package/morpheus4j)
[![Version](https://img.shields.io/npm/v/morpheus4j.svg)](https://npmjs.org/package/morpheus4j)
Nest Logo

### About
Morpheus is a modern, open-source database migration tool for [Neo4j](http://neo4j.com). It is designed to be a simple, intuitive tool for managing database migrations. The project is inspired by [Michael Simons' tool for Java](https://github.com/michael-simons/neo4j-migrations).

### Quick Start
```bash
npm install -g morpheus4j
morpheus init # Create config file
morpheus create user-nodes # Creates V1_0_0__user-nodes.cypher
morpheus migrate # Run migrations
```

### Prerequisites
- Node.js
- Neo4j database (4.4.4 or 5.x)
- npm or yarn package manager

### Migration Files
Migration files:
- Use `.cypher` extension
- Are versioned using semver (e.g., `V1_0_0__create_users.cypher`)
- Contain pure Cypher queries
- Each statement must end with a semicolon

Example migration file `V1_0_0__create_users.cypher`:
```cypher
CREATE CONSTRAINT user_email IF NOT EXISTS FOR (u:User) REQUIRE u.email IS UNIQUE;

CREATE (u:User {
email: '[email protected]',
name: 'Admin User',
created_at: datetime()
});
```

### File Naming Convention
Migration files follow this pattern:
- Prefix: `V` (for version)
- Version: Semver numbers separated by underscores (e.g., `1_0_0`)
- Separator: Double underscore `__`
- Description: Descriptive name using hyphens
- Extension: `.cypher`

Example: `V1_0_0__create-user-constraints.cypher`

### Environment Variables
Morpheus supports the following environment variables:
- `MORPHEUS_HOST` - Neo4j host
- `MORPHEUS_PORT` - Neo4j port
- `MORPHEUS_SCHEME` - Neo4j scheme
- `MORPHEUS_USERNAME` - Neo4j username
- `MORPHEUS_PASSWORD` - Neo4j password
- `MORPHEUS_DATABASE` - Neo4j database name
- `MORPHEUS_MIGRATIONS_PATH` - Path to migrations directory

### Best Practices
- Keep migrations small and focused
- Use descriptive names for migration files
- Test migrations in a development environment first
- Back up your database before running migrations in production
- Don't modify existing migrations - create new ones to make changes

### Troubleshooting
- **Checksum Mismatch**: Occurs when trying to modify an existing migration. Create a new migration instead.
- **Connection Issues**: Verify your Neo4j credentials and connection settings in morpheus.json
- **Missing Semicolons**: Ensure all Cypher statements end with semicolons

# Usage

```sh-session
$ npm install -g morpheus4j
$ morpheus COMMAND
running command...
$ morpheus (--version)
morpheus4j/4.2.0 linux-x64 node-v20.13.1
$ morpheus --help [COMMAND]
USAGE
$ morpheus COMMAND
...
```

# Commands

* [`morpheus autocomplete [SHELL]`](#morpheus-autocomplete-shell)
* [`morpheus clean`](#morpheus-clean)
* [`morpheus create NAME`](#morpheus-create-name)
* [`morpheus info`](#morpheus-info)
* [`morpheus init`](#morpheus-init)
* [`morpheus migrate`](#morpheus-migrate)

## `morpheus autocomplete [SHELL]`

Display autocomplete installation instructions.

```
USAGE
$ morpheus autocomplete [SHELL] [-r]

ARGUMENTS
SHELL (zsh|bash|powershell) Shell type

FLAGS
-r, --refresh-cache Refresh cache (ignores displaying instructions)

DESCRIPTION
Display autocomplete installation instructions.

EXAMPLES
$ morpheus autocomplete

$ morpheus autocomplete bash

$ morpheus autocomplete zsh

$ morpheus autocomplete powershell

$ morpheus autocomplete --refresh-cache
```

_See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v3.2.6/src/commands/autocomplete/index.ts)_

## `morpheus clean`

Clean up migration-related database objects

```
USAGE
$ morpheus clean [--json] [--debug] [--drop-constraints] [-c ] [-m ] [-h ] [-p
] [-s ] [-P ] [-u ] [-d ]

FLAGS
-P, --password= Neo4j password. Env: 'MORPHEUS_PASSWORD'
-c, --configFile= Path to the morpheus file. ./morpheus.json by default
-d, --database= Neo4j database. Env: 'MORPHEUS_DATABASE'
-h, --host= Neo4j host. Env: 'MORPHEUS_HOST'
-m, --migrationsPath= Migrations path. Env: 'MORPHEUS_MIGRATIONS_PATH'
-p, --port= Neo4j port. Env: 'MORPHEUS_PORT'
-s, --scheme= Neo4j scheme. Env: 'MORPHEUS_SCHEME'
-u, --username= Neo4j username. Env: 'MORPHEUS_USERNAME'
--drop-constraints Additionally remove all Morpheus-related database constraints

GLOBAL FLAGS
--debug Enable debug logging
--json Format output as json.

DESCRIPTION
Clean up migration-related database objects

Removes all Morpheus migration metadata including nodes, relationships, and optionally constraints.
Use with caution as this will reset the migration history.

EXAMPLES
$ morpheus clean

$ morpheus clean --drop-constraints

$ morpheus clean --config ./custom-config.json
```

_See code: [src/commands/clean.ts](https://github.com/marianozunino/morpheus/blob/v4.2.0/src/commands/clean.ts)_

## `morpheus create NAME`

Generate a new timestamped migration file with boilerplate code

```
USAGE
$ morpheus create NAME [--json] [-c ] [-m ]

ARGUMENTS
NAME Name of the migration (will be prefixed with a semver number)

FLAGS
-c, --configFile= Path to the morpheus file. ./morpheus.json by default
-m, --migrationsPath= Migrations path. Env: 'MORPHEUS_MIGRATIONS_PATH'

GLOBAL FLAGS
--json Format output as json.

DESCRIPTION
Generate a new timestamped migration file with boilerplate code

EXAMPLES
$ morpheus create add-user-nodes

$ morpheus create update-relationships -m ~/path/to/migrations

$ morpheus create update-relationships --config ./custom-config.json
```

_See code: [src/commands/create.ts](https://github.com/marianozunino/morpheus/blob/v4.2.0/src/commands/create.ts)_

## `morpheus info`

Info up migration-related database objects

```
USAGE
$ morpheus info [--json] [--debug] [-c ] [-m ] [-h ] [-p ] [-s ] [-P
] [-u ] [-d ]

FLAGS
-P, --password= Neo4j password. Env: 'MORPHEUS_PASSWORD'
-c, --configFile= Path to the morpheus file. ./morpheus.json by default
-d, --database= Neo4j database. Env: 'MORPHEUS_DATABASE'
-h, --host= Neo4j host. Env: 'MORPHEUS_HOST'
-m, --migrationsPath= Migrations path. Env: 'MORPHEUS_MIGRATIONS_PATH'
-p, --port= Neo4j port. Env: 'MORPHEUS_PORT'
-s, --scheme= Neo4j scheme. Env: 'MORPHEUS_SCHEME'
-u, --username= Neo4j username. Env: 'MORPHEUS_USERNAME'

GLOBAL FLAGS
--debug Enable debug logging
--json Format output as json.

DESCRIPTION
Info up migration-related database objects

Removes all Morpheus migration metadata including nodes, relationships, and optionally constraints.
Use with caution as this will reset the migration history.

EXAMPLES
$ morpheus info

$ morpheus info --config ./custom-config.json
```

_See code: [src/commands/info.ts](https://github.com/marianozunino/morpheus/blob/v4.2.0/src/commands/info.ts)_

## `morpheus init`

Initialize a new Morpheus configuration file with database connection settings

```
USAGE
$ morpheus init [-c ] [-f]

FLAGS
-c, --configFile= Path to the morpheus file. ./morpheus.json by default
-f, --force Overwrite existing configuration file if it exists

DESCRIPTION
Initialize a new Morpheus configuration file with database connection settings

EXAMPLES
$ morpheus init

$ morpheus init --force

$ morpheus init --config ./custom-path/morpheus.json

$ morpheus init --config .config.json --force
```

_See code: [src/commands/init.ts](https://github.com/marianozunino/morpheus/blob/v4.2.0/src/commands/init.ts)_

## `morpheus migrate`

Execute pending database migrations in sequential order

```
USAGE
$ morpheus migrate [--json] [--debug] [-c ] [-m ] [-h ] [-p ] [-s ] [-P
] [-u ] [-d ] [--dry-run] [--transaction-mode PER_MIGRATION|PER_STATEMENT]

FLAGS
-P, --password= Neo4j password. Env: 'MORPHEUS_PASSWORD'
-c, --configFile= Path to the morpheus file. ./morpheus.json by default
-d, --database= Neo4j database. Env: 'MORPHEUS_DATABASE'
-h, --host= Neo4j host. Env: 'MORPHEUS_HOST'
-m, --migrationsPath= Migrations path. Env: 'MORPHEUS_MIGRATIONS_PATH'
-p, --port= Neo4j port. Env: 'MORPHEUS_PORT'
-s, --scheme= Neo4j scheme. Env: 'MORPHEUS_SCHEME'
-u, --username= Neo4j username. Env: 'MORPHEUS_USERNAME'
--dry-run Perform a dry run - no changes will be made to the database
--transaction-mode= [default: PER_MIGRATION] Transaction mode

GLOBAL FLAGS
--debug Enable debug logging
--json Format output as json.

DESCRIPTION
Execute pending database migrations in sequential order

EXAMPLES
$ morpheus migrate

$ morpheus migrate -m ~/path/to/migrations

$ morpheus migrate --config ./custom-config.json

$ morpheus migrate --dry-run

$ morpheus migrate --transaction-mode=PER_STATEMENT
```

_See code: [src/commands/migrate.ts](https://github.com/marianozunino/morpheus/blob/v4.2.0/src/commands/migrate.ts)_

# NestJs Integration Nest Logo

### Module Usage

```ts
import { MorpheusModule, MorpheusService, Neo4jConfig, Neo4jScheme } from '../../dist/nestjs';
import { Module, Injectable } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';

@Module({
imports: [MorpheusModule, ConfigModule.forRoot()],
providers: [MigrationsService],
})
export class MigrationsModule {}

@Injectable()
export class MigrationsService {
constructor(
private readonly morpheusService: MorpheusService,
private readonly configService: ConfigService,
) {}

async onApplicationBootstrap() {
// When no config is provided, the default config is used
// -> morpheus.json
// -> moprheus environment variables

await this.morpheusService.cleanDatabase(); // NOTE: You probably don't want to do this, specially in production
await this.morpheusService.runMigrations();

// Use the ConfigService to access the environment variables
const configs: Neo4jConfig[] = [
{
scheme: Neo4jScheme.BOLT,
host: 'localhost',
port: 7687,
username: 'neo4j',
password: 'password',
migrationsPath: '../neo4j/migrations',
},
];

for (const config of configs) {
// Clean and run migrations
await this.morpheusService.cleanDatabase(config); // NOTE: You probably don't want to do this, specially in production
await this.morpheusService.runMigrations(config);
}
}
}
```

# How it works

The approach is simple. Morpheus will read all migrations in the `neo4j/migrations` directory and execute them in order.

For each migration, Morpheus will create a transaction and execute the migration. Thus a migration may contain multiple Cypher statements (**each statement must end with `;`**).

Once a migration file is executed, Morpheus will keep track of the migration and will not execute it again.

Existing migration files that have already been executed **can not** be modified since they are stored in a database with their corresponding checksum (crc32).

If you want to revert a migration, create a new migration and revert the changes.

## How does neo4j keep track of the migrations?

You can take a look at schema and explanation on [Michael's README](https://michael-simons.github.io/neo4j-migrations/2.2.0/#concepts_chain) - there's a neat graph that shows the migration chain.

### Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.