Moleculer Database Context Integrator

2.0.3 · active · verified Wed Apr 22

moleculer-context-db is a utility library for Moleculer microservices that integrates database session management directly into the service context. It currently offers built-in support for Mikro-ORM, specifically focusing on providing transaction-safe database sessions for actions. While SQL databases have been thoroughly tested, MongoDB support is noted as experimental. The library streamlines the process of injecting a database EntityManager or session into each Moleculer action's context, ensuring that operations within an action can participate in a single, consistent transaction. The current stable version is 2.0.3. Release cadence is not explicitly stated but aligns with Mikro-ORM major versions due to peer dependencies. Its key differentiator is simplifying transaction management within a Moleculer microservice architecture, abstracting away manual session handling.

Common errors

Warnings

Install

Imports

Quickstart

Demonstrates how to set up moleculer-context-db with Mikro-ORM (SQLite) in a Moleculer broker, define an entity, and perform CRUD operations within a service using the context-injected EntityManager.

import { ServiceBroker } from 'moleculer';
import { MikroConnector, DatabaseContextManager } from 'moleculer-context-db';
import { BaseEntity, Entity, PrimaryKey, Property, MikroORM, Collection } from '@mikro-orm/core';
import { SqliteDriver } from '@mikro-orm/sqlite';

// 1. Define your Mikro-ORM entities (example)
@Entity()
class User extends BaseEntity<User, 'id'> {
  @PrimaryKey()
  id!: number;

  @Property({ unique: true })
  username!: string;

  @Property()
  email!: string;
}

// 2. Instantiate and initialize the MikroConnector
const connector = new MikroConnector<SqliteDriver>();

async function setup() {
  await connector.init({
    type: 'sqlite',
    dbName: ':memory:',
    entities: [User],
    cache: { enabled: false },
    // Ensure schema is synchronized for in-memory DB
    migrations: { runMigrations: true, path: './migrations' }, // Dummy path, not used for in-memory
    allowGlobalContext: true // Important for direct ORM access in tests/scripts
  });
  const orm = connector.getOrm();
  if (orm) {
    await orm.getSchemaGenerator().updateSchema();
  }

  // 3. Create a Moleculer Service Broker
  const broker = new ServiceBroker({
    logger: true,
    logLevel: 'info'
  });

  // 4. Instantiate DatabaseContextManager and add its middleware
  const dbContextManager = new DatabaseContextManager(connector);
  broker.middlewares.add(dbContextManager.middleware());

  // 5. Define a Moleculer service that uses the context-injected EntityManager
  broker.createService({
    name: 'users',
    actions: {
      async create(ctx) {
        // Access the EntityManager from the context
        const em = ctx.em;
        if (!em) {
          throw new Error('EntityManager not found in context');
        }
        const { username, email } = ctx.params;
        const user = em.create(User, { username, email });
        await em.persistAndFlush(user);
        return user;
      },
      async list(ctx) {
        const em = ctx.em;
        if (!em) {
            throw new Error('EntityManager not found in context');
        }
        return em.find(User, {});
      }
    }
  });

  await broker.start();

  // 6. Call a service action to test
  try {
    const user1 = await broker.call('users.create', { username: 'john.doe', email: 'john@example.com' });
    console.log('Created user:', user1);

    const user2 = await broker.call('users.create', { username: 'jane.doe', email: 'jane@example.com' });
    console.log('Created user:', user2);

    const users = await broker.call('users.list');
    console.log('All users:', users);
  } catch (error) {
    console.error('Error during service call:', error);
  } finally {
    await broker.stop();
    const orm = connector.getOrm();
    if (orm) {
      await orm.close();
    }
  }
}

setup();

view raw JSON →