Morpheus is a database migration tool for Neo4j written in Typescript.
Morpheus is a modern, open-source, database migration tool for Neo4j. It is designed to be a simple, intuitive tool for database migrations. It is inspired by Michael Simons tool for Java.
Install the latest version of Morpheus:
npm install morpheus4jAdd a script to your project's package.json file:
"scripts": {
"morpheus": "morpheus"
}To run migrations, first you need to configure Morpheus. To do so, create a .morpheus.json file in your project root directory.
Or, you can use the
initcommand:
npm run morpheus initIf you don't want to use a morpheus.json file, you can also use ENV variables as follows:
MORPHEUS_SCHEME=neo4j
MORPHEUS_HOST=localhost
MORPHEUS_PORT=7687
MORPHEUS_USERNAME=neo4j
MORPHEUS_PASSWORD=neo4j
MORPHEUS_MIGRATIONS_PATH=neo4j/migrations # default value# deprecated
NEO4J_SCHEME=neo4j
NEO4J_HOST=localhost
NEO4J_PORT=7687
NEO4J_USERNAME=neo4j
NEO4J_PASSWORD=neo4jYou can create/generate migrations using the morpheus create command or create the files manually.
For the first, just issue the command:
npm run morpheus create <migration_name>Migrations will be created under the neo4j/migrations directory. Each migration will be a Cypher file following the format V<sem_ver>__<migration_name>.cypher.
If you want to create/add the migration manually make sure to follow the naming convention as stated in Michael's tool documentation.
You can run migrations by running the following command:
npm run morpheus migrateThis will run all migrations in the neo4j/migrations directory.
You can use Morpheus with the NestJs framework.
Migrations will be run automatically when the application is started
The biggest difference is that you don't need to create a .morpheus.json file and you can use any name for the ENV variables.
You can instantiate the module using the forRoot or forRootAsync methods.
import { Module } from '@nestjs/common';
import { MorpheusModule } from 'morpheus4j';
import { ConfigModule, ConfigService } from '@nestjs/config';
@Module({
imports: [
ConfigModule.forRoot(),
// Using forRootAsync with Dependency Injection
MorpheusModule.forRootAsync({
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
scheme: configService.get("MORPHEUS_SCHEME"),
host: configService.get("MORPHEUS_HOST"),
port: configService.get("MORPHEUS_PORT"),
username: configService.get("MORPHEUS_USERNAME"),
password: configService.get("MORPHEUS_PASSWORD"),
migrationsPath: "./neo4j/migrations", // default value
}),
}),
// Using forRoot method
MorpheusModule.forRoot({
scheme: "neo4j",
host: "localhost",
port: 7687,
username: "neo4j",
password: "neo4j",
migrationsPath: "./migrations",
}),
}),
],
})
export class AppModule {}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 em 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.
You can take a look at schema and explanation on Michael's README there's a neat graph that shows the migration chain.
