File Coverage

blib/lib/Raisin/Entity.pm
Criterion Covered Total %
statement 88 107 82.2
branch 26 52 50.0
condition 13 33 39.3
subroutine 19 19 100.0
pod 1 2 50.0
total 147 213 69.0


line stmt bran cond sub pod time code
1             #!perl
2             #PODNAME: Raisin::Entity
3             #ABSTRACT: A simple facade to use with your API
4              
5 8     8   70944 use strict;
  8         26  
  8         261  
6 8     8   45 use warnings;
  8         16  
  8         395  
7              
8             package Raisin::Entity;
9             $Raisin::Entity::VERSION = '0.93';
10 8     8   563 use parent 'Exporter';
  8         347  
  8         48  
11              
12 8     8   489 use Carp;
  8         16  
  8         543  
13 8     8   52 use Scalar::Util qw(blessed);
  8         23  
  8         418  
14 8     8   3755 use Types::Standard qw/HashRef/;
  8         476942  
  8         98  
15              
16 8     8   10237 use Raisin::Entity::Object;
  8         21  
  8         442  
17              
18             our @EXPORT = qw(expose);
19              
20             my @SUBNAME;
21              
22             sub import {
23             {
24 8     8   60 no strict 'refs';
  8     9   19  
  8         813  
  9         875  
25              
26 9         24 my $class = caller;
27              
28 9     5   58 *{ "${class}::name" } = sub { $class };
  9         72  
  5         18  
29             # A kind of a workaround for OpenAPI
30             # Every entity has a HashRef type even if it is not, so it could cause
31             # issues for users in OpenAPI specification.
32 9     2   30 *{ "${class}::type" } = sub { HashRef };
  9         41  
  2         10  
33 9         40 *{ "${class}::enclosed" } = sub {
34 8     8   65 no strict 'refs';
  8         17  
  8         1032  
35 4     4   7 \@{ "${class}::EXPOSE" };
  4         29  
36 9         31 };
37             }
38              
39 9         136236 Raisin::Entity->export_to_level(1, @_);
40             }
41              
42             sub expose {
43 34     34 1 84013 my ($name, @params) = @_;
44              
45 34         97 my $class = caller;
46 34 100       117 if (scalar @SUBNAME) {
47 3         11 $class = 'Raisin::Entity::Nested::' . join('', @SUBNAME);
48             }
49              
50             {
51 8     8   56 no strict 'refs';
  8         17  
  8         865  
  34         63  
52 34         57 push @{ "${class}::EXPOSE" }, Raisin::Entity::Object->new($name, @params);
  34         349  
53             }
54              
55 34 100       132 return $class if scalar @SUBNAME;
56             }
57              
58             sub compile {
59 26     26 0 9304 my ($self, $entity, $data) = @_;
60              
61 26         43 my @expose = do {
62 8     8   68 no strict 'refs';
  8         22  
  8         6338  
63 26         41 @{ "${entity}::EXPOSE" };
  26         128  
64             };
65              
66 26 100       90 @expose = _make_exposition($data) unless @expose;
67 26 100       74 return $data unless @expose;
68              
69 14         31 my $result;
70              
71             # Rose::DB::Object::Iterator, DBIx::Class::ResultSet
72 14 50 33     128 if (blessed($data) && $data->can('next')) {
    50 0        
    50 0        
      33        
73 0         0 while (my $i = $data->next) {
74 0         0 push @$result, _compile_column($entity, $i, \@expose);
75             }
76              
77 0 0       0 $result = [] unless $result;
78             }
79             # Array
80             elsif (ref($data) eq 'ARRAY') {
81 0         0 for my $i (@$data) {
82 0         0 push @$result, _compile_column($entity, $i, \@expose);
83             }
84              
85 0 0       0 $result = [] unless $result;
86             }
87             # Hash, Rose::DB::Object, DBIx::Class::Core
88             elsif (ref($data) eq 'HASH'
89             || (blessed($data)
90             && ( $data->isa('Rose::DB::Object')
91             || $data->isa('DBIx::Class::Core'))))
92             {
93 14         57 $result = _compile_column($entity, $data, \@expose);
94             }
95             # Scalar, everything else
96             else {
97 0         0 $result = $data;
98             }
99              
100 14         40 $result;
101             }
102              
103             sub _compile_column {
104 23     23   121 my ($entity, $data, $settings) = @_;
105 23         40 my %result;
106              
107 23         393 for my $obj (@$settings) {
108              
109 26 50 66     202 next if blessed($obj) && $obj->condition && !$obj->condition->($data);
      66        
110              
111 26 50       204 my $column = blessed($obj) ? $obj->name : $obj->{name};
112              
113 26 50       206 my $key = blessed($obj) ? $obj->display_name : $obj->{name};
114 26         117 my $value = do {
115 26 100 66     138 if (blessed($obj) and my $runtime = $obj->runtime) {
    100 66        
116              
117 5         35 push @SUBNAME, "${entity}::$column";
118 5         21 my $retval = $runtime->($data);
119 5         15 pop @SUBNAME;
120              
121 5 100 33     46 if ($retval && !ref($retval) && $retval =~ /^Raisin::Entity::Nested::/) {
      66        
122 3         24 $retval = __PACKAGE__->compile($retval, $data);
123             }
124              
125 5         13 $retval;
126             }
127             elsif (blessed($obj) and my $e = $obj->using) {
128 2 50       29 my $in = blessed($data) ? $data->$column : $data->{$column};
129 2         9 __PACKAGE__->compile($e, $in);
130             }
131             else {
132 19 50       297 blessed($data) ? $data->$column : $data->{$column};
133             }
134             };
135              
136 26         84 $result{$key} = $value;
137             }
138              
139 23         56 \%result;
140             }
141              
142             sub _make_exposition {
143 21     21   12962 my $data = shift;
144              
145 21         37 my @columns = do {
146 21 50       153 if (blessed($data)) {
    50          
    50          
147 0 0       0 if ($data->isa('DBIx::Class::ResultSet')) {
    0          
    0          
    0          
148 0         0 keys %{ $data->result_class->columns_info };
  0         0  
149             }
150             elsif ($data->isa('DBIx::Class::Core')) {
151 0         0 keys %{ $data->columns_info };
  0         0  
152             }
153             elsif ($data->isa('Rose::DB::Object')) {
154 0         0 $data->meta->column_names;
155             }
156             elsif ($data->isa('Rose::DB::Object::Iterator')) {
157 0         0 croak 'Rose::DB::Object::Iterator isn\'t supported';
158             }
159             }
160             elsif (ref($data) eq 'ARRAY') {
161 0 0 0     0 if (blessed($data->[0]) && $data->[0]->isa('Rose::DB::Object')) {
162 0         0 $data->[0]->meta->column_names;
163             }
164             else {
165 0         0 ();
166             }
167             }
168             elsif (ref($data) eq 'HASH') {
169 21         65 ();
170             }
171             };
172              
173 21 50       67 return if not @columns;
174 0           map { { name => $_ } } @columns;
  0            
175             }
176              
177             1;
178              
179             __END__