File Coverage

blib/lib/DBIx/NoSQL/Model/Index.pm
Criterion Covered Total %
statement 119 125 95.2
branch 26 34 76.4
condition 3 5 60.0
subroutine 24 25 96.0
pod 0 15 0.0
total 172 204 84.3


line stmt bran cond sub pod time code
1             package DBIx::NoSQL::Model::Index;
2             our $AUTHORITY = 'cpan:YANICK';
3             $DBIx::NoSQL::Model::Index::VERSION = '0.0021';
4 7     7   32 use strict;
  7         12  
  7         240  
5 7     7   32 use warnings;
  7         11  
  7         252  
6              
7 7     7   30 use Moose;
  7         13  
  7         64  
8 7     7   41067 use Clone qw/ clone /;
  7         13  
  7         522  
9 7     7   39 use Digest::SHA qw/ sha1_hex /;
  7         11  
  7         347  
10 7     7   4080 use DBIx::NoSQL::Search;
  7         24  
  7         8904  
11              
12             has model => qw/ is ro required 1 weak_ref 1 /, handles => [qw/ store storage /];
13              
14             has prepared => qw/ is rw isa Bool default 0 /;
15              
16             has key_column => qw/ is rw isa Str lazy_build 1 /;
17 11     11   290 sub _build_key_column { 'key' }
18              
19             has [qw/ create_statement drop_statement schema_digest /] => qw/ is rw isa Maybe[Str] /;
20              
21             has result_class_scaffold => qw/ is ro lazy_build 1 /;
22 11     11   110 sub _build_result_class_scaffold { return DBIx::NoSQL::ClassScaffold->new->become_ResultClass }
23             has result_class => qw/ is ro lazy_build 1 /;
24 11     11   283 sub _build_result_class { return shift->result_class_scaffold->package }
25              
26             sub search {
27 16     16 0 29 my $self = shift;
28              
29 16         58 $self->prepare;
30              
31 16         404 my $search = DBIx::NoSQL::Search->new( model => $self->model );
32              
33 16 100       13218 if ( @_ ) {
34 7         163 $search->_where( $_[0] );
35             }
36              
37 16         96 return $search;
38             }
39              
40             sub update {
41 26     26 0 185 my $self = shift;
42 26         55 my $key = shift;
43 26         47 my $target = shift;
44              
45 26         118 $self->prepare;
46              
47 26         811 my $model = $self->model;
48              
49 26         54 my $data = $target;
50 26 100 66     222 if ( $data && ! ref $data ) {
51 8         58 $data = $model->deserialize( $target );
52             }
53              
54 26         58 my %set;
55 26         775 $set{ $self->key_column } = $key;
56 26         54 while( my ( $field, $column ) = each %{ $model->_field2column_map } ) {
  51         1332  
57 25         70 $set{ $column } = $data->{ $field };
58             }
59              
60 26         163 $self->store->schema->resultset( $self->model->name )->update_or_create(
61             \%set, { key => 'primary' },
62             );
63             }
64              
65             sub delete {
66 1     1 0 4 my $self = shift;
67 1         2 my $key = shift;
68              
69 1         5 $self->prepare;
70              
71 1         9 my $result = $self->store->schema->resultset( $self->model->name )->find(
72             { $self->key_column => $key },
73             { key => 'primary' }
74             );
75 1 50       2380 if ( $result ) {
76 1         24 $result->delete;
77             }
78             }
79              
80             sub prepare {
81 43     43 0 78 my $self = shift;
82              
83 43 100       1713 return if $self->prepared;
84              
85 12         45 $self->register_result_class;
86              
87 12 100       47 if ( ! $self->exists ) {
    100          
88 10         1188 $self->deploy;
89             }
90             elsif ( ! $self->same ) {
91 1         1 if ( 1 ) {
92 1         4 $self->redeploy;
93             }
94             else {
95             my $model = $self->model->name;
96             die "Unable to prepare index for model ($model) because index already exists (and is different)";
97             }
98             }
99              
100 12         437 $self->prepared( 1 );
101             }
102              
103             sub register_result_class {
104 17     17 0 26 my $self = shift;
105              
106 17         425 my $model = $self->model;
107 17         112 my $store = $self->store;
108 17         93 my $schema = $store->schema;
109 17         396 my $name = $self->model->name;
110 17         422 my $result_class = $self->result_class;
111              
112 17 100       345 $schema->unregister_source( $name ) if $schema->source_registrations->{ $name };
113              
114             {
115 17 100       1390 unless ( $result_class->can( 'result_source_instance' ) ) {
  17         918  
116 11         169 $result_class->table( $name );
117             }
118              
119 17         5163 my $key_column = $self->key_column;
120 17 100       529 unless( $result_class->has_column( $key_column ) ) {
121 11         3779 $result_class->add_column( $key_column => {
122             data_type => 'text'
123             } );
124             }
125 17 100       4812 unless( $result_class->primary_columns ) {
126 11         3029 $result_class->set_primary_key( $key_column );
127             }
128              
129 17         1167 for my $field ( values %{ $model->field_map } ) {
  17         448  
130 29 50       3490 next unless $field->index;
131 29 100       614 unless( $result_class->has_column( $field->name ) ) {
132 14         445 $field->install_index( $model, $result_class );
133             }
134             }
135             }
136              
137 17         4140 $schema->register_class( $name => $result_class );
138              
139 17         5530 my $table = $result_class->table;
140 17         551 my $deployment_statements = $schema->build_deployment_statements;
141 17         170 my @deployment_statements = split m/;\n/, $deployment_statements;
142 17         44 my ( $create ) = grep { m/(?:(?i)CREATE\s+TABLE\s+.*)$table/ } @deployment_statements;
  108         573  
143 17         41 my ( $drop ) = grep { m/(?:(?i)DROP\s+TABLE\s+.*)$table/ } @deployment_statements;
  108         315  
144              
145 17         313 s/^\s*//, s/\s*$// for $create, $drop;
146              
147 17         621 $self->create_statement( $create );
148 17         506 $self->drop_statement( $drop );
149 17         713 $self->schema_digest( sha1_hex $create );
150             }
151              
152             sub stash_schema_digest {
153 17     17 0 35 my $self = shift;
154 17         536 my $model = $self->model->name;
155 17         125 return $self->store->stash->value( "model.$model.index.schema_digest", @_ );
156             }
157              
158             sub exists {
159 23     23 0 37 my $self = shift;
160              
161 23         97 return $self->storage->table_exists( $self->model->name );
162             }
163              
164             sub same {
165 3     3 0 230 my $self = shift;
166              
167 3 50       12 return unless my $stash_schema_digest = $self->stash_schema_digest;
168 3 50       98 return unless my $schema_digest = $self->schema_digest;
169 3         16 return $schema_digest eq $stash_schema_digest;
170             }
171              
172             sub deploy {
173 10     10 0 16 my $self = shift;
174              
175 10 50       29 if ( $self->exists ) {
176 0 0       0 if ( $self->same ) {
177 0         0 return;
178             }
179             else {
180 0         0 my $model = $self->model->name;
181 0         0 warn "Index schema mismatch for model ($model)";
182 0         0 return;
183             }
184             }
185              
186 10         1080 $self->_deploy;
187             }
188              
189             sub _deploy {
190 14     14   25 my $self = shift;
191 14         107 $self->store->storage->do( $self->create_statement );
192 14         516 $self->stash_schema_digest( $self->schema_digest );
193             }
194              
195             sub undeploy {
196 4     4 0 12 my $self = shift;
197 4         30 $self->store->storage->do( $self->drop_statement );
198             }
199              
200             sub redeploy {
201 4     4 0 174 my $self = shift;
202 4         10 my %options = @_;
203              
204 4   50     23 exists $options{ $_ } or $options{ $_ } = 1 for qw/ register /;
205              
206 4 50       24 $self->register_result_class if $options{ register };
207 4         53 $self->undeploy;
208 4         34 $self->_deploy;
209 4         30 $self->reload;
210 4         348353 $self->prepared( 1 );
211             }
212              
213             sub reload {
214 4     4 0 12 my $self = shift;
215              
216 4         154 my @result = $self->model->_store_set->search( { __model__ => $self->model->name } )->all;
217 4         21379 for my $result ( @result ) {
218 8         1483810 $self->update( $result->get_column( '__key__' ), $result->get_column( '__value__' ) );
219             }
220             }
221              
222             sub reset {
223 1     1 0 3 my $self = shift;
224 1         5 $self->register_result_class;
225             }
226              
227 3     3 0 14 sub reindex { return shift->redeploy( @_ ) }
228 0     0 0   sub migrate { return shift->redeploy( @_ ) }
229              
230             1;
231              
232             __END__
233              
234             =pod
235              
236             =encoding UTF-8
237              
238             =head1 NAME
239              
240             DBIx::NoSQL::Model::Index
241              
242             =head1 VERSION
243              
244             version 0.0021
245              
246             =head1 AUTHORS
247              
248             =over 4
249              
250             =item *
251              
252             Robert Krimen <robertkrimen@gmail.com>
253              
254             =item *
255              
256             Yanick Champoux <yanick@cpan.org>
257              
258             =back
259              
260             =head1 COPYRIGHT AND LICENSE
261              
262             This software is copyright (c) 2017 by Robert Krimen.
263              
264             This is free software; you can redistribute it and/or modify it under
265             the same terms as the Perl 5 programming language system itself.
266              
267             =cut