рдЪреМрдХрдбрд╝реА 9: рдПрд▓реЗрдЧреНрд░реЛ | рдкреНрд░рджрд░реНрд╢рди

рдЬрдм рдЪреМрдХрдбрд╝реА рдбреЗрдЯрд╛ рд╕рддреНрдпрд╛рдкрди рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдмрдирд╛рдИ рдЧрдИ рдереА , рддреЛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕реНрдерд▓ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд┐рдП рдЧрдП рдереЗ:



рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рдореИрдВ рдкреНрд░рджрд░реНрд╢рди quartetрдФрд░ рдЗрд╕рдХреЗ рдХрд╛рд░рдгреЛрдВ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░рдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛ ред


рдмреНрд░реЗрд╡рд┐рдЯрд┐рдЯреА рдПрдВрдб рд╕рд┐рдВрдкрд▓рд┐рд╕рд┐рдЯреА рдкрд░ рдПрдХ рд▓реЗрдЦ 4 рдЕрдкреНрд░реИрд▓ рдХреЛ рд╣реЛрдЧрд╛ред


рд╣рдо рдЗрд╕ рдкрд╣рд▓реВ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ quartetрдФрд░ рдПрдХ рдФрд░ рдЕрдзрд┐рдХ рд▓реЛрдХрдкреНрд░рд┐рдп ajv рдХреЗ рдмреАрдЪ рдХреА рдЦреЛрдЬ рдХрд░реЗрдВрдЧреЗ ред


рдирдорд╕реНрддреЗ рджреБрдирд┐рдпрд╛


рд╣рдо рд╕рдмрд╕реЗ рд╕рд░рд▓ рдкрд░реАрдХреНрд╖рдг рд▓рд┐рдЦреЗрдВрдЧреЗ - рдХреНрдпрд╛ рдореВрд▓реНрдп рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╣реИ "рд╣реИрд▓реЛ рд╡рд░реНрд▓реНрдб!"ред


рд╕рддреНрдпрд╛рдкрди рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреА рддреБрд▓рдирд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдбреЗрдЯрд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдо рдорд╛рдиреНрдп рдХрд░реЗрдВрдЧреЗред рддрджрдиреБрд╕рд╛рд░, рдЗрд╕ рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╡реИрдз рдФрд░ рдЧреИрд░-рд╡реИрдз рдбреЗрдЯрд╛ рдХреЗ рдРрд╕реЗ рд╕реЗрдЯ рд╣реИрдВред


const valids = ["Hello World!"];
const invalids = [null, false, undefined, "", 1, Infinity, "Hello World"];

AJV


рд╣рдореЗрд╢рд╛ рдХреА рддрд░рд╣, рдпрд╣ рд╕рдм рдЖрдпрд╛рдд рд╕реЗ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИ:


const Ajv = require("ajv");

"рд╕рдВрдХрд▓рдХ" рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рдПрдБ:


const ajv = new Ajv();

Ajv рдЗрдирдкреБрдЯ JSON рдпреЛрдЬрдирд╛ рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рдорд╛рдиреНрдп рдкреНрд░рдХрд╛рд░ рдХреЗ рд╡рд┐рд╡рд░рдг рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ ред


рдЖрдЗрдП рдЕрдкрдиреЗ рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрдкрдпреБрдХреНрдд рдпреЛрдЬрдирд╛ рдмрдирд╛рдПрдВред


const helloWorldSchema = {
  type: "string",
  enum: ["Hello World!"]
};

рдЕрдЧрд▓рд╛, рд╕рддреНрдпрд╛рдкрди рдлрд╝рдВрдХреНрд╢рди рдХреЛ "рд╕рдВрдХрд▓рд┐рдд" рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рдЕрд░реНрдерд╛рддреН, рд╕рд░реНрдХрд┐рдЯ рд╕реЗ, рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ рдЬреЛ рдЗрдирдкреБрдЯ рдбреЗрдЯрд╛ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░реЗрдЧрд╛, рдФрд░ рдЖрдЙрдЯрдкреБрдЯ trueрд╕рдлрд▓ рд╣реЛрдиреЗ рдкрд░ рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рдПрдЧрд╛, рдЕрдиреНрдпрдерд╛ рд╕рддреНрдпрд╛рдкрди рд╕рдлрд▓ рд╣реЛрдЧрд╛ falseред


