File Coverage

blib/lib/Raisin/Entity.pm
Criterion Covered Total %
statement 88 109 80.7
branch 26 52 50.0
condition 13 33 39.3
subroutine 19 20 95.0
pod 1 2 50.0
total 147 216 68.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   70341 use strict;
  8         21  
  8         242  
6 8     8   42 use warnings;
  8         15  
  8         377  
7              
8             package Raisin::Entity;
9             $Raisin::Entity::VERSION = '0.92';
10 8     8   503 use parent 'Exporter';
  8         321  
  8         41  
11              
12 8     8   458 use Carp;
  8         14  
  8         549  
13 8     8   53 use Scalar::Util qw(blessed);
  8         13  
  8         419  
14 8     8   3794 use Types::Standard qw/HashRef/;
  8         471260  
  8         88  
15              
16 8     8   9783 use Raisin::Entity::Object;
  8         25  
  8         455  
17              
18             our @EXPORT = qw(expose);
19              
20             my @SUBNAME;
21              
22             sub import {
23             {
24 8     8   56 no strict 'refs';
  8     9   22  
  8         795  
  9         673  
25              
26 9         22 my $class = caller;
27              
28 9     5   57 *{ "${class}::name" } = sub { $class };
  9         63  
  5         15  
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   27 *{ "${class}::type" } = sub { HashRef };
  9     0   33  
  2         9  
33 9         38 *{ "${class}::enclosed" } = sub {
34 8     8   74 no strict 'refs';
  8         15  
  8         1012  
35 4     4   6 \@{ "${class}::EXPOSE" };
  4         22  
36 9         32 };
37             }
38              
39 9         128104 Raisin::Entity->export_to_level(1, @_);
40             }
41              
42             sub expose {
43 34     34 1 74852 my ($name, @params) = @_;
44              
45 34         71 my $class = caller;
46 34 100       82 if (scalar @SUBNAME) {
47 3         10 $class = 'Raisin::Entity::Nested::' . join('', @SUBNAME);
48             }
49              
50             {
51 8     8   54 no strict 'refs';
  8         16  
  8         846  
  34         62  
52 34         41 push @{ "${class}::EXPOSE" }, Raisin::Entity::Object->new($name, @params);
  34         206  
53             }
54              
55 34 100       103 return $class if scalar @SUBNAME;
56             }
57              
58             sub compile {
59 26     26 0 8260 my ($self, $entity, $data) = @_;
60              
61 26         41 my @expose = do {
62 8     8   59 no strict 'refs';
  8         21  
  8         6359  
63 26         34 @{ "${entity}::EXPOSE" };
  26         115  
64             };
65              
66 26 100       75 @expose = _make_exposition($data) unless @expose;
67 26 100       64 return $data unless @expose;
68              
69 14         21 my $result;
70              
71             # Rose::DB::Object::Iterator, DBIx::Class::ResultSet
72 14 50 33     97 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         47 $result = _compile_column($entity, $data, \@expose);
94             }
95             # Scalar, everything else
96             else {
97 0         0 $result = $data;
98             }
99              
100 14         33 $result;
101             }
102              
103             sub _compile_column {
104 23     23   95 my ($entity, $data, $settings) = @_;
105 23         35 my %result;
106              
107 23         43 for my $obj (@$settings) {
108              
109 26 50 66     115 next if blessed($obj) && $obj->condition && !$obj->condition->($data);
      66        
110              
111 26 50       112 my $column = blessed($obj) ? $obj->name : $obj->{name};
112              
113 26 50       161 my $key = blessed($obj) ? $obj->display_name : $obj->{name};
114 26         105 my $value = do {
115 26 100 66     98 if (blessed($obj) and my $runtime = $obj->runtime) {
    100 66        
116              
117 5         30 push @SUBNAME, "${entity}::$column";
118 5         14 my $retval = $runtime->($data);
119 5         11 pop @SUBNAME;
120              
121 5 100 33     34 if ($retval && !ref($retval) && $retval =~ /^Raisin::Entity::Nested::/) {
      66        
122 3         31 $retval = __PACKAGE__->compile($retval, $data);
123             }
124              
125 5         11 $retval;
126             }
127             elsif (blessed($obj) and my $e = $obj->using) {
128 2 50       24 my $in = blessed($data) ? $data->$column : $data->{$column};
129 2         5 __PACKAGE__->compile($e, $in);
130             }
131             else {
132 19 50       222 blessed($data) ? $data->$column : $data->{$column};
133             }
134             };
135              
136 26         73 $result{$key} = $value;
137             }
138              
139 23         60 \%result;
140             }
141              
142             sub _make_exposition {
143 21     21   11869 my $data = shift;
144              
145 21         29 my @columns = do {
146 21 50       108 if (blessed($data)) {
    50          
    50          
147 0 0       0 if ($data->isa('DBIx::Class::ResultSet')) {
    0          
    0          
    0          
148 0         0 my %columns = keys %{ $data->first->columns_info };
  0         0  
149 0         0 $data->reset;
150 0         0 %columns;
151             }
152             elsif ($data->isa('DBIx::Class::Core')) {
153 0         0 keys %{ $data->columns_info };
  0         0  
154             }
155             elsif ($data->isa('Rose::DB::Object')) {
156 0         0 $data->meta->column_names;
157             }
158             elsif ($data->isa('Rose::DB::Object::Iterator')) {
159 0         0 croak 'Rose::DB::Object::Iterator isn\'t supported';
160             }
161             }
162             elsif (ref($data) eq 'ARRAY') {
163 0 0 0     0 if (blessed($data->[0]) && $data->[0]->isa('Rose::DB::Object')) {
164 0         0 $data->[0]->meta->column_names;
165             }
166             else {
167 0         0 ();
168             }
169             }
170             elsif (ref($data) eq 'HASH') {
171 21         57 ();
172             }
173             };
174              
175 21 50       61 return if not @columns;
176 0           map { { name => $_ } } @columns;
  0            
177             }
178              
179             1;
180              
181             __END__