File Coverage

blib/lib/Class/DBI/DataMigration/Synchronizer.pm
Criterion Covered Total %
statement 31 50 62.0
branch 0 10 0.0
condition 0 3 0.0
subroutine 8 10 80.0
pod 2 2 100.0
total 41 75 54.6


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2              
3             =head1 Name
4              
5             Class::DBI::DataMigration::Synchronizer
6              
7             =head1 Synopsis
8              
9             use Class::DBI::DataMigration::Synchronizer;
10              
11             my $synch = Class::DBI::DataMigration::Synchronizer->new(
12             search_criteria => \%search_criteria);
13             my $synched_objects = $synch->synchronize;
14              
15             =head1 Description
16              
17             Class::DBI::DataMigration::Synchronizer - Keep records synchronized between
18             source and target databases.
19              
20             =for testing
21             use_ok('Class::DBI::DataMigration::Synchronizer');
22              
23             =cut
24              
25 1     1   1096 use strict;
  1         1  
  1         54  
26              
27             package Class::DBI::DataMigration::Synchronizer;
28              
29 1     1   6 use base qw/Class::Accessor Class::Data::Inheritable/;
  1         2  
  1         978  
30 1     1   5166 use Class::DBI::DataMigration::Migrator;
  1         4  
  1         11  
31 1     1   40 use Carp;
  1         1  
  1         61  
32 1     1   6 use Carp::Assert;
  1         2  
  1         5  
33              
34 1     1   2552 use Getopt::Long;
  1         25030  
  1         7  
35              
36             __PACKAGE__->mk_classdata('_criteria_args');
37             __PACKAGE__->mk_classdata('config_path');
38             __PACKAGE__->config_path('./');
39              
40             sub _initialize {
41 2     2   1752 my $class = shift;
42 2         7 $class->_criteria_args([]);
43 2         112 GetOptions("table=s" => $class->_criteria_args);
44 2         636 1;
45             }
46              
47             __PACKAGE__->_initialize;
48              
49              
50             =head1 Methods
51              
52             =head2 config_path
53              
54             Class accessor/mutator for the directory in which our config.yaml can be found.
55             This config.yaml will be used to build a C,
56             which we will then use to synchronize the appropriate data. Defaults to './'.
57              
58             =head2 search_criteria
59              
60             Accessor/mutator for a hashref of hashes of search criteria to use, per table,
61             to locate objects for migration between the source and target databases.
62              
63             The hash should be keyed on source db CDBI class names, with hashrefs of
64             key/value pairs to search for in each class as values; these latter key/value
65             hashes will be used to search() each class. Classes whose values are empty
66             hashes will have retrieve_all() called on them -- that is, *all* objects in
67             that class will be migrated. For example:
68              
69             {
70             SourceClass1 => {
71             key1 => value1,
72             key2 => value2
73             }, # migrate objects in SourceClass1 that match
74             # key1 => value1, key2 => value2
75              
76             SourceClass2 => {} # migrate all objects in SourceClass2
77             }
78              
79             =for testing
80             can_ok('Class::DBI::DataMigration::Synchronizer', 'search_criteria');
81              
82             =cut
83              
84             __PACKAGE__->mk_accessors(
85             qw/search_criteria/
86             );
87              
88             =head2 new
89              
90             This constructor uses Getopt::Long to parse command-line arguments, producing a
91             search_criteria hash suitable for use at synchronize() time.
92              
93             --table=class1,key1,value1,key2,value2... --table=class2,key3,value3... --table=class3...
94              
95             The keys and values supplied for each --table argument will be used to search()
96             the given class for objects to be migrated. If no keys/values are given, *all*
97             objects in the class (i.e., all rows in the table) will be migrated. So, in the
98             example above, the search_criteria hashref produced would be:
99              
100             {
101             class1 => {
102             key1 => value1,
103             key2 => value2
104             },
105              
106             class2 => {
107             key3 => value3
108             },
109              
110             class3 => {}
111             }
112              
113             Class/key/value lists must contain no spaces and be separated by commas, as in
114             the example above.
115              
116             =begin testing
117              
118             push @ARGV, '--table=class1,key1,value1,key2,value2',
119             '--table=class2,key3,value3', '--table=class3';
120              
121             ok(Class::DBI::DataMigration::Synchronizer->_initialize);
122              
123             my $synch = Class::DBI::DataMigration::Synchronizer->new;
124             is_deeply($synch->search_criteria,
125             {
126             class1 => {
127             key1 => 'value1',
128             key2 => 'value2'
129             },
130              
131             class2 => {
132             key3 => 'value3'
133             },
134              
135             class3 => {}
136             }
137             );
138              
139             =end testing
140              
141             =cut
142              
143             sub new {
144 1     1 1 3 my $class = shift;
145 1         2 my $self = {};
146 1         5 bless $self, $class;
147 1         4 $self->search_criteria({});
148 1         126 foreach(@{$class->_criteria_args}) {
  1         6  
149 3         46 my ($class, %criteria) = split /,/;
150 3         13 $self->search_criteria->{$class} = \%criteria;
151             }
152              
153 1         12 return $self;
154             }
155              
156             =head2 synchronize
157              
158             Collect together all objects from the various CDBI classes matching our
159             search_criteria; build a migrator for our class's config.yaml file and
160             migrate the objects we've collected.
161              
162             NB: our config.yaml file is expected to be found in config_path(), which defaults to ./.
163              
164             =cut
165              
166             sub synchronize {
167 0     0 1   my ($self) = @_;
168 0   0       my $class = ref($self) || $self;
169              
170 0           my @source_objects = $self->_collect_source_objects();
171              
172 0 0         open IN, ($class->config_path . 'config.yaml') or
173             confess "Couldn't open yaml config for data migration: $!";
174 0           my $migrator = new Class::DBI::DataMigration::Migrator(join '', );
175 0           return $migrator->migrate_objects(\@source_objects);
176             }
177              
178             sub _collect_source_objects {
179 0     0     my ($self) = @_;
180 0 0         return unless $self->search_criteria;
181 0           Carp::Assert::should(ref $self->search_criteria, 'HASH');
182 0           my @results;
183 0           while (my ($class, $criteria) = each %{$self->search_criteria}) {
  0            
184 0 0         eval "require $class" unless $class->can('new');
185 0 0         confess $@ if $@;
186 0           Carp::Assert::should(ref $criteria, 'HASH');
187 0 0         if (scalar(keys(%$criteria))) {
188 0           push @results, $class->search(%$criteria);
189             } else {
190 0           @results = $class->retrieve_all;
191             }
192             }
193 0           return @results;
194             }
195              
196             =head1 Author
197              
198             Dan Friedman, C<< >>
199              
200             =head1 Copyright & License
201              
202             Copyright 2004 Dan Friedman, All Rights Reserved.
203              
204             This program is free software; you can redistribute it and/or modify it
205             under the same terms as Perl itself.
206              
207             Please note that these modules are not products of or supported by the
208             employers of the various contributors to the code.
209              
210             =cut
211              
212             1;