File Coverage

lib/File/DataClass/Schema.pm
Criterion Covered Total %
statement 101 101 100.0
branch 17 18 94.4
condition 16 22 77.2
subroutine 28 28 100.0
pod 6 6 100.0
total 168 175 96.5


line stmt bran cond sub pod time code
1             package File::DataClass::Schema;
2              
3 3     3   8551 use namespace::autoclean;
  3         4  
  3         31  
4              
5 3     3   1477 use Class::Null;
  3         758  
  3         60  
6 3     3   1023 use File::DataClass::Cache;
  3         8  
  3         91  
7 3     3   18 use File::DataClass::Constants qw( EXCEPTION_CLASS FALSE NUL PERMS TRUE );
  3         4  
  3         177  
8 3         183 use File::DataClass::Functions qw( ensure_class_loaded first_char
9             qualify_storage_class map_extension2class
10             merge_attributes supported_extensions
11 3     3   14 throw );
  3         4  
12 3     3   13 use File::DataClass::IO;
  3         4  
  3         18  
13 3     3   1587 use File::DataClass::ResultSource;
  3         7  
  3         97  
14 3     3   1388 use File::DataClass::Storage;
  3         7  
  3         106  
15 3         15 use File::DataClass::Types qw( Bool Cache ClassName Directory DummyClass
16 3     3   16 HashRef Lock Num Object Path Str );
  3         3  
17 3     3   3357 use File::Spec;
  3         6  
  3         70  
18 3     3   10 use Scalar::Util qw( blessed );
  3         3  
  3         142  
19 3     3   12 use Unexpected::Functions qw( Unspecified );
  3         4  
  3         13  
20 3     3   605 use Moo;
  3         5  
  3         12  
