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

@datadom/core

v0.1.7

Published

A simple library for representing business/data domains and models

Downloads

519

Readme

@datadom/core

This package contains the core elements of Datadom. These include domains, models, and rules.

For more info you can visit the project wiki.

Installation

npm i @datadom/core

Domain

This represents the problem space your project occupies and provides a solution to.

import { Domain } from '@datadom/core';

const domain = new Domain();

Read more ➡️

Models

Domain models map to your business entities.

Datadom does not provide specific facilities for representing domain models. There is no interface to implement or class to inherit.

Read more ➡️

Repositories

A repository is an object that represents a collection of models. Typically, a repository would be responsible for CRUD (Create Read Update Delete) operations on models.

import { ID, IRepository, Persisted } from '@datadom/core';

interface ICharacter {
  id?: ID;
  name: string;
  createdAt?: Date;
  updatedAt?: Date;
}

interface ICharacterRepository extends IRepository<ICharacter> {}

export class CharacterRepository implements ICharacterRepository {
    count(params?: IQueryBuilder<ICharacter>): Promise<number> {
        throw new Error('Method not implemented.');
    }
    delete(id: ID): Promise<OperationResult> {
        throw new Error('Method not implemented.');
    }
    deleteMany(params: IQueryBuilder<ICharacter>): Promise<OperationResult> {
        throw new Error('Method not implemented.');
    }
    exists(params: IQueryBuilder<ICharacter>): Promise<boolean> {
        throw new Error('Method not implemented.');
    }
    get(id: ID): Promise<Persisted<ICharacter> | null> {
        throw new Error('Method not implemented.');
    }
    getMany(params?: IQueryBuilder<ICharacter>): Promise<Persisted<ICharacter>[]> {
        throw new Error('Method not implemented.');
    }
    save(data: SaveInput<ICharacter>): Promise<Persisted<ICharacter>> {
        throw new Error('Method not implemented.');
    }
    update(id: ID, data: UpdateInput<ICharacter>): Promise<OperationResult> {
        throw new Error('Method not implemented.');
    }
    updateMany(params: IQueryBuilder<ICharacter>, data: UpdateInput<ICharacter>): Promise<OperationResult> {
        throw new Error('Method not implemented.');
    }
}

Read more ➡️

Services

A service is a wrapper around a repository.

Whenever you register a repository in the domain by calling domain.registerRepository, a service of the same name is created under the hood. This service exposes the same methods exposed by the repository. However, a service ensures that the relevant rules, events, and middleware are run before and after certain repository actions.

import { Domain } from '@datadom/core';
import { CharacterRepository } from './characters';

const domain = new Domain();

domain.registerRepository('character', new CharacterRepository());

It is, however, possible to create a service without a concrete repository by calling domain.createService. This way, you can attach all the domain rules, hooks, and event listeners to the service without worrying about the actual repository that will be associated with the service.

import { Domain } from '@datadom/core';

const domain = new Domain();

domain.createService('character');

Services created this way are associated with a default repository of type NullRepository.

To associated a repository to a service created this way, simply call domain.registerRepository. The NullRepository repository will be replaced with the provided repository, and all the service's previously-added rules, hooks, and event listeners will continue to function as expected. This is great for ensuring domain code remains decoupled from infrastructure code.

domain.registerRepository('character', new CharacterRepository());

After registering a repository with a domain, you can access the wrapping service in a number of ways, depending on how strict your type-checking is.

// access the character service using any of the following notations:

domain.$('character');
(domain as any).$character;
(domain as any)['$character'];
domain.$character; // without strict type-checking
domain['$character']; // without strict type-checking

You can attach various hooks, rules, and event listeners to a service to perform actions before and after various repository operations. This helps the repository methods to concerned with only their tasks and not have to worry about preconditions, checks, and side effects.

domain.$('character').addRule('save', (data) => {
  console.log('This rule runs before an entity is saved by the repository');

  // ensure that the entity to be saved has a "name" field
  return !!(data?.name);
});
domain.$('character').pre('save', (data, next) => {
  console.log('This hook/middleware runs before an entity is saved by the repository');

  // call "next" to continue to the next middleware in the chain
  // you can call "next" like this "next(data)" or simply like this "next()"
  return next();
});
domain.$('character').pre('save', (data, next) => {
  console.log('This hook/middleware runs before an entity is saved by the repository');

  // call "next" to continue to the next middleware in the chain
  // you can call "next" like this "next(data)" or simply like this "next()"
  return next(data);
});
domain.$('character').pre('save', (data, next) => {
  console.log('This hook/middleware alters the entity that is to be saved by the repository');

  return next({ ...data, field1: 'This field was added in a middleware' });
});
domain.$('character').on('save', () => console.log('This event handler runs after an entity is saved by the repository'));

Read more ➡️

Rules

Rules are functions that resolve to boolean values and are executed before repository operations. A resolved value of false means the rule is violated, and the repository operation should not continue.

Rules can be attached to a specific service or to the domain object, in which case they are available to every service in the domain.

import { Domain } from '@datadom/core';

const domain = new Domain();

async function entityMustHaveId(data) {
  return !!(data?.id);
}

domain.addRule('save', entityMustHaveId);

The rule entityMustHaveId will be executed whenever a repository wants to save an entity.

Read more ➡️