DBIx-Class-Fixtures

 view release on metacpan or  search on metacpan

lib/DBIx/Class/Fixtures.pm  view on Meta::CPAN


An array of relationships to be used in the cond clause.

 {
   "sets": [ {
     "class": "Artist",
     "quantiy": "all",
     "cond": { "cds.position": { ">": 4 } },
     "join": ["cds"]
   } ]
 }

Fetch all artists who have cds with position greater than 4.

=head2 fetch

Must be an array of hashes. Specifies which rels to also dump. For example:

 {
   "sets": [ {
     "class": "Artist",
     "ids": ["1", "3"],
     "fetch": [ {
       "rel": "cds",
       "quantity": "3",
       "cond": { "position": "2" }
     } ]
   } ]
 }

Will cause the cds of artists 1 and 3 to be dumped where the cd position is 2.

Valid attributes are: 'rel', 'quantity', 'cond', 'has_many', 'might_have' and
'join'. rel is the name of the DBIx::Class rel to follow, the rest are the same
as in the set attributes. quantity is necessary for has_many relationships, but
not if using for belongs_to or might_have relationships.

=head2 has_many

Specifies whether to fetch has_many rels for this set. Must be a hash
containing keys fetch and quantity.

Set fetch to 1 if you want to fetch them, and quantity to either 'all' or an
integer.

Be careful here, dumping has_many rels can lead to a lot of data being dumped.

=head2 might_have

As with has_many but for might_have relationships. Quantity doesn't do anything
in this case.

This value will be inherited by all fetches in this set. This is not true for
the has_many attribute.

=head2 external

In some cases your database information might be keys to values in some sort of
external storage.  The classic example is you are using L<DBIx::Class::InflateColumn::FS>
to store blob information on the filesystem.  In this case you may wish the ability
to backup your external storage in the same way your database data.  The L</external>
attribute lets you specify a handler for this type of issue.  For example:

    {
        "sets": [{
            "class": "Photo",
            "quantity": "all",
            "external": {
                "file": {
                    "class": "File",
                    "args": {"path":"__ATTR(photo_dir)__"}
                }
            }
        }]
    }

This would use L<DBIx::Class::Fixtures::External::File> to read from a directory
where the path to a file is specified by the C<file> field of the C<Photo> source.
We use the uninflated value of the field so you need to completely handle backup
and restore.  For the common case we provide  L<DBIx::Class::Fixtures::External::File>
and you can create your own custom handlers by placing a '+' in the namespace:

    "class": "+MyApp::Schema::SomeExternalStorage",

Although if possible I'd love to get patches to add some of the other common
types (I imagine storage in MogileFS, Redis, etc or even Amazon might be popular.)

See L<DBIx::Class::Fixtures::External::File> for the external handler interface.

=head1 RULE ATTRIBUTES

=head2 cond

Same as with L</SET ATTRIBUTES>

=head2 fetch

Same as with L</SET ATTRIBUTES>

=head2 join

Same as with L</SET ATTRIBUTES>

=head2 has_many

Same as with L</SET ATTRIBUTES>

=head2 might_have

Same as with L</SET ATTRIBUTES>

=head1 RULE SUBSTITUTIONS

You can provide the following substitution patterns for your rule values. An
example of this might be:

    {
        "sets": [{
            "class": "Photo",
            "quantity": "__ENV(NUMBER_PHOTOS_DUMPED)__",
        }]
    }

=head2 ENV

Provide a value from %ENV

=head2 ATTR

Provide a value from L</config_attrs>

=head2 catfile

Create the path to a file from a list

=head2 catdir

Create the path to a directory from a list

