DBIx-Class

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

          name quoting
        - Fix problems with M.A.D. under CGI::SpeedyCGI (RT#65131)
        - Reenable paging of cached resultsets - breakage erroneously added
          in 0.08127
        - Better error handling when prepare() fails silently
        - Fixes skipped lines when a comment is followed by a statement
          when deploying a schema via sql file
        - Fix reverse_relationship_info on prototypical result sources
          (sources not yet registered with a schema)
        - Warn and skip relationships missing from a partial schema during
          dbic cascade_delete
        - Automatically require the requested cursor class before use
          (RT#64795)
        - Work around a Firebird ODBC driver bug exposed by DBD::ODBC 1.29
        - Fix (to the extent allowed by the driver) transaction support in
          DBD::Sybase compiled against FreeTDS
        - Fix exiting via next warnings in ResultSource::sequence()
        - Fix stripping of table qualifiers in update/delete in arrayref
          condition elements
        - Change SQLMaker carp-monkeypatch to be compatible with versions
          of SQL::Abstract >= 1.73

Changes  view on Meta::CPAN

        - Fix nasty potentially data-eating bug when deleting/updating
          a limited resultset
        - Fix find() to use result_class set on object
        - Fix result_class setter behaviour to not mistakenly stuff attrs.
        - Don't try and ensure_class_loaded an object. This doesn't work.
        - Fix as_subselect_rs to not inject resultset class-wide where
          conditions outside of the resulting subquery
        - Fix count() failing with {for} resultset attribute (RT#56257)
        - Fixed incorrect detection of Limit dialect on unconnected $schema
        - update() on row not in_storage no longer throws an exception
          if there are no dirty columns to update (fixes cascaded update
          annoyances)
        - update()/delete() on prefetching resultsets no longer results
          in malformed SQL (some $rs attributes were erroneously left in)
        - Fix dbicadmin to allow deploy() on non-versioned schema
        - Fix dbicadmin to respect sql_dir on upgrade() (RT#57732)
        - Update Schema::Versioned to respect hashref style of
          connection_info
        - Do not recreate the same related object twice during MultiCreate
          (solves the problem of orphaned IC::FS files)
        - Fully qualify xp_msver selector when using DBD::Sybase with

Changes  view on Meta::CPAN

          loaded
        - CDBICompat: override find_or_create to fix column casing when
          ColumnCase is loaded
        - reorganized and simplified tests
        - added Ordered
        - added the ability to set on_connect_do and the various sql_maker
          options as part of Storage::DBI's connect_info.

0.06003 2006-05-19 15:37:30
        - make find_or_create_related check defined() instead of truth
        - don't unnecessarily fetch rels for cascade_update
        - don't set_columns explicitly in update_or_create; instead use
          update($hashref) so InflateColumn works
        - fix for has_many prefetch with 0 related rows
        - make limit error if rows => 0
        - added memory cycle tests and a long-needed weaken call

0.06002 2006-04-20 00:42:41
        - fix set_from_related to accept undef
        - fix to Dumper-induced hash iteration bug
        - fix to copy() with non-composed resultsource

Changes  view on Meta::CPAN

        - renamed cols attribute to columns (cols still supported)
        - added has_column_loaded to Row
        - Storage::DBI connect_info supports coderef returning dbh as 1st arg
        - load_components() doesn't prepend base when comp. prefixed with +
        - $schema->deploy
        - HAVING support
        - prefetch for has_many
        - cache attr for resultsets
        - PK::Auto::* no longer required since Storage::DBI::* handle auto-inc
        - minor tweak to tests for join edge case
        - added cascade_copy relationship attribute
          (sponsored by Airspace Software, http://www.airspace.co.uk/)
        - clean up set_from_related
        - made copy() automatically null out auto-inc columns
        - added txn_do() method to Schema, which allows a coderef to be
          executed atomically

0.05007 2006-02-24 00:59:00
        - tweak to Componentised for Class::C3 0.11
        - fixes for auto-inc under MSSQL

MANIFEST  view on Meta::CPAN

t/74mssql.t
t/750firebird.t
t/751msaccess.t
t/752sqlite.t
t/76joins.t
t/76select.t
t/77join_count.t
t/78self_referencial.t
t/79aliasing.t
t/80unique.t
t/82cascade_copy.t
t/83cache.t
t/84serialize.t
t/85utf8.t
t/86might_have.t
t/86sqlt.t
t/87ordered.t
t/88result_set_column.t
t/90ensure_class_loaded.t
t/90join_torture.t
t/91merge_joinpref_attr.t

MANIFEST  view on Meta::CPAN

t/cdbi/12-filter.t
t/cdbi/13-constraint.t
t/cdbi/14-might_have.t
t/cdbi/15-accessor.t
t/cdbi/16-reserved.t
t/cdbi/18-has_a.t
t/cdbi/19-set_sql.t
t/cdbi/21-iterator.t
t/cdbi/22-deflate_order.t
t/cdbi/22-self_referential.t
t/cdbi/23-cascade.t
t/cdbi/24-meta_info.t
t/cdbi/26-mutator.t
t/cdbi/30-pager.t
t/cdbi/68-inflate_has_a.t
t/cdbi/70_implicit_inflate.t
t/cdbi/71_column_object.t
t/cdbi/98-failure.t
t/cdbi/abstract/search_where.t
t/cdbi/columns_as_hashes.t
t/cdbi/columns_dont_override_custom_accessors.t

MANIFEST  view on Meta::CPAN

t/count/grouped_pager.t
t/count/in_subquery.t
t/count/joined.t
t/count/prefetch.t
t/count/search_related.t
t/debug/bulk-insert.t
t/debug/core.t
t/debug/no-repeats.t
t/debug/pretty.t
t/debug/show-progress.t
t/delete/cascade_missing.t
t/delete/complex.t
t/delete/m2m.t
t/delete/related.t
t/discard_changes_in_DESTROY.t
t/inflate/core.t
t/inflate/datetime.t
t/inflate/datetime_determine_parser.t
t/inflate/datetime_firebird.t
t/inflate/datetime_informix.t
t/inflate/datetime_missing_deps.t

MANIFEST  view on Meta::CPAN

t/multi_create/existing_in_chain.t
t/multi_create/find_or_multicreate.t
t/multi_create/has_many.t
t/multi_create/in_memory.t
t/multi_create/insert_defaults.t
t/multi_create/m2m.t
t/multi_create/multilev_single_PKeqFK.t
t/multi_create/reentrance_count.t
t/multi_create/standard.t
t/multi_create/torture.t
t/ordered/cascade_delete.t
t/ordered/unordered_movement.t
t/pager/data_page_compat/constructor.t
t/pager/data_page_compat/simple.t
t/pager/dbic_core.t
t/prefetch/attrs_untouched.t
t/prefetch/correlated.t
t/prefetch/count.t
t/prefetch/diamond.t
t/prefetch/double_prefetch.t
t/prefetch/empty_cache.t

lib/DBIx/Class/CDBICompat/Relationships.pm  view on Meta::CPAN


  my @f_method;

  if (ref $f_class eq 'ARRAY') {
    ($f_class, @f_method) = @$f_class;
  }

  if (ref $f_key eq 'HASH' && !$args) { $args = $f_key; undef $f_key; };

  $args ||= {};
  my $cascade = delete $args->{cascade} || '';
  if (delete $args->{no_cascade_delete} || $cascade eq 'None') {
    $args->{cascade_delete} = 0;
  }
  elsif( $cascade eq 'Delete' ) {
    $args->{cascade_delete} = 1;
  }
  elsif( length $cascade ) {
    warn "Unemulated cascade option '$cascade' in $class->has_many($rel => $f_class)";
  }

  if( !$f_key and !@f_method ) {
      $class->ensure_class_loaded($f_class);
      my $f_source = $f_class->result_source_instance;
      ($f_key) = grep { $f_source->relationship_info($_)->{class} eq $class }
                      $f_source->relationships;
  }

  $class->next::method($rel, $f_class, $f_key, $args);

lib/DBIx/Class/Manual/FAQ.pod  view on Meta::CPAN

Instead of supplying a single column name, all relationship types also
allow you to supply a hashref containing the condition across which
the tables are to be joined. The condition may contain as many fields
as you like. See L<DBIx::Class::Relationship::Base>.

=item .. define a relationship bridge across an intermediate table? (many-to-many)

The term 'relationship' is used loosely with many_to_many as it is not considered a
relationship in the fullest sense.  For more info, read the documentation on L<DBIx::Class::Relationship/many_to_many>.

=item .. stop DBIx::Class from attempting to cascade deletes on my has_many and might_have relationships?

By default, DBIx::Class cascades deletes and updates across
C<has_many> and C<might_have> relationships. You can disable this
behaviour on a per-relationship basis by supplying
C<< cascade_delete => 0 >> in the relationship attributes.

The cascaded operations are performed after the requested delete or
update, so if your database has a constraint on the relationship, it
will have deleted/updated the related records or raised an exception
before DBIx::Class gets to perform the cascaded operation.

See L<DBIx::Class::Relationship>.

=item .. use a relationship?

Use its name. An accessor is created using the name. See examples in
L<DBIx::Class::Manual::Cookbook/USING RELATIONSHIPS>.

=back

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

    }

    my $shift_rs = $self->_group_rs-> search ({ $position_column => { -between => \@between } });

    # some databases (sqlite, pg, perhaps others) are dumb and can not do a
    # blanket increment/decrement without violating a unique constraint.
    # So what we do here is check if the position column is part of a unique
    # constraint, and do a one-by-one update if this is the case.
    my $rsrc = $self->result_source;

    # set in case there are more cascades combined with $rs->update => $rs_update_all overrides
    local $rsrc->schema->{_ORDERED_INTERNAL_UPDATE} = 1;
    my @pcols = $rsrc->primary_columns;
    if (
      grep { $_ eq $position_column } ( map { @$_ } (values %{{ $rsrc->unique_constraints }} ) )
    ) {
        my $clean_rs = $rsrc->resultset;

        for ( $shift_rs->search (
          {}, { order_by => { "-$ord", $position_column }, select => [$position_column, @pcols] }
        )->cursor->all ) {

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


  # in a Book class (where Author has_many Books)
  __PACKAGE__->belongs_to(
    author =>
    'My::DBIC::Schema::Author',
    'author',
    { join_type => 'left' }
  );

Cascading deletes are off by default on a C<belongs_to>
relationship. To turn them on, pass C<< cascade_delete => 1 >>
in the $attr hashref.

By default, DBIC will return undef and avoid querying the database if a
C<belongs_to> accessor is called when any part of the foreign key IS NULL. To
disable this behavior, pass C<< undef_on_null_fk => 0 >> in the C<\%attrs>
hashref.

NOTE: If you are used to L<Class::DBI> relationships, this is the equivalent
of C<has_a>.

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

The second is almost exactly the same as the accessor method but "_rs"
is added to the end of the method name, eg C<$accessor_name_rs()>.
This method works just like the normal accessor, except that it always
returns a resultset, even in list context. The third method, named C<<
add_to_$rel_name >>, will also be added to your Row items; this allows
you to insert new related items, using the same mechanism as in
L<DBIx::Class::Relationship::Base/"create_related">.

If you delete an object in a class with a C<has_many> relationship, all
the related objects will be deleted as well.  To turn this behaviour off,
pass C<< cascade_delete => 0 >> in the C<$attr> hashref.

The cascaded operations are performed after the requested delete or
update, so if your database has a constraint on the relationship, it
will have deleted/updated the related records or raised an exception
before DBIx::Class gets to perform the cascaded operation.

If you copy an object in a class with a C<has_many> relationship, all
the related objects will be copied as well. To turn this behaviour off,
pass C<< cascade_copy => 0 >> in the C<$attr> hashref. The behaviour
defaults to C<< cascade_copy => 1 >>.

See L<DBIx::Class::Relationship::Base/attributes> for documentation on
relationship methods and valid relationship attributes. Also see
L<DBIx::Class::ResultSet> for a L<list of standard resultset
attributes|DBIx::Class::ResultSet/ATTRIBUTES> which can be assigned to
relationships as well.

=head2 might_have

=over 4

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

    pseudonym =>
    'My::DBIC::Schema::Pseudonym',
    { 'foreign.author_id' => 'self.id' },
  );

  # Usage
  my $pname = $author->pseudonym; # to get the Pseudonym object

If you update or delete an object in a class with a C<might_have>
relationship, the related object will be updated or deleted as well. To
turn off this behavior, add C<< cascade_delete => 0 >> to the C<$attr>
hashref.

The cascaded operations are performed after the requested delete or
update, so if your database has a constraint on the relationship, it
will have deleted/updated the related records or raised an exception
before DBIx::Class gets to perform the cascaded operation.

See L<DBIx::Class::Relationship::Base/attributes> for documentation on
relationship methods and valid relationship attributes. Also see
L<DBIx::Class::ResultSet> for a L<list of standard resultset
attributes|DBIx::Class::ResultSet/ATTRIBUTES> which can be assigned to
relationships as well.

Note that if you supply a condition on which to join, and the column in the
current table allows nulls (i.e., has the C<is_nullable> attribute set to a
true value), than C<might_have> will warn about this because it's naughty and

lib/DBIx/Class/Relationship/Base.pm  view on Meta::CPAN


=item join_type

Explicitly specifies the type of join to use in the relationship. Any SQL
join type is valid, e.g. C<LEFT> or C<RIGHT>. It will be placed in the SQL
command immediately before C<JOIN>.

=item proxy =E<gt> $column | \@columns | \%column

The 'proxy' attribute can be used to retrieve values, and to perform
updates if the relationship has 'cascade_update' set. The 'might_have'
and 'has_one' relationships have this set by default; if you want a proxy
to update across a 'belongs_to' relationship, you must set the attribute
yourself.

=over 4

=item \@columns

An arrayref containing a list of accessors in the foreign class to create in
the main class. If, for example, you do the following:

lib/DBIx/Class/Relationship/Base.pm  view on Meta::CPAN

    undef, {
      proxy => [ qw/notes/ ],
    });

Then, assuming MyApp::Schema::LinerNotes has an accessor named notes, you can do:

  my $cd = MyApp::Schema::CD->find(1);
  $cd->notes('Notes go here'); # set notes -- LinerNotes object is
                               # created if it doesn't exist

For a 'belongs_to relationship, note the 'cascade_update':

  MyApp::Schema::Track->belongs_to( cd => 'MyApp::Schema::CD', 'cd,
      { proxy => ['title'], cascade_update => 1 }
  );
  $track->title('New Title');
  $track->update; # updates title in CD

=item \%column

A hashref where each key is the accessor you want installed in the main class,
and its value is the name of the original in the foreign class.

  MyApp::Schema::Track->belongs_to( cd => 'MyApp::Schema::CD', 'cd', {

lib/DBIx/Class/Relationship/Base.pm  view on Meta::CPAN

a column accessor). For C<multi> accessors, an add_to_* method is also
created, which calls C<create_related> for the relationship.

=item is_foreign_key_constraint

If you are using L<SQL::Translator> to create SQL for you and you find that it
is creating constraints where it shouldn't, or not creating them where it
should, set this attribute to a true or false value to override the detection
of when to create constraints.

=item cascade_copy

If C<cascade_copy> is true on a C<has_many> relationship for an
object, then when you copy the object all the related objects will
be copied too. To turn this behaviour off, pass C<< cascade_copy => 0 >>
in the C<$attr> hashref.

The behaviour defaults to C<< cascade_copy => 1 >> for C<has_many>
relationships.

=item cascade_delete

By default, DBIx::Class cascades deletes across C<has_many>,
C<has_one> and C<might_have> relationships. You can disable this
behaviour on a per-relationship basis by supplying
C<< cascade_delete => 0 >> in the relationship attributes.

The cascaded operations are performed after the requested delete,
so if your database has a constraint on the relationship, it will
have deleted/updated the related records or raised an exception
before DBIx::Class gets to perform the cascaded operation.

=item cascade_update

By default, DBIx::Class cascades updates across C<has_one> and
C<might_have> relationships. You can disable this behaviour on a
per-relationship basis by supplying C<< cascade_update => 0 >> in
the relationship attributes.

The C<belongs_to> relationship does not update across relationships
by default, so if you have a 'proxy' attribute on a belongs_to and want to
use 'update' on it, you must set C<< cascade_update => 1 >>.

This is not a RDMS style cascade update - it purely means that when
an object has update called on it, all the related objects also
have update called. It will not change foreign keys automatically -
you must arrange to do this yourself.

=item on_delete / on_update

If you are using L<SQL::Translator> to create SQL for you, you can use these
attributes to explicitly set the desired C<ON DELETE> or C<ON UPDATE> constraint
type. If not supplied the SQLT parser will attempt to infer the constraint type by
interrogating the attributes of the B<opposite> relationship. For any 'multi'
relationship with C<< cascade_delete => 1 >>, the corresponding belongs_to
relationship will be created with an C<ON DELETE CASCADE> constraint. For any
relationship bearing C<< cascade_copy => 1 >> the resulting belongs_to constraint
will be C<ON UPDATE CASCADE>. If you wish to disable this autodetection, and just
use the RDBMS' default constraint type, pass C<< on_delete => undef >> or
C<< on_delete => '' >>, and the same for C<on_update> respectively.

=item is_deferrable

Tells L<SQL::Translator> that the foreign key constraint it creates should be
deferrable. In other words, the user may request that the constraint be ignored
until the end of the transaction. Currently, only the PostgreSQL producer
actually supports this.

lib/DBIx/Class/Relationship/CascadeActions.pm  view on Meta::CPAN


sub delete {
  my ($self, @rest) = @_;
  return $self->next::method(@rest) unless ref $self;
    # I'm just ignoring this for class deletes because hell, the db should
    # be handling this anyway. Assuming we have joins we probably actually
    # *could* do them, but I'd rather not.

  my $source = $self->result_source;
  my %rels = map { $_ => $source->relationship_info($_) } $source->relationships;
  my @cascade = grep { $rels{$_}{attrs}{cascade_delete} } keys %rels;

  if (@cascade) {
    my $guard = $source->schema->txn_scope_guard;

    my $ret = $self->next::method(@rest);

    foreach my $rel (@cascade) {
      if( my $rel_rs = eval{ $self->search_related($rel) } ) {
        $rel_rs->delete_all;
      } else {
        carp "Skipping cascade delete on relationship '$rel' - related resultsource '$rels{$rel}{class}' is not registered with this schema";
        next;
      }
    }

    $guard->commit;
    return $ret;
  }

  $self->next::method(@rest);
}

sub update {
  my ($self, @rest) = @_;
  return $self->next::method(@rest) unless ref $self;
    # Because update cascades on a class *really* don't make sense!

  my $source = $self->result_source;
  my %rels = map { $_ => $source->relationship_info($_) } $source->relationships;
  my @cascade = grep { $rels{$_}{attrs}{cascade_update} } keys %rels;

  if (@cascade) {
    my $guard = $source->schema->txn_scope_guard;

    my $ret = $self->next::method(@rest);

    foreach my $rel (@cascade) {
      next if (
        $rels{$rel}{attrs}{accessor}
          &&
        $rels{$rel}{attrs}{accessor} eq 'single'
          &&
        !exists($self->{_relationship_data}{$rel})
      );
      $_->update for grep defined, $self->$rel;
    }

lib/DBIx/Class/Relationship/HasMany.pm  view on Meta::CPAN

#    # only perform checks if the far side appears already loaded
#    if (my $f_rsrc = try { $f_class->result_source_instance } ) {
#      $class->throw_exception(
#        "No such column '$f_key' on foreign class ${f_class} ($guess)"
#      ) if !$f_rsrc->has_column($f_key);
#    }

    $cond = { "foreign.${f_key}" => "self.${pri}" };
  }

  my $default_cascade = ref $cond eq 'CODE' ? 0 : 1;

  $class->add_relationship($rel, $f_class, $cond, {
    accessor => 'multi',
    join_type => 'LEFT',
    cascade_delete => $default_cascade,
    cascade_copy => $default_cascade,
    is_depends_on => 0,
    %{$attrs||{}}
  });
}

1;

lib/DBIx/Class/Relationship/HasOne.pm  view on Meta::CPAN

#    if (! $f_rsrc and $f_rsrc = try { $f_class->result_source_instance }) {
#      $class->throw_exception(
#        "No such column '$f_key' on foreign class ${f_class} ($guess)"
#      ) if !$f_rsrc->has_column($f_key);
#    }

    $cond = { "foreign.${f_key}" => "self.${pri}" };
  }
  $class->_validate_has_one_condition($cond);

  my $default_cascade = ref $cond eq 'CODE' ? 0 : 1;

  $class->add_relationship($rel, $f_class,
   $cond,
   { accessor => 'single',
     cascade_update => $default_cascade,
     cascade_delete => $default_cascade,
     is_depends_on => 0,
     ($join_type ? ('join_type' => $join_type) : ()),
     %{$attrs || {}} });
  1;
}

sub _validate_has_one_condition {
  my ($class, $cond )  = @_;

  return if $ENV{DBIC_DONT_VALIDATE_RELS};

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


=item Return Value: $underlying_storage_rv

=back

Sets the specified columns in the resultset to the supplied values in a
single query. Note that this will not run any accessor/set_column/update
triggers, nor will it update any result object instances derived from this
resultset (this includes the contents of the L<resultset cache|/set_cache>
if any). See L</update_all> if you need to execute any on-update
triggers or cascades defined either by you or a
L<result component|DBIx::Class::Manual::Component/WHAT IS A COMPONENT>.

The return value is a pass through of what the underlying
storage backend returned, and may vary. See L<DBI/execute> for the most
common case.

=head3 CAVEAT

Note that L</update> does not process/deflate any of the values passed in.
This is unlike the corresponding L<DBIx::Class::Row/update>. The user must

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


=item Return Value: $underlying_storage_rv

=back

Deletes the rows matching this resultset in a single query. Note that this
will not run any delete triggers, nor will it alter the
L<in_storage|DBIx::Class::Row/in_storage> status of any result object instances
derived from this resultset (this includes the contents of the
L<resultset cache|/set_cache> if any). See L</delete_all> if you need to
execute any on-delete triggers or cascades defined either by you or a
L<result component|DBIx::Class::Manual::Component/WHAT IS A COMPONENT>.

The return value is a pass through of what the underlying storage backend
returned, and may vary. See L<DBI/execute> for the most common case.

=cut

sub delete {
  my $self = shift;
  $self->throw_exception('delete does not accept any arguments')

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

uniquely identifying the database row can not be constructed (see
L<significance of primary keys|DBIx::Class::Manual::Intro/The Significance and Importance of Primary Keys>
for more details).

The object is still perfectly usable, but L</in_storage> will
now return 0 and the object must be reinserted using L</insert>
before it can be used to L</update> the row again.

If you delete an object in a class with a C<has_many> relationship, an
attempt is made to delete all the related objects as well. To turn
this behaviour off, pass C<< cascade_delete => 0 >> in the C<$attr>
hashref of the relationship, see L<DBIx::Class::Relationship>. Any
database-level cascade or restrict will take precedence over a
DBIx-Class-based cascading delete, since DBIx-Class B<deletes the
main row first> and only then attempts to delete any remaining related
rows.

If you delete an object within a txn_do() (see L<DBIx::Class::Storage/txn_do>)
and the transaction subsequently fails, the result object will remain marked as
not being in storage. If you know for a fact that the object is still in
storage (i.e. by inspecting the cause of the transaction's failure), you can
use C<< $obj->in_storage(1) >> to restore consistency between the object and
the database. This would allow a subsequent C<< $obj->delete >> to work

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

Inserts a new row into the database, as a copy of the original
object. If a hashref of replacement data is supplied, these will take
precedence over data in the original. Also any columns which have
the L<column info attribute|DBIx::Class::ResultSource/add_columns>
C<< is_auto_increment => 1 >> are explicitly removed before the copy,
so that the database can insert its own autoincremented values into
the new object.

Relationships will be followed by the copy procedure B<only> if the
relationship specifies a true value for its
L<cascade_copy|DBIx::Class::Relationship::Base> attribute. C<cascade_copy>
is set by default on C<has_many> relationships and unset on all others.

=cut

sub copy {
  my ($self, $changes) = @_;
  $changes ||= {};
  my $col_data = { $self->get_columns };

  my $rsrc = $self->result_source;

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

  $new->insert;

  # Its possible we'll have 2 relations to the same Source. We need to make
  # sure we don't try to insert the same row twice else we'll violate unique
  # constraints
  my $rel_names_copied = {};

  foreach my $rel_name ($rsrc->relationships) {
    my $rel_info = $rsrc->relationship_info($rel_name);

    next unless $rel_info->{attrs}{cascade_copy};

    my $resolved = $rsrc->_resolve_condition(
      $rel_info->{cond}, $rel_name, $new, $rel_name
    );

    my $copied = $rel_names_copied->{ $rel_info->{source} } ||= {};
    foreach my $related ($self->search_related($rel_name)->all) {
      $related->copy($resolved)
        unless $copied->{$related->ID}++;
    }

lib/SQL/Translator/Parser/DBIx/Class.pm  view on Meta::CPAN

            }
            # if indeed single, check if all self.columns are our primary keys.
            # this is supposed to indicate a has_one/might_have...
            # where's the introspection!!?? :)
            else {
                $fk_constraint = not $source->_compare_relationship_keys(\@keys, \@primary);
            }

            my ($otherrelname, $otherrelationship) = %{ $source->reverse_relationship_info($rel) };

            my $cascade;
            for my $c (qw/delete update/) {
                if (exists $rel_info->{attrs}{"on_$c"}) {
                    if ($fk_constraint) {
                        $cascade->{$c} = $rel_info->{attrs}{"on_$c"};
                    }
                    elsif ( $rel_info->{attrs}{"on_$c"} ) {
                        carp "SQLT attribute 'on_$c' was supplied for relationship '$moniker/$rel', which does not appear to be a foreign constraint. "
                            . "If you are sure that SQLT must generate a constraint for this relationship, add 'is_foreign_key_constraint => 1' to the attributes.\n";
                    }
                }
                elsif (defined $otherrelationship and $otherrelationship->{attrs}{$c eq 'update' ? 'cascade_copy' : 'cascade_delete'}) {
                    $cascade->{$c} = 'CASCADE';
                }
            }

            if($rel_table) {
                # Constraints are added only if applicable
                next unless $fk_constraint;

                # Make sure we don't create the same foreign key constraint twice
                my $key_test = join("\x00", sort @keys);
                next if $created_FK_rels{$rel_table}->{$key_test};

lib/SQL/Translator/Parser/DBIx/Class.pm  view on Meta::CPAN


                  # trim schema before generating constraint/index names
                  (my $table_abbrev = $table_name) =~ s/ ^ [^\.]+ \. //x;

                  $table->add_constraint(
                    type             => 'foreign_key',
                    name             => join('_', $table_abbrev, 'fk', @keys),
                    fields           => \@keys,
                    reference_fields => \@refkeys,
                    reference_table  => $rel_table,
                    on_delete        => uc ($cascade->{delete} || ''),
                    on_update        => uc ($cascade->{update} || ''),
                    (defined $is_deferrable ? ( deferrable => $is_deferrable ) : ()),
                  );

                  # global parser_args add_fk_index param can be overridden on the rel def
                  my $add_fk_index_rel = (exists $rel_info->{attrs}{add_fk_index}) ? $rel_info->{attrs}{add_fk_index} : $add_fk_index;

                  # Check that we do not create an index identical to the PK index
                  # (some RDBMS croak on this, and it generally doesn't make much sense)
                  # NOTE: we do not sort the key columns because the order of
                  # columns is important for indexes and two indexes with the

t/60core.t  view on Meta::CPAN

  is(@artsn, 4, "Four artists returned");

  # make sure subclasses that don't set source_name are ok
  ok($schema->source('ArtistSubclass'), 'ArtistSubclass exists');
}

my $newbook = $schema->resultset( 'Bookmark' )->find(1);

lives_ok (sub { my $newlink = $newbook->link}, "stringify to false value doesn't cause error");

# test cascade_delete through many_to_many relations
{
  my $art_del = $schema->resultset("Artist")->find({ artistid => 1 });
  lives_ok (sub { $art_del->delete }, 'Cascading delete on Ordered has_many works' );  # real test in ordered.t
  is( $schema->resultset("CD")->search({artist => 1}), 0, 'Cascading through has_many top level.');
  is( $schema->resultset("CD_to_Producer")->search({cd => 1}), 0, 'Cascading through has_many children.');
}

# test column_info
{
  $schema->source("Artist")->{_columns}{'artistid'} = {};

t/cdbi/14-might_have.t  view on Meta::CPAN

  is $bt->blurb, $info->blurb, "Blurb is the same as fetching the long way";
  ok $bt->blurb("New blurb"), "We can set the blurb";
  $bt->update;
  is $bt->blurb, $info->blurb, "Blurb has been set";

  $bt->rating(18);
  eval { $bt->update };
  is $@, '', "No problems updating when do have";
  is $bt->rating, 18, "Updated OK";

  # cascade delete?
  {
    my $blurb = Blurb->retrieve('Bad Taste');
    isa_ok $blurb => "Blurb";
    $bt->delete;
    $blurb = Blurb->retrieve('Bad Taste');
    is $blurb, undef, "Blurb has gone";
  }

}

t/cdbi/23-cascade.t  view on Meta::CPAN

    my $dir = Director->insert({
        name => "Lewis Teague",
    });
    my $kk = $dir->add_to_nasties({
        Title => 'Alligator'
    });
    is $kk->director, $dir, "Director set OK";
    is $dir->nasties, 1, "We have one nasty";

    ok $dir->delete;
    ok !Film->retrieve("Alligator"), "has_many cascade deletes by default";
}


# Two ways of saying not to cascade
for my $args ({ no_cascade_delete => 1 }, { cascade => "None" }) {
    Director->has_many(nasties => 'Film', $args);

    my $dir = Director->insert({
        name => "Lewis Teague",
    });
    my $kk = $dir->add_to_nasties({
        Title => 'Alligator'
    });
    is $kk->director, $dir, "Director set OK";
    is $dir->nasties, 1, "We have one nasty";

    ok $dir->delete;
    local $Data::Dumper::Terse = 1;
    ok +Film->retrieve("Alligator"), 'has_many with ' . Dumper ($args);;
    $kk->delete;
}


#{ # Fail on cascade
#    local $TODO = 'cascade => "Fail" unimplemented';
#
#    Director->has_many(nasties => Film => { cascade => 'Fail' });
#
#    my $dir = Director->insert({ name => "Nasty Noddy" });
#    my $kk = $dir->add_to_nasties({ Title => 'Killer Killers' });
#    is $kk->director, $dir, "Director set OK";
#    is $dir->nasties, 1, "We have one nasty";
#
#    ok !eval { $dir->delete };
#    like $@, qr/1/, "Can't delete while films exist";
#
#    my $rr = $dir->add_to_nasties({ Title => 'Revenge of the Revengers' });

t/delete/cascade_missing.t  view on Meta::CPAN


my $schema = DBICTest->init_schema();
$schema->_unregister_source('CD');

warnings_exist {
  my $s = $schema;
  lives_ok {
    $_->delete for $s->resultset('Artist')->all;
  } 'delete on rows with dangling rels lives';
} [
  # 9 == 3 artists * failed cascades:
  #   cds
  #   cds_unordered
  #   cds_very_very_very_long_relationship_name
  (qr/skipping cascad/i) x 9
], 'got warnings about cascading deletes';

done_testing;

t/lib/DBICTest/BaseResult.pm  view on Meta::CPAN


__PACKAGE__->table ('bogus');
__PACKAGE__->resultset_class ('DBICTest::BaseResultSet');

#sub add_relationship {
#  my $self = shift;
#  my $opts = $_[3] || {};
#  if (grep { $_ eq $_[0] } qw/
#    cds_90s cds_80s cds_84 artist_undirected_maps mapped_artists last_track
#  /) {
#    # nothing - join-dependent or non-cascadeable relationship
#  }
#  elsif ($opts->{is_foreign_key_constraint}) {
#    $opts->{on_update} ||= 'cascade';
#  }
#  else {
#    $opts->{cascade_rekey} = 1
#      unless ref $_[2] eq 'CODE';
#  }
#  $self->next::method(@_[0..2], $opts);
#}

1;

t/lib/DBICTest/Schema/Artist.pm  view on Meta::CPAN

__PACKAGE__->has_many(
    cds_very_very_very_long_relationship_name => 'DBICTest::Schema::CD'
);

__PACKAGE__->has_many( twokeys => 'DBICTest::Schema::TwoKeys' );
__PACKAGE__->has_many( onekeys => 'DBICTest::Schema::OneKey' );

__PACKAGE__->has_many(
  artist_undirected_maps => 'DBICTest::Schema::ArtistUndirectedMap',
  [ {'foreign.id1' => 'self.artistid'}, {'foreign.id2' => 'self.artistid'} ],
  { cascade_copy => 0 } # this would *so* not make sense
);

__PACKAGE__->has_many(
    artwork_to_artist => 'DBICTest::Schema::Artwork_to_Artist' => 'artist_id'
);
__PACKAGE__->many_to_many('artworks', 'artwork_to_artist', 'artwork');

__PACKAGE__->has_many(
    cds_without_genre => 'DBICTest::Schema::CD',
    sub {

t/lib/DBICTest/Schema/ArtistUndirectedMap.pm  view on Meta::CPAN

  'id1' => { data_type => 'integer' },
  'id2' => { data_type => 'integer' },
);
__PACKAGE__->set_primary_key(qw/id1 id2/);

__PACKAGE__->belongs_to( 'artist1', 'DBICTest::Schema::Artist', 'id1', { on_delete => 'RESTRICT', on_update => 'CASCADE'} );
__PACKAGE__->belongs_to( 'artist2', 'DBICTest::Schema::Artist', 'id2', { on_delete => undef, on_update => undef} );
__PACKAGE__->has_many(
  'mapped_artists', 'DBICTest::Schema::Artist',
  [ {'foreign.artistid' => 'self.id1'}, {'foreign.artistid' => 'self.id2'} ],
  { cascade_delete => 0 },
);

1;

t/lib/DBICTest/Schema/Link.pm  view on Meta::CPAN

        is_nullable => 1,
    },
    'title' => {
        data_type => 'varchar',
        size      => 100,
        is_nullable => 1,
    },
);
__PACKAGE__->set_primary_key('id');

__PACKAGE__->has_many ( bookmarks => 'DBICTest::Schema::Bookmark', 'link', { cascade_delete => 0 } );

use overload '""' => sub { shift->url }, fallback=> 1;

1;

t/relationship/core.t  view on Meta::CPAN

my $mapped_rs = $undir_maps->search_related('mapped_artists');

my @art = $mapped_rs->all;

cmp_ok(@art, '==', 2, "Both artist returned from map");

my $searched = $mapped_rs->search({'mapped_artists.artistid' => {'!=', undef}});

cmp_ok($searched->count, '==', 2, "Both artist returned from map after adding another condition");

# check join through cascaded has_many relationships (also empty has_many rels)
$artist = $schema->resultset("Artist")->find(1);
my $trackset = $artist->cds->search_related('tracks');
is($trackset->count, 10, "Correct number of tracks for artist");
is($trackset->all, 10, "Correct number of track objects for artist");

# now see about updating eveything that belongs to artist 2 to artist 3
$artist = $schema->resultset("Artist")->find(2);
my $nartist = $schema->resultset("Artist")->find(3);
cmp_ok($artist->cds->count, '==', 1, "Correct orig #cds for artist");
cmp_ok($nartist->cds->count, '==', 1, "Correct orig #cds for artist");

t/resultset/update_delete.t  view on Meta::CPAN

    $rs->search({}, { prefetch => 'artist' })->delete;
  }, [[
    'DELETE FROM cd WHERE ( cdid IN ( SELECT me.cdid FROM cd me JOIN artist artist ON artist.artistid = me.artist WHERE ( me.year != ? ) ) )',
    2010,
  ]], 'Restricting prefetch left in, selector thrown out');

### switch artist and cd to fully qualified table names
### make sure nothing is stripped out
  my $cd_rsrc = $schema->source('CD');
  $cd_rsrc->name('main.cd');
  $cd_rsrc->relationship_info($_)->{attrs}{cascade_delete} = 0
    for $cd_rsrc->relationships;

  my $art_rsrc = $schema->source('Artist');
  $art_rsrc->name(\'main.artist');
  $art_rsrc->relationship_info($_)->{attrs}{cascade_delete} = 0
    for $art_rsrc->relationships;

  $schema->is_executed_sql_bind( sub {
    $rs->delete
  }, [[
    'DELETE FROM main.cd WHERE year != ?',
    2010,
  ]], 'delete with fully qualified table name' );

  $rs->create({ title => 'foo', artist => 1, year => 2000 });



( run in 0.711 second using v1.01-cache-2.11-cpan-49f99fa48dc )