File Coverage

blib/lib/DBIx/NoSQL/Store.pm
Criterion Covered Total %
statement 104 136 76.4
branch 25 48 52.0
condition 7 14 50.0
subroutine 28 33 84.8
pod 0 13 0.0
total 164 244 67.2


line stmt bran cond sub pod time code
1             package DBIx::NoSQL::Store;
2             our $AUTHORITY = 'cpan:YANICK';
3             $DBIx::NoSQL::Store::VERSION = '0.0021';
4 8     8   3694 use Moose;
  8         2577431  
  8         51  
5              
6 8     8   41173 use strict;
  8         12  
  8         166  
7 8     8   31 use warnings;
  8         7  
  8         216  
8              
9 8     8   28 use Try::Tiny;
  8         13  
  8         461  
10 8     8   4892 use Path::Class;
  8         121037  
  8         444  
11              
12 8     8   4967 use JSON;
  8         73608  
  8         41  
13             eval { require JSON::XS; };
14             our $json = JSON->new->pretty;
15 62     62 0 1146 sub json { $json }
16              
17 8     8   4042 use DBIx::NoSQL::Model;
  8         21  
  8         10357  
18              
19             has database => qw/ is ro /;
20             has connection => qw/ is ro /;
21             has strict => qw/ is rw isa Bool default 0 /;
22              
23             has storage => qw/ is ro lazy_build 1 /;
24             sub _build_storage {
25 9     9   17 my $self = shift;
26 9         4505 require DBIx::NoSQL::Storage;
27 9         100 return DBIx::NoSQL::Storage->new( store => $self );
28             }
29              
30             has _model => qw/ is ro lazy_build 1 /;
31 9     9   212 sub _build__model { {} }
32              
33             has type_map => qw/ is ro lazy_build 1 /;
34             sub _build_type_map {
35 2     2   6 my $self = shift;
36 2         1246 require DBIx::NoSQL::TypeMap;
37 2         21 return DBIx::NoSQL::TypeMap->new();
38             }
39              
40             sub model {
41 74     74 0 649268 my $self = shift;
42 74 50       274 die "Missing model name" unless @_;
43 74 50       262 if ( @_ > 1 ) {
44 0         0 $self->model( $_ ) for @_;
45             }
46             else {
47 74 50       289 my $name = shift or die "Missing model name";
48              
49 74   66     3051 return $self->_model->{ $name } ||= DBIx::NoSQL::Model->new( store => $self, name => $name );
50             }
51             }
52              
53             sub model_exists {
54 0     0 0 0 my $self = shift;
55 0         0 my $name = shift;
56 0 0       0 die "Missing model name" unless defined $name;
57 0 0       0 return $self->_model->{ $name } ? 1 : 0;
58             }
59              
60             sub validate {
61 0     0 0 0 my $self = shift;
62 0         0 my %options = @_;
63              
64 0   0     0 exists $options{ $_ } or $options{ $_ } = 1 for qw/ fatal /;
65              
66 0         0 my $valid = 1;
67 0         0 for my $model ( values %{ $self->_model } ) {
  0         0  
68 0 0       0 next unless $model->searchable;
69 0         0 my $index = $model->index;
70 0 0       0 next unless $index->exists;
71 0         0 $valid = $index->same;
72 0 0 0     0 if ( ! $valid && $options{ fatal } ) {
73 0         0 my $name = $model->name;
74 0         0 die "Model \"$model\" has invalid index (schema mismatch)";
75             }
76             }
77             }
78              
79             sub reindex {
80 1     1 0 2 my $self = shift;
81              
82 1         1 for my $model ( values %{ $self->_model } ) {
  1         24  
83 2 100       46 next unless $model->searchable;
84 1         4 my $index = $model->index;
85 1         5 $index->reset;
86 1 50       5 next unless $index->exists;
87 1 50       114 next if $index->same;
88 1         4 $index->reindex;
89             }
90             }
91              
92             sub _model_do {
93 40     40   86 my $self = shift;
94 40 50       167 my $name = shift or die "Missing model name";
95 40 50       140 my $operation = shift or die "Missing model operation";
96              
97 40         199 my $model = $self->model( $name );
98 40         3612 return $model->$operation( @_ );
99             }
100              
101             sub search {
102 16     16 0 10349 return shift->_model_do( shift, 'search', @_ );
103             }
104              
105             sub set {
106 8     8 0 44023 return shift->_model_do( shift, 'set', @_ );
107             }
108              
109             sub get {
110 5     5 0 148466 return shift->_model_do( shift, 'get', @_ );
111             }
112              
113             sub delete {
114 1     1 0 630 return shift->_model_do( shift, 'delete', @_ );
115             }
116              
117             sub exists {
118 10     10 0 18785 return shift->_model_do( shift, 'exists', @_ );
119             }
120              
121             has stash => qw/ is ro lazy_build 1 /;
122             sub _build_stash {
123 9     9   4826 require DBIx::NoSQL::Stash;
124 9         27 my $self = shift;
125 9         76 my $stash = DBIx::NoSQL::Stash->new( store => $self );
126 9         3661 return $stash;
127             }
128              
129             require DBIx::NoSQL::ClassScaffold;
130              
131             has schema_class_scaffold => qw/ is ro lazy_build 1 /;
132 9     9   85 sub _build_schema_class_scaffold { return DBIx::NoSQL::ClassScaffold->new->become_Schema }
133             has schema_class => qw/ is ro lazy_build 1 /;
134             sub _build_schema_class {
135 9     9   12 my $self = shift;
136 9         272 my $class = $self->schema_class_scaffold->package;
137              
138 9         40 my $store_result_class_scaffold = DBIx::NoSQL::ClassScaffold->new->become_ResultClass_Store;
139 9         311 my $store_result_class = $store_result_class_scaffold->package;
140 9         85 $store_result_class->register( $class, $store_result_class->table );
141              
142 9         3437 return $class;
143             }
144              
145             has schema => qw/ accessor _schema lazy_build 1 predicate _has_schema /;
146             sub _build_schema {
147 2     2   3 my $self = shift;
148              
149 2         44 my $connection = $self->connection;
150 2 50       5 if ( ! $connection ) {
151 2         47 my $database = $self->database;
152 2 50       10 if ( ! $database ) {
153 0         0 die "Unable to connect schema to database because no connection or database are defined";
154             }
155 2         10 $connection = $database;
156             }
157              
158 2         6 my $schema = $self->_connect( $connection );
159 2         83 return $schema;
160             }
161              
162             sub schema {
163 121     121 0 246 my $self = shift;
164 121         3452 return $self->_schema( @_ );
165             }
166              
167             sub connect {
168 13     13 0 10367 my $self = shift;
169 13 100       61 if ( ! blessed $self ) {
170 6         76 return $self->new->connect( @_ );
171             }
172              
173 7 50       196 $self->clear_schema if $self->_has_schema;
174 7         33 my $schema = $self->_connect( @_ );
175 7         61 return $self;
176             }
177              
178             sub _is_likely_file_connection {
179 15     15   1166 my $self = shift;
180 15         20 my $connection = shift;
181              
182 15 100 100     247 if ( ref $connection eq 'ARRAY' ) { return 0 }
  1 100 66     5  
    100          
    50          
183 1         4 elsif ( ref $connection eq '' && $connection =~ m/^dbi:/i ) { return 0 }
184 9         36 elsif ( blessed $connection && $connection->isa( 'Path::Class::File' ) ) { return 1 }
185 4         15 elsif ( ref $connection eq '' ) { return 1 }
186              
187 0         0 warn ref $connection;
188 0         0 warn $connection;
189              
190 0         0 return 0; # Not sure, pass through to DBI I guess
191             }
192              
193             sub _connect {
194 9     9   17 my $self = shift;
195 9         18 my $connection = shift;
196              
197 9         14 my $database_file;
198 9 50       27 if ( $self->_is_likely_file_connection( $connection ) ) {
199 9         46 $connection = file "$connection";
200 9         911 $database_file = $connection;
201 9         33 $database_file->parent->mkpath; # TODO Make this optional?
202 9         602 $connection = "dbi:SQLite:dbname=$database_file";
203             }
204              
205 9 50       280 $connection = [ $connection ] unless ref $connection eq 'ARRAY';
206 9         271 my $schema = $self->schema_class->connect( @$connection );
207 9         485919 $schema->store( $self );
208              
209             # FIXME This kind of sucks, and potentially a little redundant, see _build_schema
210 9         37 $self->schema( $schema );
211 9 100       209 if ( ! $self->storage->table_exists( '__Store__' ) ) {
212 8         1203 $schema->deploy;
213             }
214              
215 9         483 return $schema;
216             }
217              
218             has dbh => qw/ is ro lazy_build 1 weak_ref 1 /;
219             sub _build_dbh {
220 1     1   3 my $self = shift;
221 1         4 return $self->schema->storage->dbh;
222             }
223              
224             sub transact {
225 0     0 0   my $self = shift;
226 0           my $code = shift;
227              
228 0           my $dbh = $self->dbh;
229             try {
230 0     0     $dbh->begin_work;
231 0           $code->();
232 0           $dbh->commit;
233             }
234             catch {
235 0     0     my $error = $_[0];
236             try {
237 0           $dbh->rollback;
238             }
239 0           die $error;
240             }
241 0           }
242              
243             1;
244              
245             __END__
246              
247             =pod
248              
249             =encoding UTF-8
250              
251             =head1 NAME
252              
253             DBIx::NoSQL::Store
254              
255             =head1 VERSION
256              
257             version 0.0021
258              
259             =head1 AUTHORS
260              
261             =over 4
262              
263             =item *
264              
265             Robert Krimen <robertkrimen@gmail.com>
266              
267             =item *
268              
269             Yanick Champoux <yanick@cpan.org>
270              
271             =back
272              
273             =head1 COPYRIGHT AND LICENSE
274              
275             This software is copyright (c) 2017 by Robert Krimen.
276              
277             This is free software; you can redistribute it and/or modify it under
278             the same terms as the Perl 5 programming language system itself.
279              
280             =cut