Skip to content

Instantly share code, notes, and snippets.

@icebob
Last active March 18, 2023 09:27
Show Gist options
  • Save icebob/a093d0011ff0fa0f29d02dc4324557be to your computer and use it in GitHub Desktop.
Save icebob/a093d0011ff0fa0f29d02dc4324557be to your computer and use it in GitHub Desktop.
DB service mixin for Moleculer DB

DB handler mixin for Moleculer DB

It supports using MongoDB at development & production and using NeDB at unit testing.

Features

  • use NeDB memory DB for unit testing (NODE_ENV=test).
  • use NeDB file storage if NEDB_FOLDER is defined.
  • use other empty MongoDB database for E2E testing (NODE_ENV=test TEST_E2E=true).
  • create collection indexes.
  • generate entity changed broker messages. E.g. posts.entity.created, posts.entity.updated, posts.entity.removed
  • seeding empty collections if seedDB method is defined.

Usage

const DbService = require("../mixins/db.mixin");

module.exports = {
    name: "accounts",

    mixins: [
        DbService("accounts")
    ],

    settings: {
        fields: [
            // ...
        ],

        // Indexes on collection
        indexes: [
            { username: 1 }
            { email: 1 }
        ]
    },

    methods: {

        /**
         * Seed an empty collection
         */
        async seedDB() {
            const res = await this.adapter.insertMany([
                // Administrator
                {
                    username: "admin",
                    password: await this.hashPassword("admin"),
                    firstName: "Administrator",
                    lastName: "",
                    status: 1,
                    createdAt: Date.now(),
                },
            ]);

            this.logger.info(`Generated ${res.length} users.`);
        },
    }	

};
"use strict";
const _ = require("lodash");
const path = require("path");
const mkdir = require("mkdirp").sync;
const DbService = require("moleculer-db");
const MongoAdapter = require("moleculer-db-adapter-mongo");
const TESTING = process.env.NODE_ENV === "test";
const ISMONGO = !process.env.NEDB_FOLDER;
module.exports = function(collection, opts = {}) {
let adapter;
if (TESTING) {
adapter = new DbService.MemoryAdapter();
} else {
if (process.env.NEDB_FOLDER) {
const dir = path.resolve(process.env.NEDB_FOLDER);
mkdir(dir);
adapter = new DbService.MemoryAdapter({ filename: path.join(dir, `${collection}.db`)});
} else {
adapter = new MongoAdapter(process.env.MONGO_URI || "mongodb://localhost/mydb", { useNewUrlParser: true });
// Mongo has an internal reconnect logic
opts.autoReconnect = false;
}
}
const schema = {
mixins: [DbService(adapter, opts)],
collection,
methods: {
entityChanged(type, json, ctx) {
return this.clearCache().then(() => {
const eventName = `${this.name}.entity.${type}`;
this.broker.broadcast(eventName, { meta: ctx.meta, entity: json });
});
},
},
async afterConnected() {
this.logger.info("Connected to database.");
if (!TESTING) {
// Create indexes
if (this.settings.indexes) {
try {
if (_.isFunction(this.adapter.collection.createIndex))
await this.Promise.all(this.settings.indexes.map(idx => this.adapter.collection.createIndex(idx)));
} catch(err) {
this.logger.error("Unable to create indexes.", err);
}
}
}
if (process.env.TEST_E2E) {
// Clean collection
this.logger.info(`Clear '${collection}' collection before tests...`);
await this.adapter.clear();
}
// Seeding if the DB is empty
const count = await this.adapter.count();
if (count == 0 && _.isFunction(this.seedDB)) {
this.logger.info(`Seed '${collection}' collection...`);
await this.seedDB();
}
}
};
return schema;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment