line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Yancy::Backend::Memory; |
2
|
|
|
|
|
|
|
our $VERSION = '1.086'; |
3
|
|
|
|
|
|
|
# ABSTRACT: A backend entirely in memory |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
#pod =head1 DESCRIPTION |
6
|
|
|
|
|
|
|
#pod |
7
|
|
|
|
|
|
|
#pod An in-memory "database" backend for Yancy. Uses L to implement |
8
|
|
|
|
|
|
|
#pod basic searching for (). |
9
|
|
|
|
|
|
|
#pod |
10
|
|
|
|
|
|
|
#pod =cut |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# XXX: TODO Remove references to Local::Test |
13
|
|
|
|
|
|
|
|
14
|
23
|
|
|
23
|
|
20044
|
use Mojo::Base '-base'; |
|
23
|
|
|
|
|
65
|
|
|
23
|
|
|
|
|
178
|
|
15
|
23
|
|
|
23
|
|
4256
|
use List::Util qw( max ); |
|
23
|
|
|
|
|
53
|
|
|
23
|
|
|
|
|
1560
|
|
16
|
23
|
|
|
23
|
|
191
|
use Mojo::JSON qw( true false from_json to_json encode_json ); |
|
23
|
|
|
|
|
54
|
|
|
23
|
|
|
|
|
1559
|
|
17
|
23
|
|
|
23
|
|
155
|
use Mojo::File qw( path ); |
|
23
|
|
|
|
|
49
|
|
|
23
|
|
|
|
|
1165
|
|
18
|
23
|
|
|
23
|
|
150
|
use Storable qw( dclone ); |
|
23
|
|
|
|
|
49
|
|
|
23
|
|
|
|
|
1227
|
|
19
|
23
|
|
|
23
|
|
146
|
use Role::Tiny qw( with ); |
|
23
|
|
|
|
|
66
|
|
|
23
|
|
|
|
|
286
|
|
20
|
|
|
|
|
|
|
with 'Yancy::Backend::Role::Sync'; |
21
|
23
|
|
|
23
|
|
5158
|
use Yancy::Util qw( match is_type order_by is_format ); |
|
23
|
|
|
|
|
52
|
|
|
23
|
|
|
|
|
1532
|
|
22
|
23
|
|
|
23
|
|
14107
|
use Time::Piece; |
|
23
|
|
|
|
|
167155
|
|
|
23
|
|
|
|
|
112
|
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
our %DATA; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
sub new { |
27
|
84
|
|
|
84
|
1
|
75596
|
my ( $class, $url, $schema ) = @_; |
28
|
84
|
100
|
|
|
|
300
|
if ( $url ) { |
29
|
83
|
|
|
|
|
522
|
my ( $path ) = $url =~ m{^[^:]+://[^/]+(?:/(.+))?$}; |
30
|
83
|
50
|
|
|
|
320
|
if ( $path ) { |
31
|
0
|
|
0
|
|
|
0
|
%DATA = %{ from_json( path( ( $ENV{MOJO_HOME} || () ), $path )->slurp ) }; |
|
0
|
|
|
|
|
0
|
|
32
|
|
|
|
|
|
|
} |
33
|
|
|
|
|
|
|
} |
34
|
84
|
|
100
|
|
|
313
|
$schema //= \%Local::Test::SCHEMA; |
35
|
84
|
|
|
|
|
531
|
return bless { init_arg => $url, schema => $schema }, $class; |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub schema { |
39
|
3184
|
|
|
3184
|
0
|
9600
|
my ( $self, $schema ) = @_; |
40
|
3184
|
100
|
|
|
|
6815
|
if ( $schema ) { |
41
|
51
|
|
|
|
|
144
|
$self->{schema} = $schema; |
42
|
51
|
|
|
|
|
148
|
return; |
43
|
|
|
|
|
|
|
} |
44
|
3133
|
|
|
|
|
10864
|
$self->{schema}; |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
sub collections; |
47
|
|
|
|
|
|
|
*collections = *schema; |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
sub create { |
50
|
113
|
|
|
113
|
0
|
33001
|
my ( $self, $schema_name, $params ) = @_; |
51
|
113
|
|
|
|
|
577
|
$params = { %$params }; |
52
|
113
|
|
|
|
|
361
|
my $props = $self->schema->{ $schema_name }{properties}; |
53
|
|
|
|
|
|
|
$params->{ $_ } = $props->{ $_ }{default} // undef |
54
|
113
|
|
100
|
|
|
1443
|
for grep !exists $params->{ $_ }, |
55
|
|
|
|
|
|
|
keys %$props; |
56
|
113
|
|
|
|
|
513
|
$params = $self->_normalize( $schema_name, $params ); # makes a copy |
57
|
|
|
|
|
|
|
|
58
|
113
|
|
100
|
|
|
399
|
my $id_field = $self->schema->{ $schema_name }{ 'x-id-field' } || 'id'; |
59
|
113
|
100
|
|
|
|
433
|
my @id_fields = ref $id_field eq 'ARRAY' ? @$id_field : ( $id_field ); |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
# Fill in any auto-increment data... |
62
|
113
|
|
|
|
|
299
|
for my $id_field ( @id_fields ) { |
63
|
|
|
|
|
|
|
# We haven't provided a value for an integer ID, assume it's autoinc |
64
|
118
|
100
|
66
|
|
|
825
|
if ( !$params->{ $id_field } and $self->schema->{ $schema_name }{properties}{ $id_field }{type} eq 'integer' ) { |
|
|
100
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
65
|
55
|
|
|
|
|
100
|
my @existing_ids = keys %{ $DATA{ $schema_name } }; |
|
55
|
|
|
|
|
225
|
|
66
|
55
|
|
100
|
|
|
464
|
$params->{ $id_field} = ( max( @existing_ids ) // 0 ) + 1; |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
# We have provided another ID, make 'id' another autoinc |
69
|
|
|
|
|
|
|
elsif ( $params->{ $id_field } |
70
|
|
|
|
|
|
|
&& $id_field ne 'id' |
71
|
|
|
|
|
|
|
&& exists $self->schema->{ $schema_name }{properties}{id} |
72
|
|
|
|
|
|
|
) { |
73
|
46
|
|
|
|
|
94
|
my @existing_ids = map { $_->{ id } } values %{ $DATA{ $schema_name } }; |
|
45
|
|
|
|
|
132
|
|
|
46
|
|
|
|
|
156
|
|
74
|
46
|
|
100
|
|
|
325
|
$params->{id} = ( max( @existing_ids ) // 0 ) + 1; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
113
|
|
100
|
|
|
404
|
my $store = $DATA{ $schema_name } //= {}; |
79
|
113
|
|
|
|
|
476
|
for my $i ( 0 .. $#id_fields-1 ) { |
80
|
5
|
|
100
|
|
|
41
|
$store = $store->{ $params->{ $id_fields[$i] } } //= {}; |
81
|
|
|
|
|
|
|
} |
82
|
113
|
|
|
|
|
466
|
$store->{ $params->{ $id_fields[-1] } } = $params; |
83
|
|
|
|
|
|
|
|
84
|
113
|
100
|
|
|
|
738
|
return @id_fields > 1 ? { map {; $_ => $params->{ $_ } } @id_fields } : $params->{ $id_field }; |
|
10
|
|
|
|
|
59
|
|
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub get { |
88
|
327
|
|
|
327
|
0
|
475993
|
my ( $self, $schema_name, $id, %opt ) = @_; |
89
|
327
|
|
|
|
|
1000
|
my $schema = $self->schema->{ $schema_name }; |
90
|
327
|
|
100
|
|
|
2411
|
my $real_coll = ( $schema->{'x-view'} || {} )->{schema} // $schema_name; |
|
|
|
66
|
|
|
|
|
91
|
|
|
|
|
|
|
|
92
|
327
|
|
100
|
|
|
905
|
my $id_field = $self->schema->{ $schema_name }{ 'x-id-field' } || 'id'; |
93
|
327
|
100
|
|
|
|
1287
|
my @ids = ref $id_field eq 'ARRAY' ? map { $id->{ $_ } } @$id_field : ( $id ); |
|
25
|
|
|
|
|
90
|
|
94
|
326
|
100
|
66
|
|
|
1101
|
die "Missing composite ID parts" if @ids > 1 && ( !ref $id || keys %$id < @ids ); |
|
|
|
100
|
|
|
|
|
95
|
|
|
|
|
|
|
|
96
|
325
|
|
|
|
|
868
|
my $item = $DATA{ $real_coll }; |
97
|
325
|
|
|
|
|
765
|
for my $id ( @ids ) { |
98
|
336
|
100
|
|
|
|
996
|
return undef if !defined $id; |
99
|
333
|
|
100
|
|
|
1461
|
$item = $item->{ $id } // return undef; |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
280
|
|
|
|
|
955
|
$item = $self->_viewise( $schema_name, $item ); |
103
|
280
|
100
|
|
|
|
1285
|
if ( my $join = $opt{join} ) { |
104
|
3
|
|
|
|
|
14
|
$item = $self->_join( $schema_name, $item, $join ); |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
280
|
|
|
|
|
1470
|
return $item; |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub _join { |
111
|
19
|
|
|
19
|
|
57
|
my ( $self, $schema_name, $item, $join, $where ) = @_; |
112
|
19
|
|
|
|
|
116
|
$item = { %$item }; |
113
|
19
|
|
|
|
|
52
|
my $schema = $self->schema->{ $schema_name }; |
114
|
19
|
|
50
|
|
|
44
|
my $id_field = $self->schema->{ $schema_name }{ 'x-id-field' } || 'id'; |
115
|
19
|
100
|
|
|
|
75
|
my @joins = ref $join eq 'ARRAY' ? @$join : ( $join ); |
116
|
19
|
|
|
|
|
42
|
for my $join ( @joins ) { |
117
|
26
|
100
|
|
|
|
86
|
if ( my $join_prop = $schema->{ properties }{ $join } ) { |
|
|
50
|
|
|
|
|
|
118
|
21
|
|
100
|
|
|
60
|
my $join_id = $item->{ $join } || next; |
119
|
17
|
|
|
|
|
32
|
my $join_schema_name = $join_prop->{'x-foreign-key'}; |
120
|
17
|
|
|
|
|
54
|
$item->{ $join } = $self->get( $join_schema_name, $join_id ); |
121
|
17
|
|
|
|
|
157
|
for my $key ( grep /^${join}\./, keys %$where ) { |
122
|
7
|
|
|
|
|
73
|
my ( $k ) = $key =~ /^${join}\.(.+)$/; |
123
|
7
|
100
|
|
|
|
36
|
if ( !match( { $k => $where->{ $key } }, $item->{ $join } ) ) { |
124
|
|
|
|
|
|
|
# Inner match fails, so this row is not in the |
125
|
|
|
|
|
|
|
# results |
126
|
2
|
|
|
|
|
15
|
return; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
elsif ( my $join_schema = $self->schema->{ $join } ) { |
131
|
5
|
|
|
|
|
11
|
my $join_schema_name = $join; |
132
|
5
|
|
100
|
|
|
9
|
my ( $join_id_field ) = grep { ( $join_schema->{properties}{$_}{'x-foreign-key'}//'' ) eq $schema_name } keys %{ $join_schema->{properties} }; |
|
20
|
|
|
|
|
86
|
|
|
5
|
|
|
|
|
21
|
|
133
|
5
|
50
|
|
|
|
26
|
my $join_where = ref $id_field eq 'ARRAY' ? { map { $_ => $item->{ $_ } } @$join_id_field } : { $join_id_field => $item->{$join_id_field} }; |
|
0
|
|
|
|
|
0
|
|
134
|
5
|
|
|
|
|
10
|
my $min_items = 0; |
135
|
5
|
|
|
|
|
37
|
for my $key ( grep /^${join}\./, keys %$where ) { |
136
|
2
|
|
|
|
|
22
|
my ( $k ) = $key =~ /^${join}\.(.+)$/; |
137
|
2
|
|
|
|
|
6
|
$join_where->{ $k } = $where->{ $key }; |
138
|
2
|
|
|
|
|
6
|
$min_items = 1; |
139
|
|
|
|
|
|
|
} |
140
|
5
|
|
|
|
|
25
|
my $res = $self->list( $join_schema_name, $join_where ); |
141
|
5
|
100
|
|
|
|
23
|
return if $res->{total} < $min_items; |
142
|
4
|
|
|
|
|
18
|
$item->{ $join } = $res->{items}; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
} |
145
|
16
|
|
|
|
|
61
|
return $item; |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
sub _viewise { |
149
|
626
|
|
|
626
|
|
1975
|
my ( $self, $schema_name, $item, $join ) = @_; |
150
|
626
|
|
|
|
|
23186
|
$item = dclone $item; |
151
|
626
|
|
|
|
|
2281
|
my $schema = $self->schema->{ $schema_name }; |
152
|
626
|
|
100
|
|
|
3797
|
my $real_coll = ( $schema->{'x-view'} || {} )->{schema} // $schema_name; |
|
|
|
66
|
|
|
|
|
153
|
|
|
|
|
|
|
my %props = %{ |
154
|
626
|
|
|
|
|
1250
|
$schema->{properties} || $self->schema->{ $real_coll }{properties} |
155
|
626
|
100
|
|
|
|
4567
|
}; |
156
|
626
|
100
|
|
|
|
1866
|
if ( $join ) { |
157
|
12
|
100
|
|
|
|
18
|
$props{ $_ } = 1 for @{ ref $join eq 'ARRAY' ? $join : [ $join ] }; |
|
12
|
|
|
|
|
57
|
|
158
|
|
|
|
|
|
|
} |
159
|
626
|
|
|
|
|
4130
|
delete $item->{$_} for grep !$props{ $_ }, keys %$item; |
160
|
626
|
|
|
|
|
2781
|
$item; |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
sub list { |
164
|
327
|
|
|
327
|
0
|
394652
|
my ( $self, $schema_name, $params, @opt ) = @_; |
165
|
327
|
100
|
|
|
|
1246
|
my $opt = @opt % 2 == 0 ? {@opt} : $opt[0]; |
166
|
327
|
|
|
|
|
983
|
my $schema = $self->schema->{ $schema_name }; |
167
|
327
|
50
|
|
|
|
982
|
die "list attempted on non-existent schema '$schema_name'" unless $schema; |
168
|
327
|
|
100
|
|
|
1210
|
$params ||= {}; |
169
|
|
|
|
|
|
|
|
170
|
327
|
|
100
|
|
|
712
|
my $id_field = $self->schema->{ $schema_name }{ 'x-id-field' } || 'id'; |
171
|
327
|
100
|
|
|
|
1145
|
my @id_fields = ref $id_field eq 'ARRAY' ? @$id_field : ( $id_field ); |
172
|
|
|
|
|
|
|
|
173
|
327
|
|
100
|
|
|
2158
|
my $real_coll = ( $schema->{'x-view'} || {} )->{schema} // $schema_name; |
|
|
|
66
|
|
|
|
|
174
|
|
|
|
|
|
|
my $props = $schema->{properties} |
175
|
327
|
|
33
|
|
|
1126
|
|| $self->schema->{ $real_coll }{properties}; |
176
|
327
|
|
|
|
|
558
|
my @rows = values %{ $DATA{ $real_coll } }; |
|
327
|
|
|
|
|
1179
|
|
177
|
327
|
|
|
|
|
1138
|
for my $id_field ( 1..$#id_fields ) { |
178
|
8
|
|
|
|
|
41
|
@rows = map values %$_, @rows; |
179
|
|
|
|
|
|
|
} |
180
|
327
|
100
|
|
|
|
979
|
if ( $opt->{join} ) { |
181
|
6
|
|
|
|
|
54
|
@rows = map $self->_join( $schema_name, $_, $opt->{join}, $params ), @rows; |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
# Join queries have been resolved |
184
|
327
|
100
|
|
|
|
1081
|
for my $p ( ref $params eq 'ARRAY' ? @$params : ( $params ) ) { |
185
|
328
|
|
|
|
|
1365
|
for my $key ( grep /\./, keys %$p ) { |
186
|
4
|
|
|
|
|
9
|
delete $p->{ $key }; |
187
|
4
|
|
|
|
|
13
|
my ( $j ) = split /\./, $key; |
188
|
4
|
|
|
|
|
15
|
$p->{ $j } = { '!=' => undef }; |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
my $matched_rows = order_by( |
192
|
|
|
|
|
|
|
$opt->{order_by} // \@id_fields, |
193
|
327
|
|
100
|
|
|
1535
|
[ grep { match( $params, $_ ) } @rows ], |
|
537
|
|
|
|
|
1533
|
|
194
|
|
|
|
|
|
|
); |
195
|
327
|
|
100
|
|
|
1373
|
my $first = $opt->{offset} // 0; |
196
|
327
|
100
|
|
|
|
964
|
my $last = $opt->{limit} ? $opt->{limit} + $first - 1 : $#$matched_rows; |
197
|
327
|
100
|
|
|
|
944
|
if ( $last > $#$matched_rows ) { |
198
|
57
|
|
|
|
|
118
|
$last = $#$matched_rows; |
199
|
|
|
|
|
|
|
} |
200
|
327
|
|
|
|
|
1635
|
my @items = map $self->_viewise( $schema_name, $_, $opt->{join} ), @$matched_rows[ $first .. $last ]; |
201
|
327
|
|
|
|
|
1271
|
my $retval = { |
202
|
|
|
|
|
|
|
items => \@items, |
203
|
|
|
|
|
|
|
total => scalar @$matched_rows, |
204
|
|
|
|
|
|
|
}; |
205
|
|
|
|
|
|
|
#; use Data::Dumper; |
206
|
|
|
|
|
|
|
#; say Dumper $retval; |
207
|
327
|
|
|
|
|
1846
|
return $retval; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
sub set { |
211
|
58
|
|
|
58
|
0
|
50573
|
my ( $self, $schema_name, $id, $params ) = @_; |
212
|
58
|
|
100
|
|
|
199
|
my $id_field = $self->schema->{ $schema_name }{ 'x-id-field' } || 'id'; |
213
|
58
|
100
|
|
|
|
275
|
my @id_fields = ref $id_field eq 'ARRAY' ? @$id_field : ( $id_field ); |
214
|
58
|
100
|
100
|
|
|
235
|
die "Missing composite ID parts" if @id_fields > 1 && ( !ref $id || keys %$id < @id_fields ); |
|
|
|
100
|
|
|
|
|
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
# Fill in any missing params from the ID |
217
|
56
|
|
|
|
|
157
|
for my $id_field ( @id_fields ) { |
218
|
58
|
100
|
|
|
|
202
|
my $id_part = ref $id eq 'HASH' ? $id->{ $id_field } : $id; |
219
|
58
|
100
|
|
|
|
602
|
if ( !$params->{ $id_field } ) { |
220
|
34
|
|
|
|
|
151
|
$params->{ $id_field } = $id_part; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
|
224
|
56
|
|
|
|
|
209
|
$params = $self->_normalize( $schema_name, $params ); |
225
|
|
|
|
|
|
|
|
226
|
56
|
|
|
|
|
170
|
my $store = $DATA{ $schema_name }; |
227
|
56
|
|
|
|
|
224
|
for my $i ( 0..$#id_fields-1 ) { |
228
|
2
|
|
|
|
|
7
|
my $id_field = $id_fields[ $i ]; |
229
|
2
|
50
|
|
|
|
16
|
my $id_part = ref $id eq 'HASH' ? $id->{ $id_field } : $id; |
230
|
2
|
50
|
|
|
|
10
|
return 0 if !$store->{ $id_part }; |
231
|
|
|
|
|
|
|
# Update the item's ID if it changes |
232
|
2
|
|
|
|
|
7
|
my $item = delete $store->{ $id_part }; |
233
|
2
|
|
|
|
|
9
|
$store->{ $params->{ $id_field } } = $item; |
234
|
2
|
|
|
|
|
6
|
$store = $item; |
235
|
|
|
|
|
|
|
} |
236
|
56
|
100
|
|
|
|
200
|
my $id_part = ref $id eq 'HASH' ? $id->{ $id_fields[-1] } : $id; |
237
|
56
|
100
|
|
|
|
225
|
return 0 if !$store->{ $id_part }; |
238
|
|
|
|
|
|
|
$store->{ $params->{ $id_fields[-1] } } = { |
239
|
46
|
|
|
|
|
97
|
%{ delete $store->{ $id_part } }, |
|
46
|
|
|
|
|
596
|
|
240
|
|
|
|
|
|
|
%$params, |
241
|
|
|
|
|
|
|
}; |
242
|
|
|
|
|
|
|
|
243
|
46
|
|
|
|
|
294
|
return 1; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
sub delete { |
247
|
94
|
|
|
94
|
0
|
838294
|
my ( $self, $schema_name, $id ) = @_; |
248
|
94
|
50
|
|
|
|
341
|
return 0 if !$id; |
249
|
94
|
|
100
|
|
|
267
|
my $id_field = $self->schema->{ $schema_name }{ 'x-id-field' } || 'id'; |
250
|
94
|
100
|
|
|
|
365
|
my @id_fields = ref $id_field eq 'ARRAY' ? @$id_field : ( $id_field ); |
251
|
94
|
100
|
100
|
|
|
315
|
die "Missing composite ID parts" if @id_fields > 1 && ( !ref $id || keys %$id < @id_fields ); |
|
|
|
100
|
|
|
|
|
252
|
92
|
|
|
|
|
208
|
my $store = $DATA{ $schema_name }; |
253
|
92
|
|
|
|
|
285
|
for my $i ( 0..$#id_fields-1 ) { |
254
|
2
|
|
|
|
|
9
|
my $id_field = $id_fields[ $i ]; |
255
|
2
|
50
|
|
|
|
12
|
my $id_part = ref $id eq 'HASH' ? $id->{ $id_field } : $id; |
256
|
2
|
|
50
|
|
|
14
|
$store = $store->{ $id_part } // return 0; |
257
|
|
|
|
|
|
|
} |
258
|
92
|
100
|
|
|
|
282
|
my $id_part = ref $id eq 'HASH' ? $id->{ $id_fields[-1] } : $id; |
259
|
92
|
100
|
|
|
|
315
|
return 0 if !$store->{ $id_part }; |
260
|
70
|
|
|
|
|
421
|
return !!delete $store->{ $id_part }; |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
sub _normalize { |
264
|
169
|
|
|
169
|
|
416
|
my ( $self, $schema_name, $data ) = @_; |
265
|
169
|
50
|
|
|
|
450
|
return undef if !$data; |
266
|
169
|
|
|
|
|
400
|
my $schema = $self->schema->{ $schema_name }{ properties }; |
267
|
169
|
|
|
|
|
325
|
my %replace; |
268
|
169
|
|
|
|
|
610
|
for my $key ( keys %$data ) { |
269
|
1035
|
100
|
|
|
|
9970
|
next if !defined $data->{ $key }; # leave nulls alone |
270
|
819
|
|
|
|
|
1201
|
my ( $type, $format ) = @{ $schema->{ $key } }{qw( type format )}; |
|
819
|
|
|
|
|
1989
|
|
271
|
819
|
100
|
100
|
|
|
1861
|
if ( is_type( $type, 'boolean' ) ) { |
|
|
100
|
|
|
|
|
|
272
|
|
|
|
|
|
|
# Boolean: true (1, "true"), false (0, "false") |
273
|
|
|
|
|
|
|
$replace{ $key } |
274
|
56
|
100
|
100
|
|
|
406
|
= $data->{ $key } && $data->{ $key } !~ /^false$/i |
275
|
|
|
|
|
|
|
? 1 : 0; |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
elsif ( is_type( $type, 'string' ) && is_format( $format, 'date-time' ) ) { |
278
|
70
|
100
|
|
|
|
256
|
if ( $data->{ $key } eq 'now' ) { |
279
|
57
|
|
|
|
|
398
|
$replace{ $key } = Time::Piece->new->datetime; |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
} |
283
|
169
|
|
|
|
|
2719
|
+{ %$data, %replace }; |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
# Some databases can know other formats |
287
|
|
|
|
|
|
|
my %db_formats = map { $_ => 1 } qw( date time date-time binary ); |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
sub read_schema { |
290
|
104
|
|
|
104
|
0
|
74949
|
my ( $self, @table_names ) = @_; |
291
|
104
|
50
|
|
|
|
440
|
my $schema = %Local::Test::SCHEMA ? \%Local::Test::SCHEMA : $self->schema; |
292
|
104
|
|
|
|
|
29423
|
my $cloned = dclone $schema; |
293
|
104
|
|
|
|
|
1150
|
delete @$cloned{@Local::Test::SCHEMA_ADDED_COLLS}; # ones not in the "database" at all |
294
|
|
|
|
|
|
|
# zap all things that DB can't know about |
295
|
104
|
|
|
|
|
503
|
for my $c ( values %$cloned ) { |
296
|
463
|
|
|
|
|
788
|
delete $c->{'x-list-columns'}; |
297
|
463
|
|
|
|
|
623
|
for my $p ( values %{ $c->{properties} } ) { |
|
463
|
|
|
|
|
1304
|
|
298
|
2890
|
|
|
|
|
4772
|
delete @$p{ qw(description pattern title) }; |
299
|
2890
|
100
|
100
|
|
|
6666
|
if ( $p->{format} && !$db_formats{ $p->{format} } ) { |
300
|
399
|
|
|
|
|
749
|
delete $p->{format}; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
} |
304
|
104
|
100
|
|
|
|
658
|
return @table_names ? @$cloned{ @table_names } : $cloned; |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
1
|
|
|
1
|
0
|
7072
|
sub supports { grep { $_[1] eq $_ } 'complex-type' } |
|
1
|
|
|
|
|
6
|
|
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
1; |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
__END__ |