File Coverage

blib/lib/DBIx/Fixture/Admin.pm
Criterion Covered Total %
statement 41 170 24.1
branch 0 34 0.0
condition n/a
subroutine 14 37 37.8
pod 0 9 0.0
total 55 250 22.0


line stmt bran cond sub pod time code
1             package DBIx::Fixture::Admin;
2 1     1   1090 use 5.008001;
  1         4  
3 1     1   7 use strict;
  1         2  
  1         39  
4 1     1   7 use warnings;
  1         12  
  1         53  
5              
6 1     1   788 use DBIx::FixtureLoader;
  1         85917  
  1         54  
7 1     1   1011 use Teng::Schema::Loader;
  1         38566  
  1         56  
8 1     1   12 use File::Basename qw/basename/;
  1         2  
  1         90  
9 1     1   9 use File::Spec;
  1         2  
  1         50  
10 1     1   8 use List::Util qw/any/;
  1         3  
  1         143  
11 1     1   925 use Set::Functional qw/difference intersection/;
  1         3213  
  1         115  
12 1     1   878 use Data::Validator;
  1         43758  
  1         80  
13 1     1   1523 use Text::CSV_XS;
  1         15588  
  1         131  
14 1     1   1417 use Encode qw/encode decode/;
  1         21354  
  1         164  
15 1     1   22 use Try::Tiny;
  1         3  
  1         109  
16              
17             use Class::Accessor::Lite (
18 1         15 new => 1,
19             ro => [ qw(conf dbh) ],
20 1     1   9 );
  1         2  
