This package is inspired by TypeORM style of migration management. It tracks migrations directly inside neo4j database and runs them in order.
- WIP, lacks tests and not ready for production use
- Beware that Neo4j migrations cannot have both schema and data changes in the same migration!
- CLI for reverting is lacking but functional
- No generation of migrations yet
- A lot of infrastructure for this package is based on excellent nest-nsq-transport package by Oleg Repin
npm i nestjs-neo4j-migrations
import { Global, Module } from '@nestjs/common';
import { Neo4jDriverModule } from 'nestjs-neo4j-migrations';
import { migrations } from './migrations';
@Global()
@Module({
imports: [
Neo4jDriverModule.forRoot({
uri: process.env.NEO4J_URI,
username: process.env.NEO4J_USERNAME,
password: process.env.NEO4J_PASSWORD,
migrations,
}),
],
})
export class Neo4jModule {}
import { Global, Module } from '@nestjs/common';
import { Neo4jDriverModule } from 'nestjs-neo4j-migrations';
import { Config } from './config';
import { migrations } from './migrations';
@Module({
imports: [
Neo4jDriverModule.forRootAsync({
inject: [Config],
useFactory: (config: Config) => ({
uri: config.neo4jUri,
username: config.neo4jUser,
password: config.neo4jPassword,
migrations,
}),
}),
],
})
export class Neo4jModule {}
This acts as datasource options file, it should export an array of migrations (see example of one below), uri, username and password.
// migrations/index.ts
import dotenv from 'dotenv';
import { Neo4jMigrationList } from 'nestjs-neo4j-migrations';
import { InitMigration1234 } from './1234-Init';
dotenv.config();
export const migrations: Neo4jMigrationList = [
InitMigration1234,
// ... append more migrations here
];
export const uri = process.env.NEO4J_URI;
export const username = process.env.NEO4J_USERNAME;
export const password = process.env.NEO4J_PASSWORD;
Note that key can be any sequential number, but it is recommended to use timestamp for it.
Make sure your up() and down() methods are idempotent.
Use IF NOT EXISTS
and IF EXISTS
to avoid errors when running migrations multiple times.
Note: session is exposed to allow multi-transactional migrations on large datasets, when memory is a concern. In most cases you'll want to use single transaction. Learn more here https://neo4j.com/docs/javascript-manual/current/transactions/
import { Neo4jMigration, Neo4jSession } from 'nestjs-neo4j-migrations';
export class AddIndex1723704012000 implements Neo4jMigration {
readonly key = 1723704012000;
async up(session: Neo4jSession): Promise<void> {
await session.executeWrite((trx) =>
trx.run(`CREATE INDEX ageId IF NOT EXISTS FOR (e:employees) ON (e.age)`),
);
// Beware that if you change schema (indexes, constraints, etc) you cannot have data changes in the same migration, you'll have to split them.
}
async down(session: Neo4jSession): Promise<void> {
const trx = session.beginTransaction();
await trx.run(`DROP INDEX ageId IF EXISTS`);
await trx.commit();
}
}
npx nestjs-neo4j-migrations revert -c ./migrations
In this example migrations directory contains index.ts
file described above.