Skip to content

Commit

Permalink
Merge pull request #15 from pkosiec/add-drop-collection-option
Browse files Browse the repository at this point in the history
Allow dropping everycollection that is being imported
  • Loading branch information
pkosiec committed Jul 14, 2018
2 parents eb8c1c0 + a41878d commit fca04be
Show file tree
Hide file tree
Showing 12 changed files with 79 additions and 9 deletions.
3 changes: 2 additions & 1 deletion cli/README.md
Expand Up @@ -45,7 +45,8 @@ You can use the following parameters while using `seed` binary:
| `--db-name $DB_NAME` | `database` | Name of the database |
| `--db-username $DB_USERNAME` | database | Username for connecting with database that requires authentication |
| `--db-password $DB_PASSWORD` | database | Password for connecting with database that requires authentication |
| `--drop-database` | `false` | Dropping database before data import |
| `--drop-database` | `false` | Dropping entire database before data import |
| `--drop-collection` | `false` | Dropping every collection that is being imported |
| `--replace-id` | `false` | Replacing `id` property with `_id` for every document during data import |
| `--reconnect-timeout` | `10` (seconds) | Maximum time of waiting for successful MongoDB connection|
| `--help` or `-h` | n/a | Help
7 changes: 7 additions & 0 deletions cli/src/options.ts
Expand Up @@ -67,6 +67,11 @@ export const optionsDefinition: CommandLineOptionDefinition[] = [
description: 'Drops database before import',
type: Boolean,
},
{
name: 'drop-collection',
description: 'Drops collection before importing it',
type: Boolean,
},
{
name: 'replace-id',
description: 'Replaces `id` property with `_id` for every object to import',
Expand All @@ -84,6 +89,7 @@ export interface CommandLineOptions {
data?: string;
[key: string]: string | number | boolean | undefined;
'drop-database': boolean;
'drop-collection': boolean;
'replace-id': boolean;
'db-protocol'?: string;
'db-host'?: string;
Expand Down Expand Up @@ -128,6 +134,7 @@ export const convertOptions = (
databaseConnectionUri: options['db-uri'],
inputPath: options.data ? resolve(options.data) : resolve('./'),
dropDatabase: options['drop-database'],
dropCollection: options['drop-collection'],
replaceIdWithUnderscoreId: options['replace-id'],
reconnectTimeoutInSeconds: options['reconnect-timeout'],
});
1 change: 1 addition & 0 deletions core/README.md
Expand Up @@ -81,6 +81,7 @@ const config = {
password: undefined,
},
databaseConnectionUri: undefined, // if defined, it will be used for DB connection instead of `database` object
dropCollection: false, // drops every collection that is being imported
inputPath: resolve(__dirname, '../../data'), // input directory with import data structure
dropDatabase: false, // drops database before import
replaceIdWithUnderscoreId: false, // rewrites `id` property to `_id` for every document; useful for ORMs
Expand Down
3 changes: 2 additions & 1 deletion core/src/common/config.ts
Expand Up @@ -13,7 +13,8 @@ export const defaultConfig: AppConfig = {
},
databaseConnectionUri: undefined,
inputPath: resolve(__dirname, '../../data'), // input directory with import data structure
dropDatabase: false, // drops database before import
dropDatabase: false, // drops entire database before import
dropCollection: false, // drops collection before importing it
replaceIdWithUnderscoreId: false, // rewrites `id` property to `_id` for every document
supportedExtensions: ['json', 'js'], // files that should be imported
reconnectTimeoutInSeconds: 10, // maximum time of waiting for successful MongoDB connection
Expand Down
1 change: 1 addition & 0 deletions core/src/common/types.ts
Expand Up @@ -16,6 +16,7 @@ export interface AppConfig {
databaseConnectionUri?: string;
inputPath: string;
dropDatabase: boolean;
dropCollection: boolean;
replaceIdWithUnderscoreId: boolean;
supportedExtensions: string[];
reconnectTimeoutInSeconds: number;
Expand Down
17 changes: 15 additions & 2 deletions core/src/database/Database.ts
Expand Up @@ -8,10 +8,23 @@ export class Database {
collectionName: string,
) {
const documentsCopy = documentsToInsert.map(document => ({ ...document }));
await this.db.collection(collectionName).insertMany(documentsCopy);
return this.db.collection(collectionName).insertMany(documentsCopy);
}

async drop() {
await this.db.dropDatabase();
return this.db.dropDatabase();
}

async ifCollectionExist(collectionName:string):Promise<boolean> {
const collections = await this.db.collections();
return collections.map(collection => collection.collectionName).includes(collectionName);
}

async dropCollectionIfExists(collectionName:string) {
if (!await this.ifCollectionExist(collectionName)) {
return;
}

return this.db.collection(collectionName).drop()
}
}
10 changes: 8 additions & 2 deletions core/src/index.ts
@@ -1,4 +1,3 @@
import { MongoClient } from 'mongodb';
import { log, getConfig, DeepPartial, AppConfig } from './common';
import { DatabaseConnector } from './database';
import {
Expand Down Expand Up @@ -34,12 +33,19 @@ export const seedDatabase = async (partialConfig: DeepPartial<AppConfig>) => {
databaseConnectionUri: config.databaseConnectionUri,
databaseConfig: config.database,
});

if (!config.dropDatabase && config.dropCollection) {
log('Dropping collections...');
for (const collection of collections) {
await database.dropCollectionIfExists(collection.name);
}
}

if (config.dropDatabase) {
log('Dropping database...');
await database.drop();
}

await new DataImporter(database).import(collections);
} catch (err) {
throw wrapError(err);
Expand Down
13 changes: 13 additions & 0 deletions core/tests/integration/Database.ts
Expand Up @@ -73,4 +73,17 @@ describe('Database', () => {
await database.drop();
await expect(listExistingCollections(database.db)).resolves.toEqual([]);
});

it('should drop collection', async () => {
await createCollection(database.db, 'first');
await createCollection(database.db, 'second');

const collections = await listExistingCollections(database.db);
await expect(collections).toHaveLength(2);
await expect(collections).toContainEqual('first');
await expect(collections).toContainEqual('second');

await database.dropCollectionIfExists('first');
await expect(listExistingCollections(database.db)).resolves.toEqual(["second"]);
});
});
24 changes: 24 additions & 0 deletions core/tests/integration/seedDatabase.ts
Expand Up @@ -144,6 +144,30 @@ describe('Mongo Seeding', () => {
expect(collections).toContainEqual('CollectionTwo');
});

