File Coverage

blib/lib/Objects/Collection/Mirror.pm
Criterion Covered Total %
statement 21 21 100.0
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 28 28 100.0


line stmt bran cond sub pod time code
1             package Objects::Collection::Mirror;
2              
3             =head1 NAME
4              
5             Objects::Collection::Mirror - Mirror of two collections.
6              
7             =head1 SYNOPSIS
8              
9             use Objects::Collection::Mirror;
10             my $coll1 = ( new Collection::Mem:: mem => \%h1 );# fast but nonstable source ( Memcached )
11             my $coll2 = ( new Collection::Mem:: mem => \%h2 );# slow but stable source ( database )
12              
13             my $mirror_coll1 = new Objects::Collection::Mirror:: $coll1, $coll2 ;
14              
15              
16             =head1 DESCRIPTION
17              
18             Mirror two collections.
19              
20            
21             =cut
22              
23 1     1   56175 use strict;
  1         2  
  1         45  
24 1     1   5 use warnings;
  1         2  
  1         30  
25 1     1   4 use strict;
  1         6  
  1         22  
26 1     1   5 use Carp;
  1         1  
  1         67  
27 1     1   4 use Data::Dumper;
  1         2  
  1         34  
28 1     1   5 use Test::More;
  1         1  
  1         6  
29             require Tie::Hash;
30 1     1   899 use Objects::Collection;
  1         3  
  1         611  
31             @Objects::Collection::Mirror::ISA = qw(Objects::Collection);
32             $Objects::Collection::Mirror::VERSION = '0.01';
33              
34             __PACKAGE__->attributes qw( _c1 _c2 _stack);
35              
36             sub Init {
37             my ( $self, $c1, $c2 ) = @_;
38             _c1 $self $c1;
39             _c2 $self $c2;
40             $self->_stack( [ $c1, $c2 ] );
41             return 1;
42             }
43              
44             sub _init {
45             my $self = shift;
46             $self->SUPER::_init(@_);
47             return $self->Init(@_);
48             }
49              
50             =head2 _fetch
51              
52             Fetch keys from collection1. And then from collection2
53              
54             =cut
55              
56             sub _fetch {
57             my $self = shift;
58              
59             #collect ids to fetch
60             my @ids = map { $_->{id} } @_;
61             return {} unless @ids; #skip empty ids list
62             my ( $c1, $c2 ) = @{ $self->_stack };
63              
64             #read keys from first collection
65             my $res1 = $c1->fetch_objects(@_);
66             my @notfound = ();
67             foreach my $key (@ids) {
68             push @notfound, $key unless exists $res1->{$key};
69             }
70             if (@notfound) {
71              
72             #if we not found some keys, then fetch from coll2
73             #and store to coll1
74             # diag "Fetch non exists in col1".Dumper (\@notfound);
75             my $res2 = $c2->fetch_objects(@notfound);
76             my %create_keys = ();
77             foreach my $k1 (@notfound) {
78             next unless exists $res2->{$k1}; #skip real nonexists keys
79             my $value = $res2->{$k1};
80              
81             #save for create
82             $create_keys{$k1} = $value;
83             }
84             if ( keys %create_keys ) {
85              
86             # diag "create". Dumper (\%create_keys);
87             #store only simply results
88             #now store to coll1
89             my $created = $c1->create( \%create_keys );
90             while ( my ( $k2, $v2 ) = each %$created ) {
91             $res1->{$k2} = $v2;
92             }
93             }
94             }
95              
96             # diag "try " . Dumper( \@_ );
97             # diag "Diff two keys" . Dumper [ \@keys1, \@keys2 ];
98             return $res1;
99             }
100              
101             =head2 _create
102              
103             create items
104              
105             =cut
106              
107             sub _create {
108             my $self = shift;
109             my ( $c1, $c2 ) = @{ $self->_stack };
110             return $c2->create(@_);
111             }
112              
113             =head2 _store
114              
115             =cut
116              
117             sub _store {
118             my $self = shift;
119             my ( $c1, $c2 ) = @{ $self->_stack };
120             my $hash2store = shift;
121             my @ids2store = keys %$hash2store;
122             my $coll2res = $c2->fetch_objects(@ids2store);
123              
124             #and create new in col2
125             #create non exists keys on c2
126             my %tocreate = ();
127             while ( my ( $key, $val ) = each %$hash2store ) {
128             if ( exists $coll2res->{$key} ) {
129             my $value = $coll2res->{$key};
130              
131             #mirror only HASHes
132             if ( ref($value) eq 'HASH' ) {
133              
134             #use value as hash
135             %$value = %$val;
136             }
137             }
138             else {
139             $tocreate{$key} = $val;
140             }
141             }
142             if ( keys %tocreate ) {
143             $c2->create( \%tocreate );
144             }
145              
146             #now mirroring changed data
147             #mirror coll1 to coll2
148             while ( my ( $key, $val ) = each %$hash2store ) {
149             next unless exists $coll2res->{$key};
150              
151             }
152             # changed items we also mirror to coll2
153             $c1->store_changed(@ids2store);
154             $c2->store_changed(@ids2store);
155             return;
156             }
157              
158             =head2 list_ids
159              
160             Return union of keys from collection1 and collection2
161              
162             =cut
163              
164             sub list_ids {
165             my $self = shift;
166             my ( $c1, $c2 ) = @{ $self->_stack };
167             my %uniq = ();
168             @uniq{ @{ $c1->list_ids }, @{ $c2->list_ids } } = ();
169             return [ keys %uniq ];
170             }
171              
172             sub _delete {
173             my $self = shift;
174             my ( $c1, $c2 ) = @{ $self->_stack };
175             for ( $c1, $c2 ) {
176             $_->delete_objects(@_)
177             }
178             }
179             1;
180             __END__