npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

functional-cqrs

v1.3.0

Published

This library provides functional approach to CQRS (Command Query Responsibility Segregation).

Downloads

1

Readme

Functional Cqrs

This library provides functional approach to CQRS (Command Query Responsibility Segregation).

It includes all basic components - Commands Bus, Queries Bus and Events Bus with advanced typescript support.

CI Coverage Status

✨ Getting Started

Prerequsites

You will need:

  • nodejs (>=12.13.1, not tested on older versions, but might work). It should also work in browsers (not tested).

Installation

npm install functional-cqrs or yarn add functional-cqrs

🚀 Usage

Let's say that we have a simple to-do app:

import {
  Command,
  CommandContext,
  createCqrs,
  Event,
  EventContext,
} from 'functional-cqrs';
import { connectToDatabse } from 'your-database-library';

interface Task {
  id: string;
  title: string;
  done: boolean;
}

// Command name - required for type inference
const AddTask = 'AddTask' as const;

// Your command for adding new Task
class AddTaskCommand implements Command<Task> {
  readonly name = AddTask;

  constructor(readonly payload: Task) {}
}

// Event emitted after Task have been created
class TaskAddedEvent implements Event<Task> {
  constructor(readonly payload: Task) {}
}

// Your handler for adding new Task
const addTaskHandler = (connection: Connection) => async (
  command: AddTaskCommand,
  // CommandContext includes EventsBus for dispatching events
  ctx: CommandContext
) => {
  await connection.saveTask(command.payload);

  await ctx.eventsBus.dispatch(new TaskAddedEvent(command.payload));

  // Note that we return created task here
  return command.payload;
};

const onTaskAdded = (
  event: TaskAddedEvent,
  // EventContext includes CommandsBus so we can execute commands from here
  context: EventContext
) => {
  // Log created Task into console
  console.log(event.payload);
};

// Let's bootstrap our app

const connection = connectToDatabse();
const cqrs = createCqrs({
  commandHandlers: {
    // Here we create and register our command handler
    [AddTask]: addTaskHandler(connection),
  },
  eventHandlers: {
    // Events can have multiple handlers
    [TaskAddedEvent.name]: [onTaskAdded],
  },
});

const task = await cqrs.buses.commandsBus.execute(
  new AddTaskCommand({
    id: '1',
    done: false,
    title: 'Test task',
  })
);

// Typescript knows that this is a "Task"!
console.log(task.id);

You can very quickly integrate above example with any kind of application.

Now, you might ask:

Why do we need to set command name as "'AddTask' as const;" and then use it to register the command handler, but we don't do the same for events?

In order to get the type inference from Typescript, we need a way to map command to handler - and we use it's name for it. We have to define it "as const" so Typescript knows it's exact value.

We don't do that for events, because they always return void | Promise<void> :)

📖 Learn more

Need more? Check examples 😎.