Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
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.
- Host: GitHub
- URL: https://github.com/marianozunino/morpheus
- Owner: marianozunino
- License: mit
- Created: 2022-02-18T20:45:50.000Z (almost 3 years ago)
- Default Branch: master
- Last Pushed: 2024-01-29T20:07:18.000Z (12 months ago)
- Last Synced: 2024-10-07T08:40:58.921Z (3 months ago)
- Topics: cli, database, database-migrations, migration, migrations, neo4j, nestjs, nodejs, typescript
- Language: TypeScript
- Homepage:
- Size: 1.21 MB
- Stars: 19
- Watchers: 2
- Forks: 4
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
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)
![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)### 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 semicolonExample 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 typeFLAGS
-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 constraintsGLOBAL FLAGS
--debug Enable debug logging
--json Format output as json.DESCRIPTION
Clean up migration-related database objectsRemoves 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 codeEXAMPLES
$ 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 objectsRemoves 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 existsDESCRIPTION
Initialize a new Morpheus configuration file with database connection settingsEXAMPLES
$ 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 orderEXAMPLES
$ 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)_
### 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 variablesawait 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.