1.6.12 • Published 4 months ago

ivo v1.6.12

Weekly downloads
-
License
MIT
Repository
github
Last release
4 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

6 months ago

1.6.3

7 months ago

1.6.2

7 months ago

1.6.1

7 months ago

1.6.9

6 months ago

1.6.11

4 months ago

1.6.8

6 months ago

1.6.10

6 months ago

1.6.7

6 months ago

1.6.6

6 months ago

1.6.12

4 months ago

1.6.5

6 months ago

1.6.0

8 months ago

1.5.2

8 months ago

1.4.5

1 year ago

1.4.4

1 year ago

1.4.3

1 year ago

1.5.1

12 months ago

1.4.2

1 year ago

1.5.0

12 months ago

1.4.1

1 year ago

1.4.0

1 year ago

1.3.5

1 year ago

1.3.4

1 year ago

1.3.3

1 year ago

1.3.2

1 year ago

1.3.1

1 year ago

1.3.0

1 year ago

1.2.3

1 year ago

1.2.2

1 year ago

1.2.0

1 year ago

1.2.1

1 year ago

1.1.0

1 year ago

1.0.2

1 year ago

1.0.1

1 year ago

0.0.1

2 years ago

1.0.0

6 years ago