1.6.12 • Published 10 months ago

ivo v1.6.12

Weekly downloads
-
License
MIT
Repository
github
Last release
10 months ago

Foreword

ivo is a user story focused 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

// CJS
const { Schema } = require("ivo");

// ESM
import { Schema } from "ivo";

Defining a schema

import { Schema, type MutableSummary } from "ivo";

type UserInput = {
  email: string;
  username: string;
  phoneNumber: string;
};

type User = {
  id: string;
  createdAt: Date;
  email: string | null;
  username: string;
  phoneNumber: string | null;
  updatedAt: Date;
  usernameLastUpdatedAt: Date | null;
};

const userSchema = new Schema<UserInput, User>(
  {
    id: { constant: true, value: generateUserID },
    email: {
      default: null,
      required: isEmailOrPhoneRequired,
      validator: [validateEmail, makeSureEmailIsUnique],
    },
    phoneNumber: {
      default: null,
      required: isEmailOrPhoneRequired,
      validator: validatePhoneNumber,
    },
    username: {
      required: true,
      validator: [validateUsername, makeSureUsernameIsUnique],
      shouldUpdate({ usernameLastUpdatedAt }) {
        if (!usernameLastUpdatedAt) return true;

        const timeDifferenceInMillisecs =
          new Date().getTime() - usernameUpdatableFrom.getTime();
        const thirtyDaysInMillisecs = 2_592_000_000;

        return timeDifferenceInMillisecs >= thirtyDaysInMillisecs;
      },
    },
    usernameLastUpdatedAt: {
      default: null,
      dependsOn: "username",
      resolver: ({ isUpdate }) => (isUpdate ? new Date() : null),
    },
  },
  { timestamps: true },
);

function isEmailOrPhoneRequired({
  context: { email, phoneNumber },
}: MutableSummary<UserInput, User>) {
  return [!email && !phoneNumber, 'Provide "email" or "phone" number'] as const;
}

async function makeSureEmailIsUnique(email: string) {
  const userWithEmail = await usersDb.findByEmail(email);

  return userWithEmail ? { valid: false, reason: "Email already taken" } : true;
}

async function makeSureUsernameIsUnique(username: string) {
  const userWithUsername = await usersDb.findByUsername(username);

  return userWithUsername
    ? { valid: false, reason: "Username already taken" }
    : true;
}

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

Creating an entity

const { data, error } = await UserModel.create({
  email: "john.doe@mail.com",
  id: 5, // will be ignored because it is a constant property
  name: "John Doe", // will be ignored because it is not on schema
  username: "john_doe",
  usernameLastUpdatedAt: new Date(), // will be ignored because it is a dependent property
});

if (error) return handleError(error);

console.log(data);
// {
//   createdAt: new Date(),
//   email: 'john.doe@mail.com',
//   id: 101,
//   phoneNumber: null,
//   updatedAt: new Date(),
//   username: 'john_doe',
//   usernameLastUpdatedAt: null
// }

// data is safe to dump in db
await usersDb.insertOne(data);

Updating an entity

const user = await usersDb.findByID(101);

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

const { data, error } = await UserModel.update(user, {
  usernameLastUpdatedAt: new Date(), // dependent property -> will be ignored
  id: 75, // constant property -> will be ignored
  age: 34, // not on schema -> will be ignored
  username: "johndoe",
});

if (error) return handleError(error);

console.log(data);
// {
//   updatedAt: new Date(),
//   username: 'johndoe',
//   usernameLastUpdatedAt: Date // value returned from resolver -> 30days from now
// }

await usersDb.updateByID(user.id, data);
// updating 'username' again will not work

const { error } = await UserModel.update(user, {
  username: "john-doe", // will be ignored because shouldUpdate rule will return false
});

console.log(error);
// {
//   message: 'NOTHING_TO_UPDATE',
//   payload: {}
// }

Docs

1.6.4

12 months ago

1.6.3

1 year ago

1.6.2

1 year ago

1.6.1

1 year ago

1.6.9

12 months ago

1.6.11

10 months ago

1.6.8

12 months ago

1.6.10

12 months ago

1.6.7

12 months ago

1.6.6

12 months ago

1.6.12

10 months ago

1.6.5

12 months ago

1.6.0

1 year ago

1.5.2

1 year ago

1.4.5

1 year ago

1.4.4

2 years ago

1.4.3

2 years ago

1.5.1

1 year ago

1.4.2

2 years ago

1.5.0

1 year ago

1.4.1

2 years ago

1.4.0

2 years ago

1.3.5

2 years ago

1.3.4

2 years ago

1.3.3

2 years ago

1.3.2

2 years ago

1.3.1

2 years ago

1.3.0

2 years ago

1.2.3

2 years ago

1.2.2

2 years ago

1.2.0

2 years ago

1.2.1

2 years ago

1.1.0

2 years ago

1.0.2

2 years ago

1.0.1

2 years ago

0.0.1

2 years ago

1.0.0

7 years ago