Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: memory storage #220

Merged
merged 14 commits into from
May 7, 2020
6 changes: 2 additions & 4 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module.exports = {
'unicorn',
'jest',
'import',
'codegen',
],
env: { 'jest/globals': true },
extends: [
Expand All @@ -22,6 +23,7 @@ module.exports = {
ignorePatterns: ['lib', 'node_modules'],
globals: { __dirname: true, process: true },
rules: {
'codegen/codegen': 'warn',
'prettier/prettier': [
'warn',
{
Expand Down Expand Up @@ -80,9 +82,5 @@ module.exports = {

'unicorn/prevent-abbreviations': 'off',
'unicorn/consistent-function-scoping': 'off',

// for backwards compatibility, allow legacy filenames to survive.
// consider forcing a change for next major version though.
'unicorn/filename-case': 'off',
},
};
59 changes: 30 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ The following example uses a Sqlite database through sequelize and persists the

```js
const { Sequelize } = require('sequelize');
const { Umzug } = require('umzug');
const { Umzug, SequelizeStorage } = require('umzug');

const sequelize = new Sequelize({ dialect: 'sqlite', storage: './db.sqlite' });

Expand All @@ -36,8 +36,7 @@ const umzug = new Umzug({
sequelize.getQueryInterface()
]
},
storage: 'sequelize',
storageOptions: { sequelize }
storage: new SequelizeStorage({ sequelize })
});

(async () => {
Expand Down Expand Up @@ -270,29 +269,40 @@ Storages define where the migration data is stored.

#### JSON Storage

Using the `json` storage will create a JSON file which will contain an array with all the executed migrations. You can specify the path to the file. The default for that is `umzug.json` in the working directory of the process.
Using `JSONStorage` will create a JSON file which will contain an array with all the executed migrations. You can specify the path to the file. The default for that is `umzug.json` in the working directory of the process.

Detailed documentation for the options it can take are in the `JSONStorageConstructorOptions` TypeScript interface, which can be found in [src/storage/json.ts](./src/storage/json.ts).

#### Memory Storage

Using `memoryStorage` will store migrations with an in-memory array. This can be useful for proof-of-concepts or tests, since it doesn't interact with databases or filesystems.

It doesn't take any options, just import the `memoryStorage` function and call it to return a storage instance:

Detailed documentation for the options it can take are in the `JSONStorageConstructorOptions` TypeScript interface, which can be found in [src/storages/JSONStorage.ts](./src/storages/JSONStorage.ts).
```typescript
import { Umzug, memoryStorage } from 'umzug'

const umzug = new Umzug({
migrations: ...,
storage: memoryStorage(),
})
```

#### Sequelize Storage

Using the `sequelize` storage will create a table in your SQL database called `SequelizeMeta` containing an entry for each executed migration. You will have to pass a configured instance of Sequelize or an existing Sequelize model. Optionally you can specify the model name, table name, or column name. All major Sequelize versions are supported.
Using `SequelizeStorage` will create a table in your SQL database called `SequelizeMeta` containing an entry for each executed migration. You will have to pass a configured instance of Sequelize or an existing Sequelize model. Optionally you can specify the model name, table name, or column name. All major Sequelize versions are supported.

Detailed documentation for the options it can take are in the `_SequelizeStorageConstructorOptions` TypeScript interface, which can be found in [src/storages/SequelizeStorage.ts](./src/storages/SequelizeStorage.ts).
Detailed documentation for the options it can take are in the `_SequelizeStorageConstructorOptions` TypeScript interface, which can be found in [src/storage/sequelize.ts](./src/storage/sequelize.ts).

#### MongoDB Storage

Using the `mongodb` storage will create a collection in your MongoDB database called `migrations` containing an entry for each executed migration. You will have either to pass a MongoDB Driver Collection as `collection` property. Alternatively you can pass a established MongoDB Driver connection and a collection name.
Using `MongoDBStorage` will create a collection in your MongoDB database called `migrations` containing an entry for each executed migration. You will have either to pass a MongoDB Driver Collection as `collection` property. Alternatively you can pass a established MongoDB Driver connection and a collection name.

Detailed documentation for the options it can take are in the `MongoDBStorageConstructorOptions` TypeScript interface, which can be found in [src/storages/MongoDBStorage.ts](./src/storages/MongoDBStorage.ts).
Detailed documentation for the options it can take are in the `MongoDBStorageConstructorOptions` TypeScript interface, which can be found in [src/storage/mongodb.ts](./src/storage/mongodb.ts).

#### Custom

In order to use custom storage, you have two options:

##### Method 1: Pass instance to constructor

You can pass your storage instance to Umzug constructor.
In order to use a custom storage, you can pass your storage instance to Umzug constructor.

```js
class CustomStorage {
Expand All @@ -301,27 +311,18 @@ class CustomStorage {
unlogMigration(...) {...}
executed(...) {...}
}
let umzug = new Umzug({ storage: new CustomStorage(...) })
```

Your instance must adhere to the [UmzugStorage](./src/storages/type-helpers/umzug-storage.ts) interface.
mmkal marked this conversation as resolved.
Show resolved Hide resolved

##### Method 2: Pass module name to be required

Create a module which has to fulfill the following API. You can just pass the name of the module to the configuration and *umzug* will require it accordingly.

The module must export a class that implements the [UmzugStorage](./src/storages/type-helpers/umzug-storage.ts) interface.
const umzug = new Umzug({ storage: new CustomStorage(...) })
```

For example, if you're using TypeScript:
Your instance must adhere to the [UmzugStorage](./src/storage/contract.ts) interface. If you're using TypeScript you can ensure this at compile time, and get IDE type hints by importing it:

```js
import { UmzugStorage } from 'umzug/lib/src/storages/type-helpers'
```typescript
import { UmzugStorage } from 'umzug'

class MyStorage implements UmzugStorage {
class CustomStorage implements UmzugStorage {
/* ... */
}

module.exports = MyStorage;
```

### Events
Expand Down
7 changes: 1 addition & 6 deletions legacy-tests/Umzug/constructor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,6 @@ describe('constructor', () => {
expect(umzug).to.have.property('storage');
});

it('loads the specified storage module', () => {
const umzug = new Umzug({ storage: 'lodash' });
expect(umzug).to.have.property('storage');
});

it('uses passed storage object', () => {
class CustomStorage {
logMigration () {}
Expand All @@ -45,7 +40,7 @@ describe('constructor', () => {
expect(() => {
new Umzug({ storage: 'nomnom' });
}).to.throw(
'Unable to resolve the storage: nomnom, Error: Cannot find module \'nomnom\''
'Invalid storage option received: nomnom'
);
});

Expand Down
6 changes: 3 additions & 3 deletions legacy-tests/Umzug/down.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { expect } = require('chai');
const helper = require('../helper');
const { Umzug } = require('../../lib/src/index');
const { Umzug, JSONStorage } = require('../../lib/src');
const { join } = require('path');

const downTestSuite = function downTestSuite () {
Expand Down Expand Up @@ -324,7 +324,7 @@ describe('down', () => {
this.migrationNames = migrationNames;
this.umzug = new Umzug({
migrations: { path: join(__dirname, '/../tmp/') },
storageOptions: { path: join(__dirname, '/../tmp/umzug.json') },
storage: new JSONStorage({ path: join(__dirname, '/../tmp/umzug.json') }),
});
});
});
Expand All @@ -341,7 +341,7 @@ describe('down-directories', () => {
this.migrationNames = migrationNames;
this.umzug = new Umzug({
migrations: { path: join(__dirname, '/../tmp/'), traverseDirectories: true },
storageOptions: { path: join(__dirname, '/../tmp/umzug.json') },
storage: new JSONStorage({ path: join(__dirname, '/../tmp/umzug.json') }),
});
});
});
Expand Down
10 changes: 5 additions & 5 deletions legacy-tests/Umzug/execute.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { expect } = require('chai');
const helper = require('../helper');
const { Umzug } = require('../../lib/src/index');
const { Umzug, JSONStorage } = require('../../lib/src');
const sinon = require('sinon');
const { join } = require('path');

Expand All @@ -18,7 +18,7 @@ describe('execute', () => {
this.logSpy = sinon.spy();
this.umzug = new Umzug({
migrations: { path: join(__dirname, '/../tmp/') },
storageOptions: { path: join(__dirname, '/../tmp/umzug.json') },
storage: new JSONStorage({ path: join(__dirname, '/../tmp/umzug.json') }),
logging: this.logSpy,
});
this.migrate = (method) => this.umzug.execute({
Expand Down Expand Up @@ -48,7 +48,7 @@ describe('execute', () => {
this.logSpy = sinon.spy();
this.umzug = new Umzug({
migrations: { path: join(__dirname, '/../tmp/') },
storageOptions: { path: join(__dirname, '/../tmp/umzug.json') },
storage: new JSONStorage({ path: join(__dirname, '/../tmp/umzug.json') }),
logging: this.logSpy,
});
return this.umzug.execute({
Expand Down Expand Up @@ -101,7 +101,7 @@ describe('execute', () => {

it('does not add an executed entry to the storage.json', function () {
return this.migrate('up').then(() => this.migrate('up')).then(() => {
const storage = require(this.umzug.options.storageOptions.path);
const storage = require(this.umzug.options.storage.path);
expect(storage).to.eql(['123-migration.js']);
});
});
Expand Down Expand Up @@ -177,7 +177,7 @@ describe('migrations.wrap', () => {
}
},
},
storageOptions: { path: join(__dirname, '/../tmp/umzug.json') },
storage: new JSONStorage({ path: join(__dirname, '/../tmp/umzug.json') }),
});

return umzug.execute({
Expand Down
6 changes: 3 additions & 3 deletions legacy-tests/Umzug/executed.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { expect } = require('chai');
const helper = require('../helper');
const { Umzug } = require('../../lib/src/index');
const { Umzug, JSONStorage } = require('../../lib/src');
const { join } = require('path');

const executedTestSuite = function executedTestSuite () {
Expand Down Expand Up @@ -97,7 +97,7 @@ describe('executed', () => {
this.migrationNames = migrationNames;
this.umzug = new Umzug({
migrations: { path: join(__dirname, '/../tmp/') },
storageOptions: { path: join(__dirname, '/../tmp/umzug.json') },
storage: new JSONStorage({ path: join(__dirname, '/../tmp/umzug.json') }),
});
});
});
Expand All @@ -114,7 +114,7 @@ describe('executed-directories', () => {
this.migrationNames = migrationNames;
this.umzug = new Umzug({
migrations: { path: join(__dirname, '/../tmp/'), traverseDirectories: true },
storageOptions: { path: join(__dirname, '/../tmp/umzug.json') },
storage: new JSONStorage({ path: join(__dirname, '/../tmp/umzug.json') }),
});
});
});
Expand Down
4 changes: 2 additions & 2 deletions legacy-tests/Umzug/migrationsList.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const { expect } = require('chai');
const { Umzug } = require('../../lib/src');
const { Umzug, JSONStorage } = require('../../lib/src');
const { join } = require('path');
const { migrationsList } = require('../../lib/src/migrationsList');
const helper = require('../helper');
Expand All @@ -25,7 +25,7 @@ describe('migrationsList', () => {
}], ['hello']);
const umzug = new Umzug({
migrations,
storageOptions: { path: join(__dirname, '/../tmp/umzug.json') },
storage: new JSONStorage({ path: join(__dirname, '/../tmp/umzug.json') }),
});

expect((await umzug.pending())[0].file).to.equal('00');
Expand Down
6 changes: 3 additions & 3 deletions legacy-tests/Umzug/pending.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const { expect } = require('chai');
const helper = require('../helper');
const { Migration } = require('../../lib/src/migration');
const { Umzug } = require('../../lib/src/index');
const { Umzug, JSONStorage } = require('../../lib/src');
const { join } = require('path');

const pendingTestSuite = function pendingTestSuite () {
Expand Down Expand Up @@ -89,7 +89,7 @@ describe('pending', () => {
this.migrationNames = migrationNames;
this.umzug = new Umzug({
migrations: { path: join(__dirname, '/../tmp/') },
storageOptions: { path: join(__dirname, '/../tmp/umzug.json') },
storage: new JSONStorage({ path: join(__dirname, '/../tmp/umzug.json') }),
});
});
});
Expand All @@ -106,7 +106,7 @@ describe('pending-directories', () => {
this.migrationNames = migrationNames;
this.umzug = new Umzug({
migrations: { path: join(__dirname, '/../tmp/'), traverseDirectories: true },
storageOptions: { path: join(__dirname, '/../tmp/umzug.json') },
storage: new JSONStorage({ path: join(__dirname, '/../tmp/umzug.json') }),
});
});
});
Expand Down
6 changes: 3 additions & 3 deletions legacy-tests/Umzug/up.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const { expect } = require('chai');
const helper = require('../helper');
const { Migration } = require('../../lib/src/migration');
const { Umzug } = require('../../lib/src');
const { Umzug, JSONStorage } = require('../../lib/src');
const { join } = require('path');

const upTestSuite = function upTestSuite () {
Expand Down Expand Up @@ -280,7 +280,7 @@ describe('up', () => {
this.migrationNames = migrationNames;
this.umzug = new Umzug({
migrations: { path: join(__dirname, '/../tmp/') },
storageOptions: { path: join(__dirname, '/../tmp/umzug.json') },
storage: new JSONStorage({ path: join(__dirname, '/../tmp/umzug.json') }),
});
});
});
Expand All @@ -297,7 +297,7 @@ describe('up-directories', () => {
this.migrationNames = migrationNames;
this.umzug = new Umzug({
migrations: { path: join(__dirname, '/../tmp/'), traverseDirectories: true },
storageOptions: { path: join(__dirname, '/../tmp/umzug.json') },
storage: new JSONStorage({ path: join(__dirname, '/../tmp/umzug.json') }),
});
});
});
Expand Down
12 changes: 5 additions & 7 deletions legacy-tests/fixtures/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const { resolve, join, parse } = require('path');
const { expect } = require('chai');
const Sequelize = require('sequelize');
const helper = require('../helper');
const { Umzug } = require('../../lib/src');
const { Umzug, SequelizeStorage } = require('../../lib/src');
const { v4: uuid } = require('uuid');
const { Migration } = require('../../lib/src/migration');

Expand Down Expand Up @@ -32,11 +32,10 @@ describe('custom resolver', () => {
customResolver: this.customResolver,
nameFormatter: (path) => parse(path).name,
},
storage: 'sequelize',
storageOptions: {
storage: new SequelizeStorage({
path: this.storagePath,
sequelize: this.sequelize,
},
}),
});
};

Expand Down Expand Up @@ -82,11 +81,10 @@ describe('custom resolver', () => {
},
}),
],
storage: 'sequelize',
storageOptions: {
storage: new SequelizeStorage({
path: this.storagePath,
sequelize: this.sequelize,
},
}),
});

await umzug.up();
Expand Down
Loading