/ivo

A user story-focused event-driven schema validator for JS/TS backends

Primary LanguageTypeScriptMIT LicenseMIT

Foreword

ivo is a user story focused utility that helps you build factory methods to manage entities and their values in your domain.

In short, it is an event-driven schema validator which provides an interface for you to clearly define the behaviour of your entities at creation and during updates.

Installation

$ npm i ivo

Importing

// Using Nodejs `require`
const { Schema } = require('ivo');

// Using ES6 imports
import { Schema } from 'ivo';

Defining a schema

import { Schema, type Summary } from 'ivo';

type UserRole = 'admin' | 'user';

type Input = {
  firstName: string;
  lastName: string;
  password: string;
  role?: UserRole;
};

type Output = {
  createdAt: Date;
  firstName: string;
  fullName: string;
  id: number;
  lastName: string;
  password: string;
  role: UserRole;
  updatedAt: Date;
};

type ISummary = Summary<Input, Output>;

const userSchema = new Schema<Input, Output>(
  {
    firstName: {
      required: true,
      validator: validateString('invalid first name')
    },
    fullName: {
      default: '',
      dependent: true,
      dependsOn: ['firstName', 'lastName'],
      resolver: getFullName
    },
    id: { constant: true, value: generateUserId },
    lastName: {
      required: true,
      validator: validateString('invalid last name')
    },
    password: { required: true, validator: validatePassword },
    role: { default: 'user', shouldInit: false, validator: validateRole }
  },
  { timestamps: true }
);

// resolvers
function getFullName({ context: { firstName, lastName } }: ISummary) {
  return `${firstName} ${lastName}`;
}

// get the model
const UserModel = userSchema.getModel();

Creating an entity

import userDb from 'db-of-choice'; // use any db that supports the information you are modelling

const { data, error } = await UserModel.create({
  firstName: 'John',
  fullName: 'Mr. James',
  id: 1,
  lastName: 'Doe',
  lastSeen: new Date(),
  name: 'John Doe',
  password: 'au_34ibUv^T-adjInFjj',
  role: 'admin'
});

if (error) return handleError(error);

console.log(data);
//  {
//   createdAt: new Date(),
//   firstName: "John",
//   fullName: "John Doe",
//   id: 18927934748659724,
//   lastName: "Doe",
//   password: "**************",
//   role: "user",
//   updatedAt: new Date(),
// };

await userDb.insert(data);

Updating an entity

const user = await userDb.findById(18927934748659724);

if (!user) return handleError({ message: 'User not found' });

const { data, error } = await UserModel.update(user, {
  firstName: 'Peter',
  id: 2,
  age: 34,
  fullName: 'Tony Stark'
});

if (error) return handleError(error);

// age is ignored because it is not a valid property
// fullName is ignored because it is dependent
// id is ignored because it is a constant
console.log(data); // { firstName: "Peter", fullName: "Peter Doe", updatedAt: new Date() }

await userDb.updateById(user.id, data);

Docs