21              
22             my $_cache_objects = {};
23              
24             # Private methods
25             my $_build_cache = sub {
26 16     16   571 my $self = shift;
27             my $attr = { builder => $self,
28 16         29 cache_attributes => { %{ $self->cache_attributes } }, };
  16         102  
29 16         32 my $cattr = $attr->{cache_attributes};
30 16         74 (my $ns = lc __PACKAGE__) =~ s{ :: }{-}gmx;
31              
32 16   66     75 $ns = $cattr->{namespace} //= $ns;
33 16 100       214 exists $_cache_objects->{ $ns } and return $_cache_objects->{ $ns };
34 4 100       30 $self->cache_class eq 'none' and return Class::Null->new;
35 3   66     24 $cattr->{share_file} //= $self->tempdir->catfile( "${ns}.dat" )->pathname;
36              
37 3         59 return $_cache_objects->{ $ns } = $self->cache_class->new( $attr );
38             };
39              
40             my $_build_source_registrations = sub {
41 7     7   55 my $self = shift; my $sources = {};
  7         13  
42              
43 7         12 for my $moniker (keys %{ $self->result_source_attributes }) {
  7         36  
44 6         11 my $attr = { %{ $self->result_source_attributes->{ $moniker } } };
  6         24  
45             my $class = delete $attr->{result_source_class}
46 6   66     40 // $self->result_source_class;
47              
48 6         10 $attr->{name} = $moniker; $attr->{schema} = $self;
  6         9  
49              
50 6         77 $sources->{ $moniker } = $class->new( $attr );
51             }
52              
53 7         246 return $sources;
54             };
55              
56             my $_build_storage = sub {
57 17     17   907 my $self = shift; my $class = $self->storage_class;
  17         233  
58              
59 17 100       237 if (first_char $class eq '+') { $class = substr $class, 1 }
  2         6  
60 15         48 else { $class = qualify_storage_class $class }
61              
62 17         57 ensure_class_loaded $class;
63              
64 17         504 return $class->new( { %{ $self->storage_attributes }, schema => $self } );
  17         278  
65             };
66              
67             my $_constructor = sub {
68             my $class = shift;
69             my $attr = { cache_class => 'none', storage_class => 'Any' };
70              
71             return $class->new( $attr );
72             };
73              
74             # Private attributes
75             has 'cache' => is => 'lazy', isa => Cache,
76             builder => $_build_cache;
77              
78             has 'cache_attributes' => is => 'ro', isa => HashRef,
79             builder => sub { {
80 17     17   401 page_size => 131_072,
81             num_pages => 89,
82             unlink_on_exit => TRUE, } };
83              
84             has 'cache_class' => is => 'ro', isa => ClassName | DummyClass,
85             default => 'File::DataClass::Cache';
86              
87             has 'lock' => is => 'lazy', isa => Lock,
88 16     16   667 builder => sub { Class::Null->new };
89              
90             has 'log' => is => 'lazy', isa => Object,
91 14     14   483 builder => sub { Class::Null->new };
92              
93             has 'path' => is => 'rw', isa => Path, coerce => TRUE;
94              
95             has 'perms' => is => 'rw', isa => Num, default => PERMS;
96              
97             has 'result_source_attributes' => is => 'ro', isa => HashRef,
98 8     8   454 builder => sub { {} };
99              
100             has 'result_source_class' => is => 'ro', isa => ClassName,
101             default => 'File::DataClass::ResultSource';
102              
103             has 'source_registrations' => is => 'lazy', isa => HashRef[Object],
104             builder => $_build_source_registrations;
105              
106             has 'storage' => is => 'rw', isa => Object,
107             builder => $_build_storage, lazy => TRUE;
108              
109             has 'storage_attributes' => is => 'ro', isa => HashRef,
110 15     15   1195 builder => sub { {} };
111              
112             has 'storage_class' => is => 'rw', isa => Str,
113             default => 'JSON', lazy => TRUE;
114              
115             has 'tempdir' => is => 'ro', isa => Directory,
116 5     5   351 coerce => TRUE, builder => sub { File::Spec->tmpdir };
117              
118             # Construction
119             around 'BUILDARGS' => sub {
120             my ($orig, $self, @args) = @_; my $attr = $orig->( $self, @args );
121              
122             my $builder = $attr->{builder} or return $attr;
123             my $config = $builder->can( 'config' ) ? $builder->config : {};
124             my $keys = [ qw( cache_attributes cache_class lock log tempdir ) ];
125              
126             merge_attributes $attr, $builder, $keys;
127             merge_attributes $attr, $config, $keys;
128              
129             return $attr;
130             };
131              
132             # Public methods
133             sub dump {
134 8 50   8 1 151 my ($self, $args) = @_; blessed $self or $self = $self->$_constructor;
  8         37  
135              
136 8 100 66     75 my $path = $args->{path} // $self->path; blessed $path or $path = io $path;
  8         56  
137              
138 8         110 return $self->storage->dump( $path, $args->{data} );
139             }
140              
141             sub load {
142 13 100   13 1 3599 my ($self, @paths) = @_; blessed $self or $self = $self->$_constructor;
  13         65  
143              
144 13   66     157 $paths[ 0 ] //= $self->path;
145              
146 13 100       291 return $self->storage->load( map { (blessed $_) ? $_ : io $_ } @paths );
  15         550  
147             }
148              
149             sub resultset {
150 22     22 1 10103 my ($self, $moniker) = @_; return $self->source( $moniker )->resultset;
  22         50  
151             }
152              
153             sub source {
154 22     22 1 25 my ($self, $moniker) = @_;
155              
156 22 100       47 $moniker or throw Unspecified, [ 'result source' ];
157              
158 21 100       384 my $source = $self->source_registrations->{ $moniker }
159             or throw 'Result source [_1] unknown', [ $moniker ];
160              
161 20         271 return $source;
162             }
163              
164             sub sources {
165 1     1 1 20 return keys %{ shift->source_registrations };
  1         13  
166             }
167              
168             sub translate {
169 2     2 1 1535 my ($self, $args) = @_;
170              
171 2   66     14 my $class = blessed $self || $self; # uncoverable condition false
172 2   100     9 my $from_class = $args->{from_class} // 'Any';
173 2   100     8 my $to_class = $args->{to_class } // 'Any';
174 2         8 my $attr = { path => $args->{from}, storage_class => $from_class };
175 2         43 my $data = $class->new( $attr )->load;
176              
177 2         44 $attr = { path => $args->{to}, storage_class => $to_class };
178 2         63 $class->new( $attr )->dump( { data => $data } );
179 2         35 return;
180             }
181              
182             1;
183              
184             __END__