lib/DBIx/Class/Fixtures.pm  view on Meta::CPAN

          "".io->catdir(@args);
        },
      };

      my $subsre = join( '|', keys %$subs );
      $_ =~ s{__($subsre)(?:\((.+?)\))?__}{ $subs->{ $1 }->( $self, $2 ? split( /,/, $2 ) : () ) }eg;

      return $_;
    }
  );

  $v->visit( $set );

  die 'no dir passed to dump_object' unless $params->{set_dir};
  die 'no object passed to dump_object' unless $object;

  my @inherited_attrs = @{$self->_inherited_attributes};

  my @pk_vals = map {
    $object->get_column($_)
  } $object->primary_columns;

  my $key = join("\0", @pk_vals);

  my $src = $object->result_source;
  my $exists = $self->dumped_objects->{$src->name}{$key}++;


  # write dir and gen filename
  my $source_dir = io->catdir($params->{set_dir}, $self->_name_for_source($src));
  $source_dir->mkpath(0, 0777);

  # Convert characters not allowed on windows
  my $file = io->catfile("$source_dir",
      join('-', map { s|[/\\:\*\|\?"<>]|_|g; $_; } @pk_vals) . '.fix'
  );

  # write file
  unless ($exists) {
    $self->msg('-- dumping ' . "$file", 2);

    # get_columns will return virtual columns; we just want stored columns.
    # columns_info keys seems to be the actual storage column names, so we'll
    # use that.
    my $col_info = $src->columns_info;
    my @column_names = keys %$col_info;
    my %columns = $object->get_columns;
    my %ds; @ds{@column_names} = @columns{@column_names};

    if($set->{external}) {
      foreach my $field (keys %{$set->{external}}) {
        my $key = $ds{$field};
        my ($plus, $class) = ( $set->{external}->{$field}->{class}=~/^(\+)*(.+)$/);
        my $args = $set->{external}->{$field}->{args};

        $class = "DBIx::Class::Fixtures::External::$class" unless $plus;
        eval "use $class";

        $ds{external}->{$field} =
          encode_base64( $class
           ->backup($key => $args),'');
      }
    }

    # mess with dates if specified
    if ($set->{datetime_relative}) {
      my $formatter= eval {$object->result_source->schema->storage->datetime_parser};
      unless (!$formatter) {
        my $dt;
        if ($set->{datetime_relative} eq 'today') {
          $dt = DateTime->today;
        } else {
          $dt = $formatter->parse_datetime($set->{datetime_relative}) unless ($@);
        }

        while (my ($col, $value) = each %ds) {
          my $col_info = $object->result_source->column_info($col);

          next unless $value
            && $col_info->{_inflate_info}
              && (
                  (uc($col_info->{data_type}) eq 'DATETIME')
                    or (uc($col_info->{data_type}) eq 'DATE')
                    or (uc($col_info->{data_type}) eq 'TIME')
                    or (uc($col_info->{data_type}) eq 'TIMESTAMP')
                    or (uc($col_info->{data_type}) eq 'INTERVAL')
                 );

          $ds{$col} = $object->get_inflated_column($col)->subtract_datetime($dt);
        }
      } else {
        warn "datetime_relative not supported for this db driver at the moment";
      }
    }

    # do the actual dumping
    my $serialized = Dump(\%ds)->Out();

    $file->print($serialized);
  }

  # don't bother looking at rels unless we are actually planning to dump at least one type
  my ($might_have, $belongs_to, $has_many) = map {
    $set->{$_}{fetch} || $set->{rules}{$src->source_name}{$_}{fetch}
  } qw/might_have belongs_to has_many/;

  return unless $might_have
             || $belongs_to
             || $has_many
             || $set->{fetch};

  # dump rels of object
  unless ($exists) {
    foreach my $name (sort $src->relationships) {
      my $info = $src->relationship_info($name);
      my $r_source = $src->related_source($name);
      # if belongs_to or might_have with might_have param set or has_many with
      # has_many param set then
      if (
            ( $info->{attrs}{accessor} eq 'single' &&
              (!$info->{attrs}{join_type} || $might_have)



( run in 1.406 second using v1.01-cache-2.11-cpan-39bf76dae61 )