line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
2
|
|
|
2
|
|
1777
|
use utf8; |
|
2
|
|
|
|
|
19
|
|
|
2
|
|
|
|
|
15
|
|
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package JSON::API::v1; |
4
|
|
|
|
|
|
|
our $VERSION = '0.001'; |
5
|
2
|
|
|
2
|
|
667
|
use Moose; |
|
2
|
|
|
|
|
471847
|
|
|
2
|
|
|
|
|
14
|
|
6
|
2
|
|
|
2
|
|
15359
|
use namespace::autoclean; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
20
|
|
7
|
2
|
|
|
2
|
|
191
|
use Carp qw(croak); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
166
|
|
8
|
2
|
|
|
2
|
|
14
|
use List::Util qw(uniq); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
2239
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our @CARP_NOT = qw(Class::MOP::Method::Wrapped); |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# ABSTRACT: A JSON API object according to jsonapi.org v1 specification |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
has data => ( |
15
|
|
|
|
|
|
|
is => 'ro', |
16
|
|
|
|
|
|
|
isa => 'ArrayRef[JSON::API::v1::Resource]', |
17
|
|
|
|
|
|
|
traits => ['Array'], |
18
|
|
|
|
|
|
|
lazy => 1, |
19
|
|
|
|
|
|
|
default => sub { [] }, |
20
|
|
|
|
|
|
|
reader => '_data', |
21
|
|
|
|
|
|
|
handles => { add_data => 'push', has_data => 'count', data => 'uniq' }, |
22
|
|
|
|
|
|
|
); |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
has is_set => ( |
25
|
|
|
|
|
|
|
is => 'ro', |
26
|
|
|
|
|
|
|
isa => 'Bool', |
27
|
|
|
|
|
|
|
lazy => 1, |
28
|
|
|
|
|
|
|
default => 0, |
29
|
|
|
|
|
|
|
predicate => 'has_is_set', |
30
|
|
|
|
|
|
|
writer => '_is_set', |
31
|
|
|
|
|
|
|
); |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
has errors => ( |
34
|
|
|
|
|
|
|
is => 'ro', |
35
|
|
|
|
|
|
|
isa => 'ArrayRef[JSON::API::v1::Error]', |
36
|
|
|
|
|
|
|
traits => ['Array'], |
37
|
|
|
|
|
|
|
lazy => 1, |
38
|
|
|
|
|
|
|
default => sub { [] }, |
39
|
|
|
|
|
|
|
handles => { add_error => 'push', has_errors => 'count' }, |
40
|
|
|
|
|
|
|
); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
has jsonapi => ( |
43
|
|
|
|
|
|
|
is => 'ro', |
44
|
|
|
|
|
|
|
isa => 'Defined', |
45
|
|
|
|
|
|
|
predicate => 'has_jsonapi', |
46
|
|
|
|
|
|
|
); |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
has included => ( |
49
|
|
|
|
|
|
|
is => 'ro', |
50
|
|
|
|
|
|
|
isa => 'ArrayRef[JSON::API::v1::Resource]', |
51
|
|
|
|
|
|
|
traits => ['Array'], |
52
|
|
|
|
|
|
|
lazy => 1, |
53
|
|
|
|
|
|
|
default => sub { [] }, |
54
|
|
|
|
|
|
|
reader => '_included', |
55
|
|
|
|
|
|
|
handles => { |
56
|
|
|
|
|
|
|
add_included => 'push', |
57
|
|
|
|
|
|
|
has_included => 'count', |
58
|
|
|
|
|
|
|
included => 'uniq' |
59
|
|
|
|
|
|
|
}, |
60
|
|
|
|
|
|
|
); |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
around BUILDARGS => sub { |
63
|
|
|
|
|
|
|
my ($orig, $self, %args) = @_; |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
foreach (qw(data included errors)) { |
66
|
|
|
|
|
|
|
if (exists $args{$_} && defined $args{$_} && blessed($args{$_})) { |
67
|
|
|
|
|
|
|
$args{$_} = [ $args{$_} ]; |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
if (exists $args{data} && @{ $args{data} } > 1) { |
71
|
|
|
|
|
|
|
if (exists $args{is_set} && !$args{is_set}) { |
72
|
|
|
|
|
|
|
croak( |
73
|
|
|
|
|
|
|
"You are entering a set of data and telling me you are not a" |
74
|
|
|
|
|
|
|
. " set, this is incorrect!"); |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
$args{is_set} = 1 unless exists $args{is_set}; |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
return $self->$orig(%args); |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
}; |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
around add_data => sub { |
83
|
|
|
|
|
|
|
my ($orig, $self, @data) = @_; |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
if ($self->has_is_set) { |
86
|
|
|
|
|
|
|
if (!$self->is_set && $self->has_data) { |
87
|
|
|
|
|
|
|
croak("Unable to add data, this isn't a set!"); |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
return $self->$orig(@data); |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
$self->_is_set(1); |
92
|
|
|
|
|
|
|
return $self->$orig(@data); |
93
|
|
|
|
|
|
|
}; |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
around included => sub { |
96
|
|
|
|
|
|
|
my ($orig, $self) = @_; |
97
|
|
|
|
|
|
|
return $self->_assert_uniq('included', $orig); |
98
|
|
|
|
|
|
|
}; |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
sub _assert_uniq { |
101
|
7
|
|
|
7
|
|
19
|
my ($self, $type, $orig) = @_; |
102
|
|
|
|
|
|
|
|
103
|
7
|
|
|
|
|
238
|
my @rv = $self->$orig; |
104
|
7
|
|
|
|
|
31
|
my @check = uniq map { { id => $_->id, type => $_->type } } @rv; |
|
10
|
|
|
|
|
276
|
|
105
|
7
|
50
|
|
|
|
22
|
if (@check == @rv) { |
106
|
7
|
|
|
|
|
40
|
return \@rv; |
107
|
|
|
|
|
|
|
} |
108
|
0
|
|
|
|
|
0
|
croak("Duplicate ID and type are found for $type"); |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
around data => sub { |
112
|
|
|
|
|
|
|
my ($orig, $self) = @_; |
113
|
|
|
|
|
|
|
return $self->_assert_uniq('data', $orig); |
114
|
|
|
|
|
|
|
}; |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub as_data_object { |
117
|
7
|
|
|
7
|
0
|
15
|
my $self = shift; |
118
|
|
|
|
|
|
|
|
119
|
7
|
50
|
|
|
|
232
|
croak("You called me as a data object, but I'm in an error state!") |
120
|
|
|
|
|
|
|
if $self->has_errors; |
121
|
|
|
|
|
|
|
|
122
|
7
|
|
|
|
|
18
|
my %rv; |
123
|
|
|
|
|
|
|
|
124
|
7
|
100
|
|
|
|
221
|
if ($self->has_data) { |
|
|
50
|
|
|
|
|
|
125
|
6
|
100
|
|
|
|
145
|
$rv{data} = $self->is_set ? $self->data : $self->data->[0]; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
elsif ($self->is_set) { |
128
|
0
|
|
|
|
|
0
|
$rv{data} = [], |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
else { |
131
|
1
|
|
|
|
|
4
|
$rv{data} = undef; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
7
|
100
|
|
|
|
244
|
$rv{included} = $self->included if $self->has_included; |
135
|
7
|
50
|
|
|
|
216
|
$rv{jsonapi} = $self->jsonapi if $self->has_jsonapi; |
136
|
|
|
|
|
|
|
|
137
|
7
|
|
|
|
|
66
|
return \%rv; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub as_error_object { |
141
|
1
|
|
|
1
|
0
|
3
|
my $self = shift; |
142
|
|
|
|
|
|
|
|
143
|
1
|
50
|
|
|
|
32
|
croak("You called me as an error object, but I'm not in an error state!") |
144
|
|
|
|
|
|
|
unless $self->has_errors; |
145
|
|
|
|
|
|
|
|
146
|
1
|
|
|
|
|
27
|
return { errors => $self->errors }; |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub TO_JSON { |
150
|
8
|
|
|
8
|
0
|
182
|
my $self = shift; |
151
|
|
|
|
|
|
|
|
152
|
8
|
100
|
|
|
|
316
|
return $self->as_error_object if $self->has_errors; |
153
|
7
|
|
|
|
|
25
|
return $self->as_data_object; |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
with qw( |
158
|
|
|
|
|
|
|
JSON::API::v1::Roles::TO_JSON |
159
|
|
|
|
|
|
|
JSON::API::v1::Roles::MetaObject |
160
|
|
|
|
|
|
|
JSON::API::v1::Roles::Links |
161
|
|
|
|
|
|
|
); |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
__END__ |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=pod |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=encoding UTF-8 |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=head1 NAME |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
JSON::API::v1 - A JSON API object according to jsonapi.org v1 specification |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=head1 VERSION |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
version 0.001 |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=head1 SYNOPSIS |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
use JSON::API::v1; |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
my $object = JSON::API::v1->new( |
184
|
|
|
|
|
|
|
data => JSON::API::v1::Resource->new( |
185
|
|
|
|
|
|
|
... |
186
|
|
|
|
|
|
|
); |
187
|
|
|
|
|
|
|
); |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
$object->add_error(JSON::API::v1::Error->new(...)); |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
$object->add_relationship(JSON::API::v1::Error->new(...)); |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=head1 DESCRIPTION |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
This module attempts to make a Moose object behave like a JSON API object as |
196
|
|
|
|
|
|
|
defined by L<jsonapi.org>. This object adheres to the v1 specification |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=head2 data |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
This data object is there a L<JSON::API::v1::Resource> lives. |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=head2 errors |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
This becomes an array ref of L<JSON::API::v1::Error> once you start |
207
|
|
|
|
|
|
|
adding errors to this object object via C<add_error>. |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=head2 included |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
This becomes an array ref of L<JSON::API::v1::Resource> once you start |
212
|
|
|
|
|
|
|
adding additional resources to this object object via C<add_included>. |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
=head2 is_set |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
This is to tell the object it is a set and you can add data to it via |
217
|
|
|
|
|
|
|
C<add_data>. It will in turn JSON-y-fi the data to an array of the data you've |
218
|
|
|
|
|
|
|
added. If you don't set this via the constructer, please read the documentation |
219
|
|
|
|
|
|
|
of L<JSON::API::v1/add_data> |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=head1 METHODS |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=head2 add_data |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
You can add individual L<JSON::API::v1::Resource> objects to the |
226
|
|
|
|
|
|
|
toplevel object. If you have not set is_set the first call to this function |
227
|
|
|
|
|
|
|
will assume you're adding data and thus want to be a set. |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=head2 add_error |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
You can add individual L<JSON::API::v1::Error> objects to the |
232
|
|
|
|
|
|
|
toplevel object. |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=head2 add_included |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
You can add individual L<JSON::API::v1::Resource> objects to the |
237
|
|
|
|
|
|
|
toplevel object. |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=head1 AUTHOR |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
Wesley Schwengle <waterkip@cpan.org> |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
This software is Copyright (c) 2020 by Wesley Schwengle. |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
This is free software, licensed under: |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
The (three-clause) BSD License |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
=cut |