line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package WebAPI::DBIC::Resource::Role::ItemWritable; |
2
|
|
|
|
|
|
|
$WebAPI::DBIC::Resource::Role::ItemWritable::VERSION = '0.004001'; |
3
|
|
|
|
|
|
|
|
4
|
2
|
|
|
2
|
|
28507331
|
use Carp qw(croak confess); |
|
2
|
|
|
|
|
24
|
|
|
2
|
|
|
|
|
365
|
|
5
|
2
|
|
|
2
|
|
1100
|
use Devel::Dwarn; |
|
2
|
|
|
|
|
19627
|
|
|
2
|
|
|
|
|
37
|
|
6
|
|
|
|
|
|
|
|
7
|
2
|
|
|
2
|
|
1377
|
use Moo::Role; |
|
2
|
|
|
|
|
42189
|
|
|
2
|
|
|
|
|
13
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
requires 'render_item_into_body'; |
11
|
|
|
|
|
|
|
requires 'decode_json'; |
12
|
|
|
|
|
|
|
requires 'item'; |
13
|
|
|
|
|
|
|
requires 'param'; |
14
|
|
|
|
|
|
|
requires 'prefetch'; |
15
|
|
|
|
|
|
|
requires 'request'; |
16
|
|
|
|
|
|
|
requires 'response'; |
17
|
|
|
|
|
|
|
requires 'path_for_item'; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# By default the DBIx::Class::Row update() call will only update the |
21
|
|
|
|
|
|
|
# columns where %$hal contains different values to the ones in $item. |
22
|
|
|
|
|
|
|
# This is usually a useful optimization but not always. So we provide |
23
|
|
|
|
|
|
|
# a way to disable it on individual resources. |
24
|
|
|
|
|
|
|
has skip_dirty_check => ( |
25
|
|
|
|
|
|
|
is => 'rw', |
26
|
|
|
|
|
|
|
); |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
has _pre_update_resource_method => ( |
29
|
|
|
|
|
|
|
is => 'rw', |
30
|
|
|
|
|
|
|
); |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
has content_types_accepted => ( |
33
|
|
|
|
|
|
|
is => 'lazy', |
34
|
|
|
|
|
|
|
); |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
sub _build_content_types_accepted { |
37
|
0
|
|
|
0
|
|
|
return [ {'application/vnd.wapid+json' => 'from_plain_json'} ] |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
sub from_plain_json { |
42
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
43
|
0
|
|
|
|
|
|
my $data = $self->decode_json( $self->request->content ); |
44
|
0
|
|
|
|
|
|
$self->update_resource($data, is_put_replace => 0); |
45
|
0
|
|
|
|
|
|
return; |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
around 'allowed_methods' => sub { |
50
|
|
|
|
|
|
|
my $orig = shift; |
51
|
|
|
|
|
|
|
my $self = shift; |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
my $methods = $self->$orig(); |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
$methods = [ qw(PUT DELETE), @$methods ] if $self->writable; |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
return $methods; |
58
|
|
|
|
|
|
|
}; |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
|
61
|
0
|
|
|
0
|
0
|
|
sub delete_resource { return $_[0]->item->delete } |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
sub _do_update_resource { |
65
|
0
|
|
|
0
|
|
|
my ($self, $item, $hal, $result_class) = @_; |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
# provide a hook for richer behaviour, eg HAL |
68
|
0
|
|
|
|
|
|
my $_pre_update_resource_method = $self->_pre_update_resource_method; |
69
|
0
|
0
|
|
|
|
|
$self->$_pre_update_resource_method($item, $hal, $result_class) |
70
|
|
|
|
|
|
|
if $_pre_update_resource_method; |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
# By default the DBIx::Class::Row update() call below will only update the |
73
|
|
|
|
|
|
|
# columns where %$hal contains different values to the ones in $item |
74
|
|
|
|
|
|
|
# This is usually a useful optimization but not always. So we provide |
75
|
|
|
|
|
|
|
# a way to disable it on individual resources. |
76
|
0
|
0
|
|
|
|
|
if ($self->skip_dirty_check) { |
77
|
0
|
|
|
|
|
|
$item->make_column_dirty($_) for keys %$hal; |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
# Note that update() calls set_inflated_columns() |
81
|
0
|
|
|
|
|
|
$item->update($hal); |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
# XXX discard_changes causes a refetch of the record for prefetch |
84
|
|
|
|
|
|
|
# perhaps worth trying to avoid the discard if not required |
85
|
0
|
|
|
|
|
|
$item->discard_changes(); |
86
|
|
|
|
|
|
|
|
87
|
0
|
|
|
|
|
|
return $item; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub update_resource { |
92
|
0
|
|
|
0
|
0
|
|
my ($self, $hal, %opts) = @_; |
93
|
0
|
|
|
|
|
|
my $is_put_replace = delete $opts{is_put_replace}; |
94
|
0
|
0
|
|
|
|
|
croak "update_resource: invalid options: @{[ keys %opts ]}" |
|
0
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
if %opts; |
96
|
|
|
|
|
|
|
|
97
|
0
|
|
|
|
|
|
my $schema = $self->item->result_source->schema; |
98
|
|
|
|
|
|
|
# XXX perhaps the transaction wrapper belongs higher in the stack |
99
|
|
|
|
|
|
|
# but it has to be below the auth layer which switches schemas |
100
|
|
|
|
|
|
|
$schema->txn_do(sub { |
101
|
|
|
|
|
|
|
|
102
|
0
|
|
|
0
|
|
|
my $item; |
103
|
0
|
0
|
|
|
|
|
if ($is_put_replace) { |
104
|
|
|
|
|
|
|
# PUT == http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6 |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
# Using delete() followed by create() is a strict implementation |
107
|
|
|
|
|
|
|
# of treating PUT on an item as a REPLACE, but it might not be ideal. |
108
|
|
|
|
|
|
|
# Specifically it requires any FKs to be DEFERRED and it'll less |
109
|
|
|
|
|
|
|
# efficient than a simple UPDATE. There's also a concern that if |
110
|
|
|
|
|
|
|
# the REST API only has a partial view of the resource, ie not all |
111
|
|
|
|
|
|
|
# columns, then do we want the original deleted if the 'hidden' |
112
|
|
|
|
|
|
|
# fields can't be set? |
113
|
|
|
|
|
|
|
# So this could me made optional on a per-resource-class basis, |
114
|
|
|
|
|
|
|
# and/or via a request parameter. |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# we require PK fields to at least be defined |
117
|
|
|
|
|
|
|
# XXX we ought to check that they match the URL since a PUT is |
118
|
|
|
|
|
|
|
# required to store the entity "under the supplied Request-URI". |
119
|
|
|
|
|
|
|
# XXX throw proper exception |
120
|
|
|
|
|
|
|
defined $hal->{$_} or die "missing PK '$_'\n" |
121
|
0
|
|
0
|
|
|
|
for $self->set->result_source->primary_columns; |
122
|
|
|
|
|
|
|
|
123
|
0
|
|
|
|
|
|
my $old_item = $self->item; # XXX might already be gone since the find() |
124
|
0
|
0
|
|
|
|
|
$old_item->delete if $old_item; # XXX might already be gone since the find() |
125
|
|
|
|
|
|
|
|
126
|
0
|
|
|
|
|
|
my $links = delete $hal->{_links}; |
127
|
0
|
|
|
|
|
|
my $meta = delete $hal->{_meta}; |
128
|
0
|
|
0
|
|
|
|
my $embedded = delete $hal->{_embedded} && die "_embedded not supported here (yet?)\n"; |
129
|
|
|
|
|
|
|
|
130
|
0
|
|
|
|
|
|
$item = $self->set->create($hal); # handles deflation |
131
|
|
|
|
|
|
|
|
132
|
0
|
0
|
|
|
|
|
$self->response->header('Location' => $self->path_for_item($item)) |
133
|
|
|
|
|
|
|
unless $old_item; # set Location and thus 201 if Created not modified |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
else { |
136
|
0
|
|
|
|
|
|
$item = $self->_do_update_resource($self->item, $hal, $self->item->result_class); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
0
|
|
|
|
|
|
$self->item($item); |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# called here because create_path() is too late for WM |
142
|
|
|
|
|
|
|
# and we need it to happen inside the transaction for rollback=1 to work |
143
|
|
|
|
|
|
|
# XXX requires 'self' prefetch to get any others |
144
|
0
|
0
|
|
|
|
|
$self->render_item_into_body() if grep {defined $_->{self}} @{$self->prefetch||[]}; |
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
|
146
|
0
|
0
|
|
|
|
|
$schema->txn_rollback if $self->param('rollback'); # XXX |
147
|
0
|
|
|
|
|
|
}); |
148
|
0
|
|
|
|
|
|
return; |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
1; |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
__END__ |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=pod |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=encoding UTF-8 |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=head1 NAME |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
WebAPI::DBIC::Resource::Role::ItemWritable |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=head1 VERSION |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
version 0.004001 |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=head1 NAME |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
WebAPI::DBIC::Resource::Role::ItemWritable - methods handling requests to update item resources |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=head1 AUTHOR |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
Tim Bunce <Tim.Bunce@pobox.com> |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
This software is copyright (c) 2015 by Tim Bunce. |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
180
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=cut |