| 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__ |