const ajvValidator = ajv.compile(helloWorldSchema);

рдХрд┐рдпрд╛ рд╣реБрдЖ!


benchmark.


, :


Ajv Build
661,639 ops/sec
354,725 ops/sec
628,443 ops/sec
659,900 ops/sec
557,037 ops/sec

: 572,349 ops/sec

:


for (let i = 0; i < valids.length; i++) {
  ajvValidator(valids[i]);
}
for (let i = 0; i < invalids.length; i++) {
  ajvValidator(invalids[i]);
}

:


Ajv Validation

21,452,228 ops/sec
 3,066,770 ops/sec
 4,522,850 ops/sec
 2,522,777 ops/sec
 2,741,310 ops/sec

: 6,861,187 ops/sec

тАФ , .


quartet


╤Ф ┬л┬╗:


const { v } = require("quartet");

:


const quartetValidator = v("Hello World!");

:


Quartet 9: Allegro Build

6,019,078 ops/sec
3,893,780 ops/sec
2,712,363 ops/sec
5,926,415 ops/sec
2,729,369 ops/sec

: 4,256,201 ops/sec

:


for (let i = 0; i < valids.length; i++) {
  quartetValidator(valids[i]);
}
for (let i = 0; i < invalids.length; i++) {
  quartetValidator(invalids[i]);
}

:


Quartet 9: Allegro Validation

15,073,432 ops/sec
13,711,573 ops/sec
13,123,812 ops/sec
25,617,225 ops/sec
17,588,846 ops/sec

: 17,022,977 ops/sec

:


рдЫрд╡рд┐


рдЫрд╡рд┐



:


console.log("Function");
console.log(quartetValidator.toString());

:


function (value) { return value === c; }

c тАФ , .



. , , .



. API. , :


interface Person {
  id: number; //   
  name: string; //  
  phone: string | null; // null  12  
  phoneBook: {
    [name: string]: string; // 12  
  };
  gender: "male" | "female";
}


const valids = [
  {
    id: 1,
    name: "andrew",
    phone: "380975003434",
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    },
    gender: "male"
  },
  {
    id: 2,
    name: "bohdan",
    phone: null,
    phoneBook: {},
    gender: "male"
  },
  {
    id: 3,
    name: "Elena",
    phone: null,
    phoneBook: {
      siroja: "380975003434"
    },
    gender: "female"
  }
];

const invalids = [
  null, //  
  false, //  
  undefined, //  
  "", //  
  1, //  
  Infinity, //  
  "Hello World", //  
  {
    id: 0, //   
    name: "andrew",
    phone: "380975003434",
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    },
    gender: "male"
  },
  {
    //  id
    name: "andrew",
    phone: "380975003434",
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    },
    gender: "male"
  },
  {
    id: 1.5, //  
    name: "andrew",
    phone: "380975003434",
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    },
    gender: "male"
  },
  {
    id: 1,
    name: "", //  
    phone: "380975003434",
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    },
    gender: "male"
  },
  {
    id: 1,
    //  name
    phone: "380975003434",
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    },
    gender: "male"
  },
  {
    id: 1,
    name: "andrew",
    phone: "38097500434", // 11 
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    },
    gender: "male"
  },
  {
    id: 1,
    name: "andrew",
    //  phone
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    },
    gender: "male"
  },
  {
    id: 1,
    name: "andrew",
    phone: "380975003434",
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "38097503434" // 11 
    },
    gender: "male"
  },
  {
    id: 1,
    name: "andrew",
    phone: "380975003434",
    // phoneBook 
    gender: "male"
  },
  {
    id: 1,
    name: "andrew",
    phone: "380975003434",
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    },
    gender: "Male" // 'male'
  },
  {
    id: 1,
    name: "andrew",
    phone: "380975003434",
    phoneBook: {
      andrew: "380975003434",
      bohdan: "380975003434",
      vasilina: "380975003434"
    }
  }
];

ajv


:


