File Coverage

blib/lib/DBIx/Fixture/Admin.pm
Criterion Covered Total %
statement 44 174 25.2
branch 0 38 0.0
condition n/a
subroutine 15 38 39.4
pod 0 9 0.0
total 59 259 22.7


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