Data validation in C ++ using the cpp-validator library



It would seem that data validation is one of the basic tasks in programming, which will be encountered at the beginning of learning a language along with "Hello world!", And in one form or another will be present in many mature projects. However, Google still gives zero relevant results when trying to find a generic open source C ++ data validation library.



, C++, , , JSON XML. , , .



- C++ GUI-, .









, C++ , , :



  • ;
  • , ;
  • , , .


.., , , ? β€” , .



, , :



  • ;
  • ;
  • .


, , , . . , β€” , , SQL. , , β€” .





cpp-validator header-only C++ C++14/C++17. cpp-validator Boost.Hana.



cpp-validator .



  • :

    • ;
    • , :

      • ;
      • getter;
    • ;
    • , .
  • - , .
  • - , , .
  • AND, OR NOT.
  • ALL ANY.
  • (lazy operands).
  • .
  • :

    • ;
    • , , , ..
  • :

    • , ;
    • ;
    • ().
  • , :

    • ;
    • , ;
    • ;
    • ;
    • .
  • , Clang, GCC, MSVC Windows, Linux, macOS, iOS, Android.




cpp-validator :



  1. , , - ;
  2. ;
  3. , , .


//  
auto container_validator=validator(
   _[size](eq,1), //      1
   _["field1"](exists,true), //  "field1"    
   _["field1"](ne,"undefined") //  "field1"     "undefined"
);

//  
std::map<std::string,std::string> map1={{"field1","value1"}};
validate(map1,container_validator);

//  ,   
error_report err;
std::map<std::string,std::string> map2={{"field2","value2"}};
validate(map2,container_validator,err);
if (err)
{
    std::cerr<<err.message()<<std::endl;
    /* :
    field1 must exist
    */
}

//  ,  
try
{
    std::map<std::string,std::string> map3={{"field1","undefined"}};
    validate(map3,container_validator);
}
catch(const validation_error& ex)
{
    std::cerr<<ex.what()<<std::endl;
    /* :
    field1 must be not equal to undefined
    */
}


cpp-validator , , - , , , , .





cpp-validator GitHub https://github.com/evgeniums/cpp-validator β€” 1.0.2. Boost 1.0.



, .







//  
auto v=validator(gt,100); //   100

//  
error err;

//   
validate(90,v,err);
if (err)
{
  //  
}

//  
validate(200,v,err);
if (!err)
{
  //  
}




//  
auto v=validator(gt,100); //   100

try
{
    validate(200,v); // 
    validate(90,v); //  
}
catch (const validation_error& err)
{
    std::cerr << err.what() << std::endl;
    /* :
    must be greater than 100
    */
}




//  
auto v=validator(gt,100); //   100

//    

int value1=90;
if (!v.apply(value1))
{
  //  
}

int value2=200;
if (v.apply(value2))
{
  //  
}




// :   15       "sample string"
auto v=validator(
  length(lt,15),
  value(gte,"sample string")
);

//     

std::string str1="sample";
if (!v.apply(str1))
{
  //     sample  ,  sample string
}

std::string str2="sample string+";
if (v.apply(str2))
{
  //  
}

std::string str3="too long sample string";
if (!v.apply(str3))
{
  //  ,      15 
}


, ,



// :    [95,100]
auto v=validator(in,interval(95,100));

//  
error_report err;

//  
size_t val=90;
validate(val,v,err);
if (err)
{
    std::cerr << err.message() << std::endl; 
    /* :
    must be in interval [95,100]
    */
}




//  
auto v=validator(
                _["field1"](gte,"xxxxxx")
                 ^OR^
                _["field1"](size(gte,100) ^OR^ value(gte,"zzzzzzzzzzzz"))
            );

//     

error_report err;
std::map<std::string,std::string> test_map={{"field1","value1"}};
validate(test_map,v,err);
if (err)
{
    std::cerr << err.message() << std::endl;
    /* :
    field1 must be greater than or equal to xxxxxx OR size of field1 must be greater than or equal to 100 OR field1 must be greater than or equal to zzzzzzzzzzzz
    */
}




//     
auto v=validator(
                _["field1"][1](in,range({10,20,30,40,50})),
                _["field1"][2](lt,100),
                _["field2"](exists,false),
                _["field3"](empty(flag,true))
            );

//      
error_report err;
std::map<std::string,std::map<size_t,size_t>> nested_map={
            {"field1",{{1,5},{2,50}}},
            {"field3",{}}
        };
validate(nested_map,v,err);
if (err)
{
    std::cerr << err.message() << std::endl;
    /* :
    element #1 of field1 must be in range [10, 20, 30, 40, 50]
    */
}




//   getter 
struct Foo
{
    bool red_color() const
    {
        return true;
    }
};

//    red_color
DRACOSHA_VALIDATOR_PROPERTY_FLAG(red_color,"Must be red","Must be not red");

//    red_color
auto v=validator(
    _[red_color](flag,false)
);

//       

