File Coverage

blib/lib/KiokuDB/Set/Deferred.pm
Criterion Covered Total %
statement 15 75 20.0
branch 0 28 0.0
condition 0 3 0.0
subroutine 5 16 31.2
pod 0 6 0.0
total 20 128 15.6


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             package KiokuDB::Set::Deferred;
4 12     12   54 use Moose;
  12         19  
  12         75  
5              
6 12     12   62036 use Carp qw(croak);
  12         23  
  12         708  
7              
8 12     12   5422 use KiokuDB::Set::Loaded;
  12         36  
  12         557  
9              
10 12     12   94 use Scalar::Util qw(refaddr);
  12         19  
  12         754  
11              
12 12     12   62 use namespace::clean -except => 'meta';
  12         19  
  12         88  
13              
14             with qw(KiokuDB::Set::Storage) => { excludes => '_apply' };
15              
16             extends qw(KiokuDB::Set::Base);
17              
18             has _linker => (
19             isa => "KiokuDB::Linker",
20             is => "ro",
21             required => 1,
22             clearer => "_clear_linker",
23             );
24              
25             has _live_objects => (
26             isa => "KiokuDB::LiveObjects",
27             is => "ro",
28             lazy_build => 1,
29             clearer => "_clear_live_objects",
30             );
31              
32             sub _build__live_objects {
33 0     0     my $self = shift;
34 0           $self->_linker->live_objects;
35             }
36              
37             has _live_object_scope => (
38             isa => "KiokuDB::LiveObjects::Scope",
39             is => "rw",
40             weak_ref => 1,
41             clearer => "_clear_live_object_scope",
42             );
43              
44             sub BUILD {
45 0     0 0   my $self = shift;
46             # can't use lazy build because it doesn't work with weak_ref
47             # at any rate we need to capture the current scope at begin time
48 0           $self->_live_object_scope( $self->_live_objects->current_scope );
49             }
50              
51 0     0 0   sub loaded { shift->size == 0 }
52              
53             sub includes {
54 0     0 0   my ( $self, @members ) = @_;
55              
56 0 0         return 1 unless @members;
57              
58 0 0         return unless $self->size;
59              
60 0           my @ids = grep { defined } $self->_live_objects->objects_to_ids(@members);
  0            
61              
62 0 0         if ( @ids == @members ) {
63             # all objects have IDs, so we check
64 0           return $self->_objects->includes(@ids);
65             }
66              
67             # if they didn't have IDs thenn they are not in storage, and hence not part of the set
68 0           return;
69             }
70              
71             sub remove {
72 0     0 0   my ( $self, @members ) = @_;
73              
74 0 0 0       return 0 unless $self->size or @members;
75              
76 0           my @ids = grep { defined } $self->_live_objects->objects_to_ids(@members);
  0            
77              
78 0           return $self->_objects->remove(@ids);
79             }
80              
81             sub insert {
82 0     0 0   my ( $self, @members ) = @_;
83              
84 0 0         return unless @members;
85              
86 0 0         croak "Can't insert non reference into a KiokuDB::Set" if grep { not ref } @members;
  0            
87              
88 0           my @ids = grep { defined } $self->_live_objects->objects_to_ids(@members);
  0            
89              
90 0 0         if ( @ids == @members ) {
91 0 0         if ( my $scope = $self->_live_object_scope ) {
92 0           $scope->push(@members); # keep them around at least as long as us
93             }
94              
95             # all objects have IDs, no need to load anything
96 0           return $self->_objects->insert(@ids);
97             } else {
98 0           $self->_load_all;
99 0           return $self->insert(@members);
100             }
101             }
102              
103             sub members {
104 0     0 0   my $self = shift;
105              
106 0 0         return unless $self->size;
107              
108 0           $self->_load_all();
109 0           $self->members;
110             }
111              
112             sub _load_all {
113 0     0     my $self = shift;
114              
115             # load all the IDs
116 0           my @objects = $self->_linker->get_or_load_objects($self->_objects->members);
117              
118             # push all the objects to the set's scope so that they live at least as long as it
119 0           my $scope = $self->_live_object_scope;
120 0 0         unless ( $scope ) {
121 0 0         if ( my $current_scope = $self->_live_objects->current_scope ) {
122 0           $scope = $current_scope;
123 0           $self->_live_object_scope($scope);
124             } else {
125 0           croak "Can't vivify set, originating object scope is already dead";
126             }
127             }
128 0           $scope->push( @objects );
129              
130             # replace the ID set with the object set
131 0           $self->_set_objects( Set::Object::Weak->new(@objects) );
132              
133             # and swap in loaded behavior
134 0           bless $self, "KiokuDB::Set::Loaded";
135             }
136              
137             sub _all_deferred {
138 0     0     my ( $self, @sets ) = @_;
139              
140 0           my $my_linker = refaddr($self->_linker);
141              
142 0           foreach my $set ( @sets ) {
143 0 0         return unless $set->isa(__PACKAGE__);
144 0 0         return unless refaddr($set->_linker) == $my_linker;
145             }
146              
147 0           return 1;
148             }
149              
150             sub _apply {
151 0     0     my ( $self, $method, @sets ) = @_;
152              
153 0 0         if ( $self->_all_deferred(@sets) ) {
154             # working in terms of IDs is OK
155 0           my $res = $self->_objects->$method(map { $_->_objects } @sets);
  0            
156 0           return $self->meta->clone_object( $self, set => $res );
157             } else {
158 0           $self->_load_all;
159 0           return $self->$method(@sets);
160             }
161             }
162              
163             sub _set_ids {
164 0     0     my ( $self, $id_set ) = @_;
165              
166             # replace the object set with the ID set
167 0           $self->_set_objects( $id_set );
168             }
169              
170             __PACKAGE__->meta->make_immutable;
171              
172             __PACKAGE__
173              
174             __END__
175              
176             =pod
177              
178             =head1 NAME
179              
180             KiokuDB::Set::Deferred - Implementation of deferred set.
181              
182             =head1 SYNOPSIS
183              
184             # created automatically when sets are loaded from the database
185              
186             =head1 DESCRIPTION
187              
188             This class implements deferred sets conforming to the L<KiokuDB::Set> API.
189              
190             Do not use this class directly, instead use L<KiokuDB::Set::Transient> or
191             L<KiokuDB::Util/set> to create sets.
192              
193             =cut
194