DBIx-Class-Fixtures
view release on metacpan or search on metacpan
lib/DBIx/Class/Fixtures.pm view on Meta::CPAN
if ($fetch->{cond} and ref $fetch->{cond} eq 'HASH') {
# if value starts with \ assume it's meant to be passed as a scalar ref
# to dbic. ideally this would substitute deeply
$fetch->{cond} = { map {
$_ => ($fetch->{cond}->{$_} =~ s/^\\//) ? \$fetch->{cond}->{$_}
: $fetch->{cond}->{$_}
} keys %{$fetch->{cond}} };
}
$related_rs = $related_rs->search(
$fetch->{cond},
{ join => $fetch->{join} }
) if $fetch->{cond};
$related_rs = $related_rs->search(
{},
{ rows => $fetch->{quantity} }
) if $fetch->{quantity} && $fetch->{quantity} ne 'all';
$related_rs = $related_rs->search(
{},
{ order_by => $fetch->{order_by} }
) if $fetch->{order_by};
$self->dump_rs($related_rs, { %{$params}, set => $fetch });
}
}
sub _generate_schema {
my $self = shift;
my $params = shift || {};
require DBI;
$self->msg("\ncreating schema");
my $schema_class = $self->schema_class || "DBIx::Class::Fixtures::Schema";
eval "require $schema_class";
die $@ if $@;
my $pre_schema;
my $connection_details = $params->{connection_details};
$namespace_counter++;
my $namespace = "DBIx::Class::Fixtures::GeneratedSchema_$namespace_counter";
Class::C3::Componentised->inject_base( $namespace => $schema_class );
$pre_schema = $namespace->connect(@{$connection_details});
unless( $pre_schema ) {
return DBIx::Class::Exception->throw('connection details not valid');
}
my @tables = map { $self->_name_for_source($pre_schema->source($_)) } $pre_schema->sources;
$self->msg("Tables to drop: [". join(', ', sort @tables) . "]");
my $dbh = $pre_schema->storage->dbh;
# clear existing db
$self->msg("- clearing DB of existing tables");
$pre_schema->storage->txn_do(sub {
$pre_schema->storage->with_deferred_fk_checks(sub {
foreach my $table (@tables) {
eval {
$dbh->do("drop table $table" . ($params->{cascade} ? ' cascade' : '') )
};
}
});
});
# import new ddl file to db
my $ddl_file = $params->{ddl};
$self->msg("- deploying schema using $ddl_file");
my $data = _read_sql($ddl_file);
foreach (@$data) {
eval { $dbh->do($_) or warn "SQL was:\n $_"};
if ($@ && !$self->{ignore_sql_errors}) { die "SQL was:\n $_\n$@"; }
}
$self->msg("- finished importing DDL into DB");
# load schema object from our new DB
$namespace_counter++;
my $namespace2 = "DBIx::Class::Fixtures::GeneratedSchema_$namespace_counter";
Class::C3::Componentised->inject_base( $namespace2 => $schema_class );
my $schema = $namespace2->connect(@{$connection_details});
return $schema;
}
sub _read_sql {
my $ddl_file = shift;
my $fh;
open $fh, "<$ddl_file" or die ("Can't open DDL file, $ddl_file ($!)");
my @data = split(/\n/, join('', <$fh>));
@data = grep(!/^--/, @data);
@data = split(/;/, join('', @data));
close($fh);
@data = grep { $_ && $_ !~ /^-- / } @data;
return \@data;
}
=head2 dump_config_sets
Works just like L</dump> but instead of specifying a single json config set
located in L</config_dir> we dump each set named in the C<configs> parameter.
The parameters are the same as for L</dump> except instead of a C<directory>
parameter we have a C<directory_template> which is a coderef expected to return
a scalar that is a root directory where we will do the actual dumping. This
coderef get three arguments: C<$self>, C<$params> and C<$set_name>. For
example:
$fixture->dump_all_config_sets({
schema => $schema,
configs => [qw/one.json other.json/],
directory_template => sub {
my ($fixture, $params, $set) = @_;
return io->catdir('var', 'fixtures', $params->{schema}->version, $set);
},
});
=cut
sub dump_config_sets {
my ($self, $params) = @_;
my $available_config_sets = delete $params->{configs};
lib/DBIx/Class/Fixtures.pm view on Meta::CPAN
=head2 dump_all_config_sets
my %local_params = %$params;
my $local_self = bless { %$self }, ref($self);
$local_params{directory} = $directory_template->($self, \%local_params, $set);
$local_params{config} = $set;
$self->dump(\%local_params);
Works just like L</dump> but instead of specifying a single json config set
located in L</config_dir> we dump each set in turn to the specified directory.
The parameters are the same as for L</dump> except instead of a C<directory>
parameter we have a C<directory_template> which is a coderef expected to return
a scalar that is a root directory where we will do the actual dumping. This
coderef get three arguments: C<$self>, C<$params> and C<$set_name>. For
example:
$fixture->dump_all_config_sets({
schema => $schema,
directory_template => sub {
my ($fixture, $params, $set) = @_;
return io->catdir('var', 'fixtures', $params->{schema}->version, $set);
},
});
=cut
sub dump_all_config_sets {
my ($self, $params) = @_;
$self->dump_config_sets({
%$params,
configs=>[$self->available_config_sets],
});
}
=head2 populate
=over 4
=item Arguments: \%$attrs
=item Return Value: 1
=back
$fixtures->populate( {
# directory to look for fixtures in, as specified to dump
directory => '/home/me/app/fixtures',
# DDL to deploy
ddl => '/home/me/app/sql/ddl.sql',
# database to clear, deploy and then populate
connection_details => ['dbi:mysql:dbname=app_dev', 'me', 'password'],
# DDL to deploy after populating records, ie. FK constraints
post_ddl => '/home/me/app/sql/post_ddl.sql',
# use CASCADE option when dropping tables
cascade => 1,
# optional, set to 1 to run ddl but not populate
no_populate => 0,
# optional, set to 1 to run each fixture through ->create rather than have
# each $rs populated using $rs->populate. Useful if you have overridden new() logic
# that effects the value of column(s).
use_create => 0,
# optional, same as use_create except with find_or_create.
# Useful if you are populating a persistent data store.
use_find_or_create => 0,
# Dont try to clean the database, just populate over whats there. Requires
# schema option. Use this if you want to handle removing old data yourself
# no_deploy => 1
# schema => $schema
} );
In this case the database app_dev will be cleared of all tables, then the
specified DDL deployed to it, then finally all fixtures found in
/home/me/app/fixtures will be added to it. populate will generate its own
DBIx::Class schema from the DDL rather than being passed one to use. This is
better as custom insert methods are avoided which can to get in the way. In
some cases you might not have a DDL, and so this method will eventually allow a
$schema object to be passed instead.
If needed, you can specify a post_ddl attribute which is a DDL to be applied
after all the fixtures have been added to the database. A good use of this
option would be to add foreign key constraints since databases like Postgresql
cannot disable foreign key checks.
If your tables have foreign key constraints you may want to use the cascade
attribute which will make the drop table functionality cascade, ie 'DROP TABLE
$table CASCADE'.
C<directory> is a required attribute.
If you wish for DBIx::Class::Fixtures to clear the database for you pass in
C<dll> (path to a DDL sql file) and C<connection_details> (array ref of DSN,
user and pass).
If you wish to deal with cleaning the schema yourself, then pass in a C<schema>
attribute containing the connected schema you wish to operate on and set the
C<no_deploy> attribute.
=cut
sub populate {
my $self = shift;
my ($params) = @_;
DBIx::Class::Exception->throw('first arg to populate must be hash ref')
unless ref $params eq 'HASH';
DBIx::Class::Exception->throw('directory param not specified')
unless $params->{directory};
my $fixture_dir = io->dir(delete $params->{directory});
DBIx::Class::Exception->throw("fixture directory '$fixture_dir' does not exist")
unless -d "$fixture_dir";
my $ddl_file;
my $dbh;
my $schema;
if ($params->{ddl} && $params->{connection_details}) {
$ddl_file = io->file(delete $params->{ddl});
unless (-e "$ddl_file") {
return DBIx::Class::Exception->throw('DDL does not exist at ' . $ddl_file);
}
unless (ref $params->{connection_details} eq 'ARRAY') {
return DBIx::Class::Exception->throw('connection details must be an arrayref');
}
$schema = $self->_generate_schema({
ddl => "$ddl_file",
connection_details => delete $params->{connection_details},
%{$params}
});
} elsif ($params->{schema} && $params->{no_deploy}) {
$schema = $params->{schema};
} else {
DBIx::Class::Exception->throw('you must set the ddl and connection_details params');
}
return 1 if $params->{no_populate};
$self->msg("\nimporting fixtures");
my $tmp_fixture_dir = io->dir(tempdir());
my $config_set_path = io->file($fixture_dir, '_config_set');
my $config_set = -e "$config_set_path" ? do { my $VAR1; eval($config_set_path->slurp); $VAR1 } : '';
my $v = Data::Visitor::Callback->new(
plain_value => sub {
my ($visitor, $data) = @_;
( run in 2.664 seconds using v1.01-cache-2.11-cpan-302cb4679cc )