diff --git a/benchmarks/array.ts b/benchmarks/array.ts index f58ea73..98728f0 100644 --- a/benchmarks/array.ts +++ b/benchmarks/array.ts @@ -3,6 +3,8 @@ import Benchmark from 'benchmark' import { z } from 'zod' import yup from 'yup' import vine from '../index.js' +import Joi from 'joi' +import Ajv, { AsyncSchema } from 'ajv' function getData() { return { @@ -54,6 +56,42 @@ const vineSchema = vine.compile( }) ) +const joiSchema = Joi.object({ + contacts: Joi.array() + .items( + Joi.object({ + type: Joi.string().required(), + value: Joi.string().required(), + }) + ) + .required(), +}).required() + +const ajv = new Ajv.default() +interface AjvData { + contacts: [{ type: string; value: string }] +} +const ajvSchema: AsyncSchema = { + $async: true, + type: 'object', + properties: { + contacts: { + type: 'array', + items: { + type: 'object', + properties: { + type: { type: 'string', nullable: false }, + value: { type: 'string', nullable: false }, + }, + required: ['type', 'value'], + }, + }, + }, + required: ['contacts'], + additionalProperties: false, +} +const ajvValidator = ajv.compile(ajvSchema) + console.log('======================') console.log('Benchmarking arrays') console.log('======================') @@ -87,6 +125,23 @@ suite .catch(console.log) }, }) + .add('Joi', { + defer: true, + fn: function (deferred: any) { + joiSchema + .validateAsync(getData()) + .then(() => deferred.resolve()) + .catch(console.log) + }, + }) + .add('Ajv', { + defer: true, + fn: function (deferred: any) { + ajvValidator(getData()) + .then(() => deferred.resolve()) + .catch(console.log) + }, + }) .on('cycle', function (event: any) { console.log(String(event.target)) }) diff --git a/benchmarks/flat_object.ts b/benchmarks/flat_object.ts index e776566..be648f0 100644 --- a/benchmarks/flat_object.ts +++ b/benchmarks/flat_object.ts @@ -3,6 +3,8 @@ import Benchmark from 'benchmark' import { z } from 'zod' import yup from 'yup' import vine from '../index.js' +import Joi from 'joi' +import Ajv, { AsyncSchema } from 'ajv' function getData() { return { @@ -30,6 +32,28 @@ const vineSchema = vine.compile( }) ) +const joiSchema = Joi.object({ + username: Joi.string().required(), + password: Joi.string().required(), +}).required() + +const ajv = new Ajv.default() +interface AjvData { + username: string + password: string +} +const ajvSchema: AsyncSchema = { + $async: true, + type: 'object', + properties: { + username: { type: 'string', nullable: false }, + password: { type: 'string', nullable: false }, + }, + required: ['username', 'password'], + additionalProperties: false, +} +const ajvValidator = ajv.compile(ajvSchema) + console.log('===============================') console.log('Benchmarking with flat object') console.log('===============================') @@ -63,6 +87,23 @@ suite .catch(console.log) }, }) + .add('Joi', { + defer: true, + fn: function (deferred: any) { + joiSchema + .validateAsync(getData()) + .then(() => deferred.resolve()) + .catch(console.log) + }, + }) + .add('Ajv', { + defer: true, + fn: function (deferred: any) { + ajvValidator(getData()) + .then(() => deferred.resolve()) + .catch(console.log) + }, + }) .on('cycle', function (event: any) { console.log(String(event.target)) }) diff --git a/benchmarks/nested_object.ts b/benchmarks/nested_object.ts index 75df394..ecde1b9 100644 --- a/benchmarks/nested_object.ts +++ b/benchmarks/nested_object.ts @@ -3,6 +3,8 @@ import Benchmark from 'benchmark' import { z } from 'zod' import yup from 'yup' import vine from '../index.js' +import Joi from 'joi' +import Ajv, { AsyncSchema } from 'ajv' function getData() { return { @@ -48,6 +50,44 @@ const vineSchema = vine.compile( }) ) +const joiSchema = Joi.object({ + username: Joi.string().required(), + password: Joi.string().required(), + contact: Joi.object({ + name: Joi.string().required(), + address: Joi.string(), + }).required(), +}).required() + +const ajv = new Ajv.default() +interface AjvData { + username: string + password: string + contact: { + name: string + address?: string + } +} +const ajvSchema: AsyncSchema = { + $async: true, + type: 'object', + properties: { + username: { type: 'string', nullable: false }, + password: { type: 'string', nullable: false }, + contact: { + type: 'object', + properties: { + name: { type: 'string', nullable: false }, + address: { type: 'string' }, + }, + required: ['name'], + }, + }, + required: ['username', 'password', 'contact'], + additionalProperties: false, +} +const ajvValidator = ajv.compile(ajvSchema) + console.log('=================================') console.log('Benchmarking with nested object') console.log('=================================') @@ -81,6 +121,23 @@ suite .catch(console.log) }, }) + .add('Joi', { + defer: true, + fn: function (deferred: any) { + joiSchema + .validateAsync(getData()) + .then(() => deferred.resolve()) + .catch(console.log) + }, + }) + .add('Ajv', { + defer: true, + fn: function (deferred: any) { + ajvValidator(getData()) + .then(() => deferred.resolve()) + .catch(console.log) + }, + }) .on('cycle', function (event: any) { console.log(String(event.target)) }) diff --git a/benchmarks/union.ts b/benchmarks/union.ts index 6901bf7..8214765 100644 --- a/benchmarks/union.ts +++ b/benchmarks/union.ts @@ -2,6 +2,8 @@ import Benchmark from 'benchmark' import { z } from 'zod' import vine from '../index.js' +import Joi from 'joi' +import Ajv, { AsyncSchema } from 'ajv' function getData() { return { @@ -46,6 +48,58 @@ const vineSchema = vine.compile( }) ) +const joiSchema = Joi.object({ + contact: Joi.alternatives() + .try( + Joi.object({ type: 'email', email: Joi.string().required() }), + Joi.object({ type: 'phone', mobile_number: Joi.string().required() }) + ) + .required(), +}).required() + +const ajv = new Ajv.default({ discriminator: true }) +interface AjvEmail { + type: 'email' + email: string +} +interface AjvPhone { + type: 'phone' + mobile_number: string +} +interface AjvData { + contact: AjvEmail | AjvPhone +} +const ajvSchema: AsyncSchema = { + $async: true, + type: 'object', + properties: { + contact: { + type: 'object', + discriminator: { propertyName: 'type' }, + required: ['type'], + oneOf: [ + { + properties: { + type: { const: 'email' }, + email: { type: 'string', nullable: false }, + }, + required: ['email'], + }, + { + properties: { + type: { const: 'phone' }, + mobile_number: { type: 'string', nullable: false }, + }, + required: ['mobile_number'], + }, + ], + }, + }, + required: ['contact'], + additionalProperties: false, +} +const ajvValidator = ajv.compile(ajvSchema) + console.log('=======================') console.log('Benchmarking unions') console.log('=======================') @@ -70,6 +124,23 @@ suite .catch(console.log) }, }) + .add('Joi', { + defer: true, + fn: function (deferred: any) { + joiSchema + .validateAsync(getData()) + .then(() => deferred.resolve()) + .catch((err) => console.dir(err, { depth: 20, colors: true })) + }, + }) + .add('Ajv', { + defer: true, + fn: function (deferred: any) { + ajvValidator(getData()) + .then(() => deferred.resolve()) + .catch(console.log) + }, + }) .on('cycle', function (event: any) { console.log(String(event.target)) }) diff --git a/package.json b/package.json index 3fec489..9929846 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,9 @@ "@poppinss/macroable": "^1.0.0-6", "@types/validator": "^13.7.17", "@vinejs/compiler": "^2.0.1", + "ajv": "^8.12.0", "camelcase": "^7.0.1", + "joi": "^17.9.2", "normalize-url": "^8.0.0", "validator": "^13.9.0" },