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   8585 use namespace::autoclean;
  3         6  
  3         90  
4              
5 3     3   1583 use Class::Null;
  3         939  
  3         69  
6 3     3   1102 use File::DataClass::Cache;
  3         11  
  3         98  
7 3     3   22 use File::DataClass::Constants qw( EXCEPTION_CLASS FALSE NUL PERMS TRUE );
  3         6  
  3         206  
8 3         167 use File::DataClass::Functions qw( ensure_class_loaded first_char
9             qualify_storage_class map_extension2class
10             merge_attributes supported_extensions
11 3     3   16 throw );
  3         6  
12 3     3   16 use File::DataClass::IO;
  3         8  
  3         20  
13 3     3   1539 use File::DataClass::ResultSource;
  3         12  
  3         96  
14 3     3   1466 use File::DataClass::Storage;
  3         10  
  3         115  
15 3         19 use File::DataClass::Types qw( Bool Cache ClassName Directory DummyClass
16 3     3   23 HashRef Lock Num Object Path Str );
  3         6  
17 3     3   5725 use File::Spec;
  3         8  
  3         90  
18 3     3   19 use Scalar::Util qw( blessed );
  3         7  
  3         176  
19 3     3   20 use Unexpected::Functions qw( Unspecified );
  3         8  
  3         20  
20 3     3   929 use Moo;
  3         9  
  3         16  
21              
22             my $_cache_objects = {};
23              
24             # Private methods
25             my $_build_cache = sub {
26 16     16   726 my $self = shift;
27             my $attr = { builder => $self,
28 16         35 cache_attributes => { %{ $self->cache_attributes } }, };
  16         110  
29 16         42 my $cattr = $attr->{cache_attributes};
30 16         103 (my $ns = lc __PACKAGE__) =~ s{ :: }{-}gmx;
31              
32 16   66     89 $ns = $cattr->{namespace} //= $ns;
33 16 100       234 exists $_cache_objects->{ $ns } and return $_cache_objects->{ $ns };
34 4 100       24 $self->cache_class eq 'none' and return Class::Null->new;
35 3   66     23 $cattr->{share_file} //= $self->tempdir->catfile( "${ns}.dat" )->pathname;
36              
37 3         66 return $_cache_objects->{ $ns } = $self->cache_class->new( $attr );
38             };
39              
40             my $_build_source_registrations = sub {
41 7     7   74 my $self = shift; my $sources = {};
  7         17  
42              
43 7         16 for my $moniker (keys %{ $self->result_source_attributes }) {
  7         38  
44 6         15 my $attr = { %{ $self->result_source_attributes->{ $moniker } } };
  6         29  
45             my $class = delete $attr->{result_source_class}
46 6   66     40 // $self->result_source_class;
47              
48 6         15 $attr->{name} = $moniker; $attr->{schema} = $self;
  6         14  
49              
50 6         79 $sources->{ $moniker } = $class->new( $attr );
51             }
52              
53 7         314 return $sources;
54             };
55              
56             my $_build_storage = sub {
57 17     17   1144 my $self = shift; my $class = $self->storage_class;
  17         255  
58              
59 17 100       287 if (first_char $class eq '+') { $class = substr $class, 1 }
  2         7  
60 15         54 else { $class = qualify_storage_class $class }
61              
62 17         74 ensure_class_loaded $class;
63              
64 17         520 return $class->new( { %{ $self->storage_attributes }, schema => $self } );
  17         299  
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   426 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   868 builder => sub { Class::Null->new };
89              
90             has 'log' => is => 'lazy', isa => Object,
91 14     14   605 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   470 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   1516 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   468 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 193 my ($self, $args) = @_; blessed $self or $self = $self->$_constructor;
  8         45  
135              
136 8 100 66     87 my $path = $args->{path} // $self->path; blessed $path or $path = io $path;
  8         73  
137              
138 8         123 return $self->storage->dump( $path, $args->{data} );
139             }
140              
141             sub load {
142 13 100   13 1 6070 my ($self, @paths) = @_; blessed $self or $self = $self->$_constructor;
  13         77  
143              
144 13   66     183 $paths[ 0 ] //= $self->path;
145              
146 13 100       298 return $self->storage->load( map { (blessed $_) ? $_ : io $_ } @paths );
  15         710  
147             }
148              
149             sub resultset {
150 22     22 1 15461 my ($self, $moniker) = @_; return $self->source( $moniker )->resultset;
  22         67  
151             }
152              
153             sub source {
154 22     22 1 46 my ($self, $moniker) = @_;
155              
156 22 100       69 $moniker or throw Unspecified, [ 'result source' ];
157              
158 21 100       442 my $source = $self->source_registrations->{ $moniker }
159             or throw 'Result source [_1] unknown', [ $moniker ];
160              
161 20         356 return $source;
162             }
163              
164             sub sources {
165 1     1 1 26 return keys %{ shift->source_registrations };
  1         15  
166             }
167              
168             sub translate {
169 2     2 1 2376 my ($self, $args) = @_;
170              
171 2   66     16 my $class = blessed $self || $self; # uncoverable condition false
172 2   100     13 my $from_class = $args->{from_class} // 'Any';
173 2   100     10 my $to_class = $args->{to_class } // 'Any';
174 2         11 my $attr = { path => $args->{from}, storage_class => $from_class };
175 2         60 my $data = $class->new( $attr )->load;
176              
177 2         46 $attr = { path => $args->{to}, storage_class => $to_class };
178 2         78 $class->new( $attr )->dump( { data => $data } );
179 2         45 return;
180             }
181              
182             1;
183              
184             __END__