const personSchema = {
  type: "object",
  required: ["id", "name", "phone", "phoneBook", "gender"],
  properties: {
    id: {
      type: "integer",
      exclusiveMinimum: 0
    },
    name: {
      type: "string",
      minLength: 1
    },
    phone: {
      anyOf: [
        { type: "null" },
        {
          type: "string",
          pattern: "^\\d{12}$"
        }
      ]
    },
    phoneBook: {
      type: "object",
      additionalProperties: {
        type: "string",
        pattern: "^\\d{12}$"
      }
    },
    gender: {
      type: "string",
      enum: ["male", "female"]
    }
  }
};

:


const ajvCheckPerson = ajv.compile(personSchema);

:


Ajv Build

79,476 ops/sec
78,334 ops/sec
61,752 ops/sec
77,395 ops/sec
78,539 ops/sec
51,922 ops/sec
80,031 ops/sec
77,687 ops/sec
65,439 ops/sec
79,805 ops/sec

: 73,038 ops/sec

:


for (let i = 0; i < valids.length; i++) {
  ajvCheckPerson(valids[i]);
}
for (let i = 0; i < invalids.length; i++) {
  ajvCheckPerson(invalids[i]);
}

:


Ajv Validation

227,640 ops/sec
301,134 ops/sec
190,450 ops/sec
195,595 ops/sec
384,380 ops/sec
193,358 ops/sec
385,280 ops/sec
239,009 ops/sec
193,832 ops/sec
392,808 ops/sec

: 270,349 ops/sec

quartet


:


const quartetCheckPerson = v({
  id: v.and(v.safeInteger, v.positive),
  name: v.and(v.string, v.minLength(1)),
  phone: [null, v.test(/^\d{12}$/)],
  phoneBook: {
    [v.rest]: v.test(/^\d{12}$/)
  },
  gender: ["male", "female"]
});

:


Quartet 9: Allegro Build

35,564 ops/sec
14,401 ops/sec
15,438 ops/sec
26,852 ops/sec
33,935 ops/sec
16,010 ops/sec
34,550 ops/sec
33,148 ops/sec
16,037 ops/sec
36,828 ops/sec

: 26,276 ops/sec

:


for (let i = 0; i < valids.length; i++) {
  quartetCheckPerson(valids[i]);
}
for (let i = 0; i < invalids.length; i++) {
  quartetCheckPerson(invalids[i]);
}

, :


Quartet 9: Allegro Validation

237,059 ops/sec
435,844 ops/sec
248,021 ops/sec
238,931 ops/sec
416,993 ops/sec
281,904 ops/sec
439,975 ops/sec
242,074 ops/sec
330,487 ops/sec
421,704 ops/sec

: 329,299 ops/sec

:


рдЫрд╡рд┐
рдЫрд╡рд┐



, , quartetCheckPerson .


console.log(quartetCheckPerson.toString());
console.log({ ...quartetCheckPerson });


function validator(value) {
  if (value == null) return false
  if (!Number.isSafeInteger(value.id)) return false
  if (value.id <= 0) return false
  if (typeof value.name !== 'string') return false
  if (value.name == null || value.name.length < 1) return false
  if (!validator["value.phone"](value.phone)) return false
  if (value.phoneBook == null) return false
  validator.keys = Object.keys(value.phoneBook)
  for (let i = 0; i < validator.keys.length; i++) {
    validator.elem = value.phoneBook[validator.keys[i]]
    if (!validator["tester-1"].test(validator.elem)) return false
  }

  if (!validator["value.gender"](value.gender)) return false
  return true
};

// Check person properties
{
  'value.phone': function validator(value) {
    if (value === null) return true;
    if (validator.tester.test(value)) return true;
    return false
  }
  ['value.phone']['tester']: /^\d{12}$/,
  'tester-1': /^\d{12}$/,
  'value.gender': function validator(value) {
    if (validator.__validValuesDict[value] === true) return true
    return false
  },
  ['value.gender']['__validValuesDict']: {
    male: true,
    female: true
  }
}

тАФ , тАФ .


:


ajv


тАФ ajv , errors.


quartet


quartet - .


:


1) v.custom. тАФ , explanations , . тАФ тАФ