it('should drop collections before importing data', async () => {
const expectedCollectionNames = ['CollectionOne', 'CollectionTwo'];
createSampleFiles(expectedCollectionNames, TEMP_DIRECTORY_PATH);

await createCollection(database.db, 'CollectionOne');
await createCollection(database.db, 'ShouldNotBeRemoved');

const config: DeepPartial<AppConfig> = {
inputPath: TEMP_DIRECTORY_PATH,
database: {
name: DATABASE_NAME,
},
dropCollection: true,
};

await expect(seedDatabase(config)).resolves.toBeUndefined();

const collections = await listExistingCollections(database.db);
expect(collections).toHaveLength(3);
expect(collections).toContainEqual('CollectionOne');
expect(collections).toContainEqual('CollectionTwo');
expect(collections).toContainEqual('ShouldNotBeRemoved');
});

it('should throw error when wrong path given', async () => {
const config: DeepPartial<AppConfig> = {
inputPath: '/this/path/surely/doesnt/exist',
Expand Down
1 change: 1 addition & 0 deletions core/tests/unit/config.ts
Expand Up @@ -30,6 +30,7 @@ describe('Config', () => {
},
inputPath: '/',
dropDatabase: false,
dropCollection: false,
replaceIdWithUnderscoreId: true,
supportedExtensions: ['md', 'txt'],
reconnectTimeoutInSeconds: 20,
Expand Down
5 changes: 3 additions & 2 deletions docker-image/README.md
Expand Up @@ -2,7 +2,7 @@

# Mongo Seeding Docker Image

[![Build Status](https://travis-ci.org/pkosiec/mongo-seeding-docker.svg?branch=master)](https://travis-ci.org/pkosiec/mongo-seeding-docker) [![David](https://img.shields.io/david/pkosiec/mongo-seeding.svg?path=docker-image)]() [![David](https://img.shields.io/david/dev/pkosiec/mongo-seeding.svg?path=docker-image)]()
[![Build Status](https://travis-ci.org/pkosiec/mongo-seeding.svg?branch=master)](https://travis-ci.org/pkosiec/mongo-seeding) [![David](https://img.shields.io/david/pkosiec/mongo-seeding.svg?path=docker-image)]() [![David](https://img.shields.io/david/dev/pkosiec/mongo-seeding.svg?path=docker-image)]()

The ultimate solution for populating your MongoDB database. Define the data in JSON, JavaScript or TypeScript. Import collections and documents!

Expand Down Expand Up @@ -55,7 +55,8 @@ Specify environmental variables with `-e {key}={value}` parameter.
| DB_NAME | `database` | Name of the database |
| DB_USERNAME | *`undefined`* | Username for connecting with database that requires authentication |
| DB_PASSWORD | *`undefined`* | Password for connecting with database that requires authentication |
| DROP_DATABASE | `false` | Dropping database before data import |
| DROP_DATABASE | `false` | Dropping entire database before data import |
| DROP_COLLECTION | `false` | Dropping every collection that is being imported |
| REPLACE_ID_TO_UNDERSCORE_ID | `false` | Replacing `id` property with `_id` for every document during import; useful for ORMs |
| RECONNECT_TIMEOUT_IN_SECONDS | `10` | Maximum time, in which app should keep trying connecting to database |

Expand Down
3 changes: 2 additions & 1 deletion docker-image/src/index.ts
@@ -1,6 +1,6 @@
import { seedDatabase } from 'mongo-seeding';
import { resolve } from 'path';
import { DeepPartial, AppConfig } from 'mongo-seeding/common';
import { DeepPartial, AppConfig } from 'mongo-seeding/dist/common';

const env = process.env;
const envOptions: DeepPartial<AppConfig> = {
Expand All @@ -16,6 +16,7 @@ const envOptions: DeepPartial<AppConfig> = {
? String(env.DB_CONNECTION_URI)
: undefined,
dropDatabase: env.DROP_DATABASE === 'true',
dropCollection: env.DROP_COLLECTION === 'true',
replaceIdWithUnderscoreId: env.REPLACE_ID_TO_UNDERSCORE_ID === 'true',
supportedExtensions: ['ts', 'js', 'json'],
inputPath: resolve(__dirname, '../data'),
Expand Down

0 comments on commit fca04be

Please sign in to comment.