Subject: | kinda slow |
I used the attached script to compare the speed of Validate::Simple with Type::Tiny. My results were that Type::Tiny is about 37 times faster.
Rate Validate_Simple Types_Standard
Validate_Simple 4.00/s -- -97%
Types_Standard 154/s 3748% --
Type::Tiny/Types::Standard is also a lot more concise to express the schema:
my $tt = Dict[
username => Str,
first_name => Str,
last_name => Optional[Str],
age => Optional[IntRange[18]],
gender => Optional[
Enum[qw/ mail femaile id_rather_not_to_say /]
],
tags => Optional[ArrayRef[Str]],
hobbies => Optional[
ArrayRef[
Enum[qw/ hiking travelling surfing laziness /]
]
],
score => Optional[HashRef[PositiveOrZeroInt]],
monthly_score => Optional[
HashRef[
HashRef[
ArrayRef->where('@$_ < 12')
]
]
]
];
The main advantage that Validate::Simple seems to offer is that Type::Tiny is geared towards giving a single result about whether the supplied data is valid or not as a whole, while Validate::Simple will drill down into the data to figure out why it's not valid, which might be more useful when, say, reporting errors from a form someone has filled out.
If there were a simple way to build a fast Type::Tiny object from Validate::Simple (or vice versa, in fact) then people could use the fast Type::Tiny check to check whether a data is valid or not, then fall back to Validate::Simple to report the errors if there are any.
Of course, in many situations, validation speed is not an issue, like if you're validating a smallish JSON structure you've been posted via HTTP, then the network and HTTP stuff is probably your app's bottleneck, and not data validation.
Subject: | vs.pl |
use strict;
use warnings;
use Validate::Simple;
my $specs = {
username => {
type => 'string',
required => 1,
},
first_name => {
type => 'string',
required => 1,
},
last_name => {
type => 'string',
},
age => {
type => 'integer',
gt => 18,
},
gender => {
type => 'enum',
values => [
'mail',
'femaile',
'id_rather_not_to_say',
],
},
tags => {
type => 'array',
of => {
type => 'string',
},
},
hobbies => {
type => 'array',
of => {
type =>'enum',
values => [ qw/hiking travelling surfing laziness/ ],
}
},
score => {
type => 'hash',
of => { type => 'non_negative_int' },
},
monthly_score => {
type => 'hash',
of => {
type => 'hash',
of => {
type => 'array',
of => { type => 'integer' },
callback => sub {
@{ $_[0] } < 12;
},
}
},
}
};
my $vs = Validate::Simple->new( $specs );
use Types::Standard -types;
use Types::Common::Numeric -types;
use Types::Common::String -types;
my $tt = Dict[
username => Str,
first_name => Str,
last_name => Optional[Str],
age => Optional[IntRange[18]],
gender => Optional[Enum[qw/ mail femaile id_rather_not_to_say /]],
tags => Optional[ArrayRef[Str]],
hobbies => Optional[ArrayRef[Enum[qw/ hiking travelling surfing laziness /]]],
score => Optional[HashRef[PositiveOrZeroInt]],
monthly_score => Optional[HashRef[HashRef[ArrayRef->where('@$_ < 12')]]]
];
use Test::More;
my $data = {
username => 'alice',
first_name => 'Alice',
last_name => 'Jones',
age => 21,
tags => [qw/ abc xyz /],
hobbies => ['hiking'],
score => { hiking => 45 },
monthly_score => { hiking => { '2020' => [ 8 ] } },
};
ok( $vs->validate($data) )
or diag explain( [$vs->errors] );
ok( $tt->check($data) );
use Benchmark qw(cmpthese);
cmpthese -3, {
Validate_Simple => sub { $vs->validate($data) for 1..1000 },
Types_Standard => sub { $tt->check($data) for 1..1000 },
};
done_testing;