21              
22             our $VERSION = "0.15";
23              
24             sub load {
25 0     0 0   my $v = Data::Validator->new(
26             tables => +{ isa => 'ArrayRef[Str]' }
27             )->with(qw/Method StrictSequenced/);
28 0           my($self, $args) = $v->validate(@_);
29              
30 0           my @tables = intersection($args->{tables}, [$self->tables]);
31              
32 0 0         return unless scalar @tables;
33              
34 0           for my $table (@tables) {
35             try {
36             $self->_load_fixture(
37             table => $table,
38             fixture_path => $self->conf->{fixture_path},
39 0     0     );
40             }
41             catch {
42 0     0     warn $_;
43 0           };
44             }
45             }
46              
47             sub load_all {
48 0     0 0   my ($self,) = @_;
49 0           $self->load([$self->tables]);
50             }
51              
52             sub load_external_fixture {
53 0     0 0   my $v = Data::Validator->new(
54             table => +{ isa => 'Str' },
55             external_fixture_path => +{ isa => 'Str' },
56             )->with(qw/Method/);
57 0           my ($self, $args) = $v->validate(@_);
58              
59             $self->_load_fixture(
60             table => $args->{table},
61             fixture_path => $args->{external_fixture_path},
62 0           );
63             }
64              
65             sub load_all_external_fixture {
66 0     0 0   my $v = Data::Validator->new(
67             external_fixture_path => +{ isa => 'Str' },
68             )->with(qw/Method/);
69 0           my ($self, $args) = $v->validate(@_);
70              
71 0           for my $table ($self->tables) {
72             $self->_load_fixture(
73             table => $table,
74             fixture_path => $args->{external_fixture_path},
75 0           );
76             }
77             }
78              
79             sub create {
80 0     0 0   my $v = Data::Validator->new(
81             tables => +{ isa => 'ArrayRef[Str]' },
82             create_file => +{ isa => 'Bool', default => 1 },
83             )->with(qw/Method StrictSequenced/);
84 0           my ($self, $args) = $v->validate(@_);
85              
86 0           my @result;
87 0           for my $data ($self->_build_create_data($args->{tables})) {
88             try {
89             push @result, $self->_make_fixture_yaml(+{%$data, create_file => $args->{create_file}})
90 0 0   0     if $self->conf->{fixture_type} eq 'yaml';
91              
92             push @result, $self->_make_fixture_csv(+{%$data, create_file => $args->{create_file}})
93 0 0         if $self->conf->{fixture_type} eq 'csv';
94             }
95             catch {
96 0     0     warn $_;
97 0           };
98             }
99              
100 0           return @result;
101             }
102              
103             sub create_all {
104 0     0 0   my $v = Data::Validator->new(
105             create_file => +{ isa => 'Bool', default => 1 },
106             )->with(qw/Method/);
107 0           my($self, $args) = $v->validate(@_);
108              
109 0           $self->create([$self->tables], $args->{create_file});
110             }
111              
112             sub ignore_tables {
113 0     0 0   my ($self,) = @_;
114              
115 0 0         return unless exists $self->conf->{ignore_tables};
116 0           return @{$self->conf->{ignore_tables}};
  0            
117             }
118              
119             sub fixtures {
120 0     0 0   my ($self,) = @_;
121              
122 0           my @all_fixtures = $self->_all_fixtures;
123 0           my $type = $self->conf->{fixture_type};
124             my %table2fixture
125             = map {
126 0           my $tmp = basename($_);
  0            
127 0           $tmp =~ s/\.$type$//;
128 0           $tmp => basename($_);
129             } @all_fixtures;
130              
131 0           my @tables = $self->_difference_ignore_tables([keys %table2fixture]);
132 0           my @fixtures = map { $table2fixture{$_} } @tables;
  0            
133              
134 0           return @fixtures;
135             }
136              
137             sub tables {
138 0     0 0   my ($self,) = @_;
139 0           return $self->_difference_ignore_tables([map { $_->[2] } @{$self->dbh->table_info('','','')->fetchall_arrayref}]);
  0            
  0            
140             }
141              
142             sub _all_fixtures {
143 0     0     my ($self,) = @_;
144              
145 0           return glob(File::Spec->catfile($self->conf->{fixture_path}, '*.' . $self->conf->{fixture_type}));
146             }
147              
148             sub _difference_ignore_tables {
149 0     0     my $v = Data::Validator->new(
150             tables => 'ArrayRef[Str]'
151             )->with(qw/Method StrictSequenced/);
152 0           my($self, $args) = $v->validate(@_);
153              
154 0           my @tables = @{$args->{tables}};
  0            
155 0           my @ignore_tables = $self->ignore_tables;
156 0           my @difference_tables;
157 0           for my $table (@tables) {
158             push @difference_tables, $table
159 0 0   0     unless any { $table =~ m/^${_}$/ } @ignore_tables;
  0            
160             }
161              
162 0           return @difference_tables;
163             }
164              
165             sub _make_loader {
166 0     0     my ($self,) = @_;
167              
168             $self->{__make_loader} = DBIx::FixtureLoader->new(dbh => $self->dbh)
169 0 0         unless $self->{__make_loader} ;
170              
171 0           return $self->{__make_loader};
172             }
173              
174             sub _build_create_data {
175 0     0     my $v = Data::Validator->new(
176             tables => +{ isa => 'ArrayRef[Str]' }
177             )->with(qw/Method StrictSequenced/);
178 0           my($self, $args) = $v->validate(@_);
179 0           my @tables = $self->_difference_ignore_tables($args->{tables});
180 0 0         return unless scalar @tables;
181              
182 0           my $schema = $self->_load_schema($self->dbh);
183 0           my @shema_tables = keys %{$schema->{tables}};
  0            
184              
185 0           my $sql_maker = SQL::Maker->new(driver => $self->conf->{driver});
186 0           my @data;
187 0           for my $table (@tables) {
188 0           (my $table_name = $table) =~ s/^\`\w+\`\.//;
189 0           $table_name =~ s/\`//g;
190              
191 0           my $table_data = $schema->{tables}->{$table_name};
192              
193 0           my $columns = $table_data->columns;
194 0           my ($sql) = $sql_maker->select($table_name => $columns);
195              
196 0           push @data, +{ table => $table_name, columns => $columns, sql => $sql };
197             }
198              
199 0           return @data;
200             }
201              
202             sub _load_schema {
203 0     0     my ($self, $dbh) = @_;
204              
205             $self->{__schema} = Teng::Schema::Loader->load(
206             dbh => $dbh,
207             namespace => 'Hoge',
208 0 0         )->schema unless $self->{__schema};
209              
210 0           return $self->{__schema};
211             }
212              
213             sub _load_fixture {
214 0     0     my $v = Data::Validator->new(
215             table => +{ isa => 'Str' },
216             fixture_path => +{ isa => 'Str' },
217             )->with(qw/Method/);
218 0           my ($self, $args) = $v->validate(@_);
219              
220 0           my $loader = $self->_make_loader;
221 0 0         my $load_opt = exists $self->conf->{load_opt} ? $self->conf->{load_opt} : undef;
222              
223 0           my $fixture = File::Spec->catfile($args->{fixture_path}, $args->{table} . '.' . $self->conf->{fixture_type});
224 0 0         return unless -f $fixture;
225              
226             $loader->load_fixture(
227             $fixture,
228             format => $self->conf->{fixture_type},
229 0 0         csv_opt => +{ binary => 1 },
230             ) unless $load_opt;
231              
232             $loader->load_fixture(
233             $fixture,
234             format => $self->conf->{fixture_type},
235 0 0         csv_opt => +{ binary => 1 },
236             $load_opt => 1,
237             ) if $load_opt;
238             }
239              
240             sub _make_fixture_yaml {
241 0     0     my $v = Data::Validator->new(
242             table => 'Str',
243             columns => 'ArrayRef[Str]',
244             sql => 'Str',
245             create_file => +{ isa => 'Bool', default => 1 },
246             )->with(qw/Method/);
247 0           my($self, $args) = $v->validate(@_);
248              
249 0           my %tmp_args = %$args;
250 0           my $fixture_path = File::Spec->catfile($self->conf->{fixture_path}, "$tmp_args{table}.yaml");
251              
252             _dump_yaml(
253             $self->dbh,
254             $tmp_args{table},
255             $tmp_args{columns},
256             $tmp_args{sql},
257 0 0         $args->{create_file} ? $fixture_path : (),
258             );
259             }
260              
261             sub _dump_yaml {
262 0     0     my ( $dbh, $schema, $name_column, $sql, $filename ) = @_;
263 0           my $rows = $dbh->selectall_arrayref( $sql, +{ Slice => +{} } );
264              
265 0           my @data;
266 0           for my $row (@$rows) {
267 0           push(
268             @data,
269             +{
270             schema => $schema,
271             data => $row,
272             }
273             );
274             }
275              
276 0 0         if ($filename) {
277 0           YAML::Syck::DumpFile( $filename, \@data );
278             }
279             else {
280 0           return \@data;
281             }
282             }
283              
284             sub _make_fixture_csv {
285 0     0     my $v = Data::Validator->new(
286             table => 'Str',
287             columns => 'ArrayRef[Str]',
288             sql => 'Str',
289             create_file => +{ isa => 'Bool', default => 1 },
290             )->with(qw/Method/);
291 0           my($self, $args) = $v->validate(@_);
292              
293 0           my %tmp_args = %$args;
294 0           my @columns = @{$args->{columns}};
  0            
295 0           my $fixture_path = File::Spec->catfile($self->conf->{fixture_path}, "$tmp_args{table}.csv");
296              
297 0           my @data = @{$args->{columns}};
  0            
298 0           my $rows = $self->dbh->selectall_arrayref( $args->{sql}, +{ Slice => +{} } );
299              
300 0           my $csv_builder = Text::CSV_XS->new(+{ binary => 1 });
301 0           $csv_builder->combine(@columns);
302              
303 0           my $csv = $csv_builder->string . "\n";
304              
305 0           for my $row (@$rows) {
306 0           my @values;
307 0           for my $key (@data) {
308 0           my $value = $row->{$key};
309 0 0         push @values, decode('utf8', $value)
310             unless utf8::is_utf8($value);
311              
312 0 0         push @values, $value
313             if utf8::is_utf8($value);
314             }
315 0           $csv_builder->combine(@values);
316 0           $csv = $csv . $csv_builder->string . "\n";
317             }
318              
319 0 0         if ($args->{create_file}) {
320 0           open my $file, '>', $fixture_path;
321 0           print $file encode('utf8', $csv);
322 0           close $file;
323             }
324             else {
325 0           return $csv;
326             }
327             }
328              
329             1;
330             __END__
331              
332             =encoding utf-8
333              
334             =head1 NAME
335              
336             DBIx::Fixture::Admin - facilitate data management by the fixtures
337              
338             =head1 SYNOPSIS
339              
340             # in perl code
341             use DBIx::Fixture::Admin;
342              
343             use DBI;
344             my $dbh = DBI->connect("DBI:mysql:sample", "root", "");
345              
346             my $admin = DBIx::Fixture::Admin->new(
347             conf => +{
348             fixture_path => "./fixture/",
349             fixture_type => "yaml",
350             driver => "mysql",
351             load_opt => "update",
352             ignore_tables => ["user_.*", ".*_log"] # ignore management
353             },
354             dbh => $dbh,
355             );
356              
357             $admin->load_all(); # load all fixture
358             $admin->create_all(); # create all fixture
359             $admin->create(["sample"]); # create sample table fixture
360             $admin->load(["sample"]); # load sample table fixture
361              
362             # in CLI
363             # use config file .fixture in current dir
364             # see also .fixture in thish repository
365             create-fixture # execute create_all
366             load-fixture # execute load_all
367              
368             =head1 DESCRIPTION
369              
370             DBIx::Fixture::Admin is facilitate data management by the fixtures
371              
372             =head1 LICENSE
373              
374             Copyright (C) meru_akimbo.
375              
376             This library is free software; you can redistribute it and/or modify
377             it under the same terms as Perl itself.
378              
379             =head1 AUTHOR
380              
381             meru_akimbo E<lt>merukatoruayu0@gmail.comE<gt>
382              
383             =cut
384