File Coverage

blib/lib/DBIx/Class/KiokuDB.pm
Criterion Covered Total %
statement 93 97 95.8
branch 22 36 61.1
condition 3 3 100.0
subroutine 18 18 100.0
pod 8 8 100.0
total 144 162 88.8


line stmt bran cond sub pod time code
1             package DBIx::Class::KiokuDB;
2             BEGIN {
3 2     2   1285 $DBIx::Class::KiokuDB::AUTHORITY = 'cpan:NUFFIN';
4             }
5             # ABSTRACT: Refer to KiokuDB objects from DBIx::Class tables.
6             $DBIx::Class::KiokuDB::VERSION = '1.23';
7 2     2   15 use strict;
  2         5  
  2         48  
8 2     2   12 use warnings;
  2         3  
  2         55  
9              
10 2     2   12 use Carp;
  2         5  
  2         136  
11 2     2   14 use Scalar::Util qw(weaken);
  2         4  
  2         97  
12              
13 2     2   15 use namespace::clean;
  2         5  
  2         19  
14              
15 2     2   678 use base qw(DBIx::Class::Core);
  2         5  
  2         2194  
16              
17             sub new {
18 4     4 1 5341 my $self = shift->next::method(@_);
19              
20 4         666 foreach my $key ( $self->result_source->columns ) {
21 12         296 my $col_info = $self->column_info($key);
22              
23 12 100 100     673 if ( $col_info->{_kiokudb_info} and ref( my $obj = $self->get_column($key) ) ) {
24 3         54 $self->store_kiokudb_column( $key => $obj );
25             }
26             }
27              
28 4         22 return $self;
29             }
30              
31             sub insert {
32 4     4 1 93 my ( $self, @args ) = @_;
33              
34 4         13 my $schema = $self->result_source->schema;
35              
36 4         66 my $g = $schema->txn_scope_guard;
37              
38 4         1143 my $dir = $schema->kiokudb_handle;
39 4         91 my $lo = $dir->live_objects;
40              
41 4 50       31 if ( my @insert = grep { ref and not $lo->object_to_entry($_) } values %{ $self->{_kiokudb_column} } ) {
  3 100       22  
  4         16  
42 2         166 $dir->insert(@insert);
43             }
44              
45 4         1554 my $ret = $self->next::method(@args);
46              
47 4         6958 $g->commit;
48              
49 4         248 return $ret;
50             }
51              
52             sub update {
53 4     4 1 138 my ( $self, @args ) = @_;
54              
55 4         22 my $dir = $self->result_source->schema->kiokudb_handle;
56 4         140 my $lo = $dir->live_objects;
57              
58 4 50       42 if ( my @insert = grep { ref and not $lo->object_to_entry($_) } values %{ $self->{_kiokudb_column} } ) {
  2 100       17  
  4         20  
59 1         127 croak("Can't update object, related KiokuDB objects are not in storage");
60             }
61              
62 3         86 $self->next::method(@args);
63             }
64              
65             sub store {
66 1     1 1 34 my ( $self, @args ) = @_;
67              
68 1         5 my $schema = $self->result_source->schema;
69              
70 1         13 my $g = $schema->txn_scope_guard;
71              
72 1 50       146 if ( my @objects = grep { ref } values %{ $self->{_kiokudb_column} } ) {
  1         5  
  1         5  
73 1         4 $schema->kiokudb_handle->store(@objects);
74             }
75              
76 1         815 my $ret = $self->insert_or_update;
77              
78 1         2113 $g->commit;
79              
80 1         64 return $ret;
81             }
82              
83             sub kiokudb_column {
84 2     2 1 8672 my ($self, $rel, $cond, $attrs) = @_;
85              
86             # assume a foreign key contraint unless defined otherwise
87             $attrs->{is_foreign_key_constraint} = 1
88 2 50       11 if not exists $attrs->{is_foreign_key_constraint};
89              
90 2 50       7 my $fk = defined $cond ? $cond : $rel;
91              
92 2         30 $self->add_relationship( $rel, 'entries', { 'foreign.id' => "self.$fk" }, $attrs ); # FIXME hardcoded 'entries'
93              
94 2         662 my $col_info = $self->column_info($fk);
95              
96 2         902 $col_info->{_kiokudb_info} = {};
97              
98 2         4 my $accessor = $col_info->{accessor};
99 2 50       10 $accessor = $rel unless defined $accessor;
100              
101 2         20 $self->mk_group_accessors('kiokudb_column' => [ $accessor, $fk]);
102             }
103              
104             sub _kiokudb_id_to_object {
105 5     5   15 my ( $self, $id ) = @_;
106              
107 5 50       20 if ( ref( my $obj = $self->result_source->schema->kiokudb_handle->lookup($id) ) ) {
108 5         12834 return $obj;
109             } else {
110 0 0       0 croak("No object with ID '$id' found") unless ref $obj;
111             }
112             }
113              
114             sub _kiokudb_object_to_id {
115 4     4   10 my ( $self, $object ) = @_;
116              
117 4 50       16 confess unless ref $object;
118              
119 4         15 my $dir = $self->result_source->schema->kiokudb_handle;
120              
121 4 100       22 if ( my $id = $dir->object_to_id($object) ) {
122 1         84 return $id;
123             } else {
124             # generate an ID
125 3         308 my $collapser = $dir->collapser;
126 3         448770 my $id_method = $collapser->id_method(ref $object);
127 3         3305 my $id = $id = $collapser->$id_method($object);
128              
129             # register the ID
130 3         428 $dir->live_objects->insert( $id => $object );
131              
132 3         1050 return $id;
133             }
134             }
135              
136             sub get_kiokudb_column {
137 9     9 1 25060 my ( $self, $col ) = @_;
138              
139             $self->throw_exception("$col is not a KiokuDB column")
140 9 50       178 unless exists $self->column_info($col)->{_kiokudb_info};
141              
142             return $self->{_kiokudb_column}{$col}
143 9 100       610 if defined $self->{_kiokudb_column}{$col};
144              
145 5 50       23 if ( defined( my $val = $self->get_column($col) ) ) {
146 5 50       82 my $obj = ref $val ? $val : $self->_kiokudb_id_to_object($val);
147              
148             # weaken by default, in case there are cycles, the live object scope will
149             # take care of this
150 5         40 weaken( $self->{_kiokudb_column}{$col} = $obj );
151              
152 5         40 return $obj;
153             } else {
154 0         0 return;
155             }
156             }
157              
158             sub _set_kiokudb_column {
159 4     4   15 my ( $self, $method, $col, $obj ) = @_;
160              
161 4 50       16 if ( ref $obj ) {
162 4         19 $self->$method( $col, $self->_kiokudb_object_to_id($obj) );
163 4         277 $self->{_kiokudb_column}{$col} = $obj;
164             } else {
165 0         0 $self->$method( $col, undef );
166 0         0 delete $self->{_kiokudb_column}{$col};
167             }
168              
169 4         15 return $obj;
170             }
171              
172             sub set_kiokudb_column {
173 1     1 1 649 my ( $self, @args ) = @_;
174 1         5 $self->_set_kiokudb_column( set_column => @args );
175             }
176              
177             sub store_kiokudb_column {
178 3     3 1 11 my ( $self, @args ) = @_;
179 3         20 $self->_set_kiokudb_column( store_column => @args );
180             }
181              
182             # ex: set sw=4 et:
183              
184             __PACKAGE__
185              
186             __END__
187              
188             =pod
189              
190             =encoding UTF-8
191              
192             =head1 NAME
193              
194             DBIx::Class::KiokuDB - Refer to KiokuDB objects from DBIx::Class tables.
195              
196             =head1 VERSION
197              
198             version 1.23
199              
200             =head1 SYNOPSIS
201              
202             See L<DBIx::Class::Schema::KiokuDB>.
203              
204             package MyApp::DB::Result::Album;
205             use base qw(DBIx::Class);
206              
207             __PACKAGE__>load_components(qw(Core KiokuDB));
208              
209             __PACKAGE__->table('album');
210              
211             __PACKAGE__->add_columns(
212             id => { data_type => "integer" },
213             title => { data_type => "varchar" },
214              
215             # the foreign key for the KiokuDB object:
216             metadata => { data_type => "varchar" },
217             );
218              
219             __PACKAGE__->set_primary_key('id');
220              
221             # enable a KiokuDB rel on the column:
222             __PACKAGE__->kiokudb_column('metadata');
223              
224             =head1 DESCRIPTION
225              
226             This L<DBIx::Class> component provides the code necessary for
227             L<DBIx::Class::Row> objects to refer to L<KiokuDB> objects stored in
228             L<KiokuDB::Backend::DBI>.
229              
230             =head1 CLASS METHODS
231              
232             =over 4
233              
234             =item kiokudb_column $rel
235              
236             Declares a relationship to any L<KiokuDB> object.
237              
238             In future versions adding relationships to different sub-collections will be
239             possible as well.
240              
241             =back
242              
243             =head1 METHODS
244              
245             =over 4
246              
247             =item store
248              
249             A convenience method that calls L<KiokuDB/store> on all referenced L<KiokuDB>
250             objects, and then invokes C<insert_or_update> on C<$self>.
251              
252             =item get_kiokudb_column $col
253              
254             =item set_kiokudb_column $col, $obj
255              
256             =item store_kiokudb_column $col, $obj
257              
258             See L<DBIx::Class::Row>.
259              
260             =back
261              
262             =head1 OVERRIDDEN METHODS
263              
264             =over 4
265              
266             =item new
267              
268             Recognizes objects passed in as column values, much like standard relationships
269             do.
270              
271             =item insert
272              
273             Also calls L<KiokuDB/insert> on all referenced objects that are not in the
274             L<KiokuDB> storage.
275              
276             =item update
277              
278             Adds a check to ensure that all referenced L<KiokuDB> objects are in storage.
279              
280             =back
281              
282             =head1 AUTHOR
283              
284             Yuval Kogman <nothingmuch@woobling.org>
285              
286             =head1 COPYRIGHT AND LICENSE
287              
288             This software is copyright (c) 2014 by Yuval Kogman, Infinity Interactive.
289              
290             This is free software; you can redistribute it and/or modify it under
291             the same terms as the Perl 5 programming language system itself.
292              
293             =cut