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   70244 use strict;
  8         26  
  8         217  
6 8     8   33 use warnings;
  8         12  
  8         350  
7              
8             package Raisin::Entity;
9             $Raisin::Entity::VERSION = '0.94';
10 8     8   440 use parent 'Exporter';
  8         318  
  8         38  
11              
12 8     8   387 use Carp;
  8         17  
  8         472  
13 8     8   40 use Scalar::Util qw(blessed);
  8         14  
  8         372  
14 8     8   2969 use Types::Standard qw/HashRef/;
  8         397358  
  8         87  
15              
16 8     8   8935 use Raisin::Entity::Object;
  8         19  
  8         383  
17              
18             our @EXPORT = qw(expose);
19              
20             my @SUBNAME;
21              
22             sub import {
23             {
24 8     8   51 no strict 'refs';
  8     9   12  
  8         747  
  9         545  
25              
26 9         23 my $class = caller;
27              
28 9     5   52 *{ "${class}::name" } = sub { $class };
  9         56  
  5         13  
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   28 *{ "${class}::type" } = sub { HashRef };
  9         32  
  2         6  
33 9         33 *{ "${class}::enclosed" } = sub {
34 8     8   44 no strict 'refs';
  8         14  
  8         838  
35 4     4   5 \@{ "${class}::EXPOSE" };
  4         21  
36 9         27 };
37             }
38              
39 9         107284 Raisin::Entity->export_to_level(1, @_);
40             }
41              
42             sub expose {
43 34     34 1 79480 my ($name, @params) = @_;
44              
45 34         89 my $class = caller;
46 34 100       126 if (scalar @SUBNAME) {
47 3         13 $class = 'Raisin::Entity::Nested::' . join('', @SUBNAME);
48             }
49              
50             {
51 8     8   45 no strict 'refs';
  8         15  
  8         749  
  34         55  
52 34         54 push @{ "${class}::EXPOSE" }, Raisin::Entity::Object->new($name, @params);
  34         328  
53             }
54              
55 34 100       112 return $class if scalar @SUBNAME;
56             }
57              
58             sub compile {
59 26     26 0 9282 my ($self, $entity, $data) = @_;
60              
61 26         41 my @expose = do {
62 8     8   69 no strict 'refs';
  8         14  
  8         5279  
63 26         42 @{ "${entity}::EXPOSE" };
  26         125  
64             };
65              
66 26 100       87 @expose = _make_exposition($data) unless @expose;
67 26 100       82 return $data unless @expose;
68              
69 14         24 my $result;
70              
71             # Rose::DB::Object::Iterator, DBIx::Class::ResultSet
72 14 50 33     120 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         76 $result = _compile_column($entity, $data, \@expose);
94             }
95             # Scalar, everything else
96             else {
97 0         0 $result = $data;
98             }
99              
100 14         30 $result;
101             }
102              
103             sub _compile_column {
104 23     23   108 my ($entity, $data, $settings) = @_;
105 23         34 my %result;
106              
107 23         39 for my $obj (@$settings) {
108              
109 26 50 66     135 next if blessed($obj) && $obj->condition && !$obj->condition->($data);
      66        
110              
111 26 50       145 my $column = blessed($obj) ? $obj->name : $obj->{name};
112              
113 26 50       188 my $key = blessed($obj) ? $obj->display_name : $obj->{name};
114 26         102 my $value = do {
115 26 100 66     106 if (blessed($obj) and my $runtime = $obj->runtime) {
    100 66        
116              
117 5         31 push @SUBNAME, "${entity}::$column";
118 5         17 my $retval = $runtime->($data);
119 5         15 pop @SUBNAME;
120              
121 5 100 33     43 if ($retval && !ref($retval) && $retval =~ /^Raisin::Entity::Nested::/) {
      66        
122 3         21 $retval = __PACKAGE__->compile($retval, $data);
123             }
124              
125 5         12 $retval;
126             }
127             elsif (blessed($obj) and my $e = $obj->using) {
128 2 50       28 my $in = blessed($data) ? $data->$column : $data->{$column};
129 2         11 __PACKAGE__->compile($e, $in);
130             }
131             else {
132 19 50       277 blessed($data) ? $data->$column : $data->{$column};
133             }
134             };
135              
136 26         96 $result{$key} = $value;
137             }
138              
139 23         50 \%result;
140             }
141              
142             sub _make_exposition {
143 21     21   12125 my $data = shift;
144              
145 21         38 my @columns = do {
146 21 50       142 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         59 ();
170             }
171             };
172              
173 21 50       77 return if not @columns;
174 0           map { { name => $_ } } @columns;
  0            
175             }
176              
177             1;
178              
179             __END__