@commodo/hooks

Hooks are points in code on which you can "hook" on to and execute one or more callbacks.

Usage no npm install needed!

<script type="module">
  import commodoHooks from 'https://cdn.skypack.dev/@commodo/hooks';
</script>

README

Prettier license SemVer lerna Commitizen friendly Gitter

Commodo is a library of higher order functions (HOFs) that let you create and compose rich data models.

📹 Videos

Wanna get up to speed quickly? Check out the Commodo videos here!

Quick example

A simple model

The following example shows how to create a simple data model, which you can later use to validate data (e.g. data received as body of an HTTP request):

import { withFields, string, number, boolean } from "@commodo/fields";

const Animal = withFields({
    name: string({
        validation: value => {
            if (!value) {
                throw Error("A pet must have a name!");
            }
        }
    }),
    age: number(),
    isAwesome: boolean(),
    about: fields({
        value: {},
        instanceOf: withFields({
            type: string({ value: "cat" }),
            dangerous: boolean({ value: true })
        })()
    })
})();

const animal = new Animal();
animal.populate({ age: "7" }); // Throws data type error, cannot populate a string with number.

animal.populate({ age: 7 });
await animal.validate(); // Throws a validation error - name must be defined.

animal.name = "Garfield";
await animal.validate(); // All good.
More complex model

Using other HOFs, you can create more complex models, that have a name, attached hooks, and even storage layer, so that you can easily save the data to the database:

import { withFields, string, number, boolean, fields, onSet } from "@commodo/fields";
import { withName } from "@commodo/name";
import { withHooks } from "@commodo/hooks";
import { withStorage } from "@commodo/fields-storage";
import { MongoDbDriver, withId } from "@commodo/fields-storage-mongodb";
import { compose } from "ramda";

// Define User and Verification models.
const Verification = compose(
  withFields({
    verified: boolean(),
    verifiedOn: string()
  })
)();

const User = compose(
  withFields({
    firstName: string(),
    lastName: string(),
    email: compose(
      onSet(value => value.toLowerCase())
    )(string()),
    age: number(),
    scores: number({ list: true }),
    enabled: boolean({ value: false }),
    verification: fields({ instanceOf: Verification })
  }),
  withHooks({
    async beforeCreate() {
      if (await User.count({ query: { email: this.email } })) {
        throw Error("User with same e-mail already exists.");
      }
    }
  }),
  withName("User"), // Utilized by storage layer, to determine collection / table name.
  withId(),
  withStorage({
    driver: new MongoDbDriver({ database })
  })
)();

const user = new User();
user.populate({
  firstName: "Adrian",
  lastName: "Smith",
  email: "aDrIan@google.com",
  enabled: true,
  scores: [34, 66, 99],
  verification: {
    verified: true,
    verifiedOn: "2019-01-01"
  }
});

await user.save();

Is Commodo an ORM/ODM?

Fundamentally, Commodo is not an ORM/ODM, but can very quickly become one, by utilizing an additional HOF. You can use the already provided @commodo/fields-storage or even create your own if you don't like the existing one.

Using HOFs is a very flexible approach for defining your data models, because you can append only the functionality you actually need and will use.

Core packages:

The following section shows all of the useful higher order functions that you can use right now.

Package Short Description Version
@commodo/fields The starting point of every model. Provides base string, number, boolean and model fields.
@commodo/name Assign a name to your models.
@commodo/hooks Provides methods for defining and triggering hooks on your models.
@commodo/fields-storage Enables saving models to a database (with an appropriate driver, e.g. MySQL).

Additional packages:

Package Short Description Version
@commodo/fields-storage-ref Provides ref field, for saving references to other models saved in database.
@commodo/fields-storage-mongodb A MongoDB driver for @commodo/fields-storage package.
@commodo/fields-storage-soft-delete Introduces deleted boolean field to mark whether a model was deleted or not, instead of physically deleting the entry in the storage.

Community packages:

Package Short Description Version
commodo-fields-date Provides date field, for saving dates.
commodo-fields-object Provides object field, for saving plain objects.
commodo-fields-int Provides int field, for saving integer numbers.
commodo-fields-float Provides float field, for saving float numbers.
commodo-fields-storage-crud-logs Adds and automatically manages createdOn, updatedOn, savedOn fields.

Contributing

Please see our Contributing Guideline which explains repo organization, linting, testing, and other steps.

License

This project is licensed under the terms of the MIT license.