:


const checkId = v(v.and(v.safeInteger, v.positive));
const checkName = v(v.and(v.string, v.minLength(1)));
const checkPhone = v([null, v.test(/^\d{12}$/)]);
const checkPhoneBookItem = v(v.test(/^\d{12}$/));
const checkGender = v(["male", "female"]);

const quartetCheckPerson = v({
    id: v.custom(checkId, "id"),
    name: v.custom(checkName, "name"),
    phone: v.custom(checkPhone, "phone"),
    phoneBook: {
      [v.rest]: v.custom(checkPhoneBookItem, "phoneBook")
    },
    gender: v.custom(checkGender, "gender")
  }); 

// quartetCheckPerson({}) // false
// quartetCheckPerson.explanations // ['id']

рдорд╛рдк рдХрд░реЗрдВ:
рдЫрд╡рд┐
рдЫрд╡рд┐


2) рджреВрд╕рд░реА рд╡рд┐рдзрд┐ рдЕрдзрд┐рдХ рд╡рд┐рдЪрд╛рд░рдзрд╛рд░рд╛рддреНрдордХ рд╣реИ - рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдХрд╕реНрдЯрдо рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ред рдЬреИрд╕реЗ рд╣реА рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛рдУрдВ рдореЗрдВ рд╕реЗ рдХреЛрдИ рдПрдХ рдЧрд▓рдд рд╣реЛрддрд╛ рд╣реИ рддреНрд░реБрдЯрд┐рдмрд╛рдЙрдВрдбрд░реА рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред


import { quartet } from 'quartet'
const v = quartet({
  errorBoundary(explanations, { value, id, schema, innerExplanations }) {
    explanations.push(...innerExplanations, { value, id, schema })
  }
})

const checkPerson = v({
  id: v.and(v.safeInteger, v.positive),
  name: v.and(v.string, v.minLength(1)),
  phone: [null, v.test(/^\d{12}$/)],
  phoneBook: {
    [v.rest]: v.test(/^\d{12}$/)
  },
  gender: ["male", "female"]
});

// checkPerson(null) // false
// checkPerson.explanations // [{ value: null, id: 'value', schema: { id: ... }]

рдорд╛рдк рдХрд░реЗрдВ:


рдЫрд╡рд┐
рдЫрд╡рд┐


рд╕рд╛рд░рд╛рдВрд╢


рддреБрд▓рдирд╛ рдорд┐рд╢реНрд░рд┐рдд рдкрд░рд┐рдгрд╛рдо рджреЗрддреА рд╣реИред рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЬрд┐рдиреНрд╣реЗрдВ рдкреНрд░рджрд░реНрд╢рди рдФрд░ рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ - ajv рдЪреБрдиреЗрдВред рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЬрд┐рдиреНрд╣реЗрдВ рд╡рд┐рдХрд▓рд╛рдВрдЧреЛрдВ рдХреЗ рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ - рдЪреМрдХрдбрд╝реА рд▓реЗрддреЗ рд╣реИрдВ - рдФрд░ рдЕрдзрд┐рдХ рдкрдардиреАрдп рдФрд░ рдЕрднрд┐рд╡реНрдпрдВрдЬрдХ рдпреЛрдЬрдирд╛ рдХреЗ рд╕рд╛рде рдФрд░ рднреА рдЕрдзрд┐рдХ рдкреНрд░рджрд░реНрд╢рди рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВред
рдореИрдВ рдЗрд╕ рдкрд░рд┐рдгрд╛рдо рд╕реЗ рдкреНрд░реЛрддреНрд╕рд╛рд╣рд┐рдд рд╣реВрдВред рдореБрдЭреЗ рдЖрд╢рд╛ рд╣реИ рдХрд┐ рдкрд╛рдардХ quartet@9рд╡реНрдпрд╡рд╣рд╛рд░ рдореЗрдВ рдкреНрд░рдпрд╛рд╕ рдХрд░рдирд╛ рдЪрд╛рд╣реЗрдВрдЧреЗ ред


рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдХреЛ рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рджрд┐рд▓рдЪрд╕реНрдкред


All Articles