error_report err;
Foo foo_instance;
validate(foo_instance,v,err);
if (err)
{
    std::cerr << err.message() << std::endl;
    /* :
    "Must be not red"
    */
}


-



//       setter
struct Foo
{
    std::string bar_value;

    uint32_t other_value;
    size_t some_size;

    void set_bar_value(std::string val)
    {
        bar_value=std::move(val);
    }
};

using namespace DRACOSHA_VALIDATOR_NAMESPACE;

//   
DRACOSHA_VALIDATOR_PROPERTY(bar_value);
DRACOSHA_VALIDATOR_PROPERTY(other_value);

//    set_member_t    bar_value  Foo
DRACOSHA_VALIDATOR_NAMESPACE_BEGIN

template <>
struct set_member_t<Foo,DRACOSHA_VALIDATOR_PROPERTY_TYPE(bar_value)>
{
    template <typename ObjectT, typename MemberT, typename ValueT>
    void operator() (
            ObjectT& obj,
            MemberT&&,
            ValueT&& val
        ) const
    {
        obj.set_bar_value(std::forward<ValueT>(val));
    }
};

DRACOSHA_VALIDATOR_NAMESPACE_END

//    
auto v=validator(
    _[bar_value](ilex_ne,"UNKNOWN"), //  " "   
    _[other_value](gte,1000) //    1000
);

Foo foo_instance;
error_report err;

//      bar_value  foo_instance
set_validated(foo_instance,bar_value,"Hello world",v,err);
if (!err)
{
    //  bar_value  foo_instance  
}

//       bar_value  foo_instance
set_validated(foo_instance,bar_value,"unknown",v,err);
if (err)
{
    //   
    std::cerr << err.message() << std::endl;
    /* :
     bar_value must be not equal to UNKNOWN
     */
}


- -



#include <iostream>
#include <dracosha/validator/validator.hpp>
#include <dracosha/validator/validate.hpp>
using namespace DRACOSHA_VALIDATOR_NAMESPACE;

namespace validator_ns {

//  getter  "x"
DRACOSHA_VALIDATOR_PROPERTY(GetX);

//  GetX
auto MyClassValidator=validator(
   /* 
   "x"   -   ,      GetX;
   interval.open() -       
   */
   _[GetX]("x")(in,interval(0,500,interval.open())) 
);

}
using namespace validator_ns;

//     
class MyClass {
  double x;

public:

  //   -
  MyClass(double _x) : x(_x) {
      validate(*this,MyClassValidator);
  }

  // Getter
  double GetX() const noexcept
  {
     return _x;
  }

  // Setter  -
  void SetX(double _x) {
    validate(_[validator_ns::GetX],_x,MyClassValidator);
    x = _x;
  }
};

int main()
{

//    
try {
    MyClass obj1{100.0}; // ok
}
catch (const validation_error& err)
{
}

//    
try {
    MyClass obj2{1000.0}; //   
}
catch (const validation_error& err)
{
    std::cerr << err.what() << std::endl;
    /*
     :
     x must be in interval(0,500)
    */
}

MyClass obj3{100.0};

//    
try {
    obj3.SetX(200.0); // ok
}
catch (const validation_error& err)
{
}

//     
try {
    obj3.SetX(1000.0); //   
}
catch (const validation_error& err)
{
    std::cerr << err.what() << std::endl;
    /*
     :
     x must be in interval (0,500)
    */
}

return 0;
}




//         ,   
phrase_translator tr;
tr["password"]={
                    {""},
                    {"",grammar_ru::roditelny_padezh}
               };
tr["hyperlink"]={
                    {{"",grammar_ru::zhensky_rod}},
                    {{"",grammar_ru::zhensky_rod},grammar_ru::roditelny_padezh}
                };
tr["words"]={
                {{"",grammar_ru::mn_chislo}}
            };

/* 
        
validator_translator_ru()   tr   
*/
auto tr1=extend_translator(validator_translator_ru(),tr);

//   
std::map<std::string,std::string> m1={
    {"password","123456"},
    {"hyperlink","zzzzzzzzz"}
};

//         
std::string rep;
auto ra1=make_reporting_adapter(m1,make_reporter(rep,make_formatter(tr1)));

//        

auto v1=validator(
    _["words"](exists,true)
 );
if (!v1.apply(ra1))
{
    std::cerr<<rep<<std::endl;
    /*
    :
      
    */
}
rep.clear();

auto v2=validator(
    _["hyperlink"](eq,"https://www.boost.org")
 );
if (!v2.apply(ra1))
{
    std::cerr<<rep<<std::endl;
    /*
    :
        https://www.boost.org
    */
}
rep.clear();

auto v3=validator(
    _["password"](length(gt,7))
 );
if (!v3.apply(ra1))
{
    std::cerr<<rep<<std::endl;
    /*
    :
         7
    */
}
rep.clear();

auto v4=validator(
    _["hyperlink"](length(lte,7))
 );
if (!v4.apply(ra1))
{
    std::cerr<<rep<<std::endl;
    /*
    :
           7
    */
}
rep.clear();



All Articles