DBIx-Class-AuditAny

 view release on metacpan or  search on metacpan

MANIFEST  view on Meta::CPAN

lib/DBIx/Class/AuditAny/Role/Storage.pm
lib/DBIx/Class/AuditAny/Util.pm
lib/DBIx/Class/AuditAny/Util/BuiltinDatapoints.pm
lib/DBIx/Class/AuditAny/Util/ResultMaker.pm
lib/DBIx/Class/AuditAny/Util/SchemaMaker.pm
t/001_simple_file_tracking.t
t/002_record_custom_tables.t
t/004_auto_dbic_collector.t
t/005_auto_dbic_collector_defaults.t
t/006_auto_dbic_collector_all_datapoints.t
t/007_cascades.t
t/008_resultset_changes.t
t/009_txn_do.t
t/010_txn_commit.t
t/011_sakila.t
t/012_wackyrels.t
t/013_skip_env.t
t/014_multi_pk.t
t/015_deep_create.t
t/97_pod.t
t/98_podspelling.t

lib/DBIx/Class/AuditAny/Collector/AutoDBIC.pm  view on Meta::CPAN

			},
			$self->changeset_source_name => {
				table_name => $self->changeset_table_name,
				columns => $self->changeset_columns,
				call_class_methods => [
					set_primary_key => ['id'],
					has_many => [
						$self->change_data_rel,
						$namespace . '::' . $self->change_source_name,
						{ "foreign.changeset_id" => "self.id" },
						{ cascade_copy => 0, cascade_delete => 0 },
					]
				]
			},
			$self->change_source_name => {
				table_name => $self->change_table_name,
				columns => $self->change_columns,
				call_class_methods => [
					set_primary_key => ['id'],
					belongs_to => [
						$self->reverse_changeset_data_rel,
						$namespace . '::' . $self->changeset_source_name,
						{ id => "changeset_id" },
						{ is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
					],
					has_many => [
						$self->column_data_rel,
						$namespace . '::' . $self->column_change_source_name,
						{ "foreign.change_id" => "self.id" },
						{ cascade_copy => 0, cascade_delete => 0 },
					]
				]
			},
			$self->column_change_source_name => {
				table_name => $self->column_change_table_name,
				columns => $self->change_column_columns,
				call_class_methods => [
					set_primary_key => ['id'],
					@$col_context_uniq_const,
					#add_unique_constraint => ["change_id", ["change_id", "column_name"]],

lib/DBIx/Class/AuditAny/Role/Storage.pm  view on Meta::CPAN

use strict;
use warnings;

# ABSTRACT: Role to apply to tracked DBIx::Class::Storage objects

use Moo::Role;
use MooX::Types::MooseLike::Base qw(:all);

## TODO:
##  1. track rekey in update
##  2. track changes in FK with cascade


=head1 NAME

DBIx::Class::AuditAny::Role::Storage - Role to apply to tracked DBIx::Class::Storage objects

=head1 DESCRIPTION

This role adds the hooks to the DBIC Storage object to be able to sniff and collect change data
has it happens in real time.

lib/DBIx/Class/AuditAny/Role/Storage.pm  view on Meta::CPAN

  # attribute to be updated and recorded at the end of the update. The 
  # auditors will keep track of their own changes temporarily in a "group":
  $self->_add_change_contexts(
    map {
      $_->_start_current_change_group($Source, $nested, $action, @change_datam)
    } $self->all_auditors
  );
  
  # -----
  # Recursively follow effective changes in other tables that will 
  # be caused by any db-side cascades defined in relationships:
  $self->_follow_relationship_cascades($Source,$cond,$change);
  # -----
  
	# Run the original/supplied method:
	my @ret;
  if($orig) {
    try {
      #############################################################
      # ---  Call original - scalar/list/void context agnostic  ---
      @ret = !defined $want ? do { $self->$orig(@$args); undef }
        : $want ? $self->$orig(@$args)

lib/DBIx/Class/AuditAny/Role/Storage.pm  view on Meta::CPAN

	# into the active changeset (unless the action we're following is nested):
  unless ($nested) {
    $self->_record_change_contexts;
    $_->_finish_current_change_group for ($self->all_auditors);
  }
	
	return $want ? @ret : $ret[0];
}


sub _follow_relationship_cascades {
  my ($self, $Source, $cond, $change) = @_;
  
  ## IN PROGRESS.....
  
  # If any of these columns are being changed, we have to also watch the
  # corresponding relationhips for changes (from cascades) during the
  # course of the current database operation. This can be expensive, but
  # we prefer accuracy over speed
  my $cascade_cols = $self->_get_cascading_rekey_columns($Source);
  
  # temp: just get all of themfor now
  #  this should be limited to only rels associated with columns
  #  being changed
  my @rels = uniq(map { @{$cascade_cols->{$_}} } keys %$cascade_cols);
  
  foreach my $rel (@rels) {
    my $rinfo = $Source->relationship_info($rel);
    #my $rrinfo = $Source->reverse_relationship_info($rel);
    
    # Generate a virtual 'change' to describe what will happen in the related table
    my $map = &_cond_foreign_keymap($rinfo->{cond});
    my $rel_change = {};
    foreach my $col (keys %$change) {
      my $fcol = $map->{$col} or next;
      $rel_change->{$fcol} = $change->{$col};
    }
     
    # Only track related rows if there is at least one related change:
    if(scalar(keys %$rel_change) > 0) {
      # Get related rows that will be changed from the cascade:
      my $rel_rows = get_raw_source_related_rows($Source,$rel,$cond);
      
      # Follow these rows via special nested call:
      $self->_follow_row_changes({
        Source => $Source->related_source($rel),
        rows => $rel_rows,
        cond => {},
        nested => 1,
        action => 'update',
        change => $rel_change

lib/DBIx/Class/AuditAny/Role/Storage.pm  view on Meta::CPAN

	
	# Get the current rows that are going to be deleted:
	my $rows = get_raw_source_rows($Source,$cond);
	
	my @change_datam = map {{
		old_columns => $_,
		condition => $cond
	}} @$rows;
	
	###########################
	# TODO: find cascade deletes here
	###########################
	
	
	# Start new change operation within each Auditor and get back
	# all the created ChangeContexts from all auditors. Each auditor
	# will keep track of its own changes temporarily in a "group":
	my @ChangeContexts = map {
		$_->_start_current_change_group($Source, 0,'delete', @change_datam)
	} $self->all_auditors;
	

lib/DBIx/Class/AuditAny/Role/Storage.pm  view on Meta::CPAN

	# Tell each auditor that we're done and to record the change group
	# into the active changeset:
	$_->_finish_current_change_group for ($self->all_auditors);
	
	return $want ? @ret : $ret[0];
};



# _get_cascading_rekey_cols: gets a map of column names to relationships. These
# are the relationships that *could* be changed via a cascade when the column (fk)
# is changed.
# TODO: use 'cascade_rekey' attr from DBIx::Class::Shadow 
#  (DBIx::Class::Relationship::Cascade::Rekey) ?
sub _get_cascading_rekey_columns {
	my $self = shift;
	my $Source = shift;
	
	# cache for next time (should I even bother? since if rels are added to the ResultSource
	# later this won't get updated? Is that a bigger risk than the performance boost?)
	$self->_source_cascade_rekey_cols->{$Source->source_name} ||= do {
		my $rels = { map { $_ => $Source->relationship_info($_) } $Source->relationships };
		
		my $cascade_cols = {};
		foreach my $rel (keys %$rels) {
			# Only multi rels apply:
			next unless ($rels->{$rel}{attrs}{accessor} eq 'multi');
      
      # NEW: We can't currently do anything with CodeRef conditions
      next if ((ref($rels->{$rel}{cond})||'') eq 'CODE');
			
			# Get all the local columns that effect (i.e. might cascade to) this relationship:
			my @cols = $self->_parse_cond_cols_by_alias($rels->{$rel}{cond},'self');
			
			# Add the relationship to list for each column.
			#$cascade_cols->{$_} ||= [] for (@cols); #<-- don't need this
			push @{$cascade_cols->{$_}}, $rel for (@cols);
		}
	
		return $cascade_cols;
	};
	
	return $self->_source_cascade_rekey_rels->{$Source->source_name};
}

has '_source_cascade_rekey_cols', is => 'ro', isa => HashRef, lazy => 1, default => sub {{}};

sub _parse_cond_cols_by_alias {
	my $self = shift;
	my $cond = shift;
	my $alias = shift;
	
	# Get the string elements (keys and values)
	# (TODO: deep walk any hahs/array structure)
	my @elements = %$cond;
	

t/007_cascades.t  view on Meta::CPAN

		first => 'Payton',
		last => 'Manning',
		team_id => 1,
		position => 'Quarterback'
	}),
	"Insert a test row (Player table)"
);

ok(
	$Position->update({ name => 'QB' }),
	"Update fk that should cascade"
);

ok(
	my $Player = $schema->resultset('Player')->search_rs({ last => 'Manning' })->first,
	"Find the test Player row"
);

is(
	$Player->get_column('position'),
	'QB',
	'Confirm the cascade update happened'
);

### finish me


done_testing;

t/lib/Routine/Sakila.pm  view on Meta::CPAN

			film_actors => [
				{ film_id => 1 }
			]
		}),
		"Insert an Actor row with film_actors link"
	);
	
};


test 'updates_cascades' => { desc => 'Updates causing db-side cascades' } => sub {
	my $self = shift;
	my $schema = $self->Schema;
	
	ok(
		my $English = $schema->resultset('Language')->search_rs({ 
			name => 'English'
		})->first,
		"Find 'English' Language row"
	);
	
	ok(
		$English->update({ language_id => 100 }),
		"Change the PK of the 'English' Language row (should cascade)"
	);
	
};	

1;

t/lib/Routine/Sakila/ToAutoDBIC.pm  view on Meta::CPAN

	is(
		$schema->resultset('AuditChangeColumn')->search_rs({
			$c->{old} => '1',
			$c->{new} => '100',
			$c->{column} => 'language_id',
			'change.action' => 'update',
			'change.source' => 'Film'
		},{
			join => { change => 'changeset' }
		})->count => 2,
		"Expected specific UPDATE records - generated from db-side cascade"
	);

};

1;

t/lib/Routine/WackyRels.pm  view on Meta::CPAN

        ]
      }),
      "Create Grade 'C' with Things"
    );
    
  });
  
};


test 'updates_cascades' => { desc => 'Updates causing db-side cascades' } => sub {
  my $self = shift;
  my $schema = $self->Schema;
  
  ok(
    my $Parent = $schema->resultset('Parent')->search_rs({ 
      size => 'big',
      color => 'blue'
    })->first,
    "Find 'big-blue' Parent row"
  );
  
  ok(
    $Parent->update({ color => 'red' }),
    "Change the PK of the 'big-blue' Parent row (should cascade)"
  );
  
  ok(
    my $Size = $schema->resultset('Size')->search_rs({ 
      name => 'big',
    })->first,
    "Find 'big' Size row"
  );
  
  ok(
    $Size->update({ name => 'venti' }),
    "Change the PK of the 'big' Size row (should cascade + double-cascade [3 tables])"
  );
  
};	

1;

t/lib/Routine/WackyRels/ToAutoDBIC.pm  view on Meta::CPAN

	is(
		$schema->resultset('AuditChangeColumn')->search_rs({
			$c->{old} => 'big',
			$c->{new} => 'venti',
			$c->{column} => 'size',
			'change.action' => 'update',
			'change.source' => 'Product'
		},{
			join => { change => 'changeset' }
		})->count => 3,
		"Expected Product UPDATE records - generated from 1-layer db-side cascade"
	);

	is(
		$schema->resultset('AuditChangeColumn')->search_rs({
			$c->{old} => 'big',
			$c->{new} => 'venti',
			$c->{column} => 'size',
			'change.action' => 'update',
			'change.source' => 'Child'
		},{
			join => { change => 'changeset' }
		})->count => 3,
		"Expected Child UPDATE records - generated from 2-layer db-side cascade"
	);
	
	is(
		$schema->resultset('AuditChangeColumn')->search_rs({
			$c->{old} => 'big',
			$c->{new} => undef,
			$c->{column} => 'size',
			'change.action' => 'update',
			'change.source' => 'Thing'
		},{
			join => { change => 'changeset' }
		})->count => 1,
		"Expected Thing UPDATE records - 'SET NULL' from db-side cascade"
	);

};

1;

t/lib/TestSchema/One/Result/AuditChange.pm  view on Meta::CPAN

  "changeset",
  "TestSchema::One::Result::AuditChangeSet",
  { id => "changeset_id" },
  { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
);

__PACKAGE__->has_many(
  "audit_change_columns",
  "TestSchema::One::Result::AuditChangeColumn",
  { "foreign.change_id" => "self.id" },
  { cascade_copy => 0, cascade_delete => 0 },
);


1;

t/lib/TestSchema/One/Result/AuditChangeSet.pm  view on Meta::CPAN

  },
  "client_ip",
  { data_type => "varchar", is_nullable => 1, size => 32 },
);
__PACKAGE__->set_primary_key("id");

__PACKAGE__->has_many(
  "audit_changes",
  "TestSchema::One::Result::AuditChange",
  { "foreign.changeset_id" => "self.id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

1;

t/lib/TestSchema/One/Result/ContactType.pm  view on Meta::CPAN

  "id"		=> { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
  "name"		=> { data_type => "varchar", is_nullable => 0, size => 32 },
);
__PACKAGE__->set_primary_key("id");


__PACKAGE__->has_many(
  "contacts",
  "TestSchema::One::Result::Contact",
  { "foreign.type_id" => "self.id" },
  { cascade_copy => 0, cascade_delete => 0 },
);


    
1;

t/lib/TestSchema/Sakila/Result/Actor.pm  view on Meta::CPAN

Type: has_many

Related object: L<TestSchema::Sakila::Result::FilmActor>

=cut

__PACKAGE__->has_many(
  "film_actors",
  "TestSchema::Sakila::Result::FilmActor",
  { "foreign.actor_id" => "self.actor_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);


# Created by DBIx::Class::Schema::Loader v0.07010 @ 2013-02-17 16:15:04
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:UTtfCAGXGENKnwGIwF6paA


# You can replace this text with custom code or comments, and it will be preserved on regeneration
1;

t/lib/TestSchema/Sakila/Result/Address.pm  view on Meta::CPAN

Type: has_many

Related object: L<TestSchema::Sakila::Result::Customer>

=cut

__PACKAGE__->has_many(
  "customers",
  "TestSchema::Sakila::Result::Customer",
  { "foreign.address_id" => "self.address_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

=head2 staffs

Type: has_many

Related object: L<TestSchema::Sakila::Result::Staff>

=cut

__PACKAGE__->has_many(
  "staffs",
  "TestSchema::Sakila::Result::Staff",
  { "foreign.address_id" => "self.address_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

=head2 stores

Type: has_many

Related object: L<TestSchema::Sakila::Result::Store>

=cut

__PACKAGE__->has_many(
  "stores",
  "TestSchema::Sakila::Result::Store",
  { "foreign.address_id" => "self.address_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);


# Created by DBIx::Class::Schema::Loader v0.07010 @ 2013-02-17 16:15:04
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:2IpqcMwZA7j+9RoW5A7Z7g


# You can replace this text with custom code or comments, and it will be preserved on regeneration
1;

t/lib/TestSchema/Sakila/Result/Category.pm  view on Meta::CPAN

Type: has_many

Related object: L<TestSchema::Sakila::Result::FilmCategory>

=cut

__PACKAGE__->has_many(
  "film_categories",
  "TestSchema::Sakila::Result::FilmCategory",
  { "foreign.category_id" => "self.category_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);


# Created by DBIx::Class::Schema::Loader v0.07010 @ 2013-02-17 16:15:04
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:FUFmM8sj+adV0Szue+HLfQ


# You can replace this text with custom code or comments, and it will be preserved on regeneration
1;

t/lib/TestSchema/Sakila/Result/City.pm  view on Meta::CPAN

Type: has_many

Related object: L<TestSchema::Sakila::Result::Address>

=cut

__PACKAGE__->has_many(
  "addresses",
  "TestSchema::Sakila::Result::Address",
  { "foreign.city_id" => "self.city_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

=head2 country

Type: belongs_to

Related object: L<TestSchema::Sakila::Result::Country>

=cut

t/lib/TestSchema/Sakila/Result/Country.pm  view on Meta::CPAN

Type: has_many

Related object: L<TestSchema::Sakila::Result::City>

=cut

__PACKAGE__->has_many(
  "cities",
  "TestSchema::Sakila::Result::City",
  { "foreign.country_id" => "self.country_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);


# Created by DBIx::Class::Schema::Loader v0.07010 @ 2013-02-17 16:15:04
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:thoN1+OTcGL++MC+Djcryg


# You can replace this text with custom code or comments, and it will be preserved on regeneration
1;

t/lib/TestSchema/Sakila/Result/Customer.pm  view on Meta::CPAN

Type: has_many

Related object: L<TestSchema::Sakila::Result::Payment>

=cut

__PACKAGE__->has_many(
  "payments",
  "TestSchema::Sakila::Result::Payment",
  { "foreign.customer_id" => "self.customer_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

=head2 rentals

Type: has_many

Related object: L<TestSchema::Sakila::Result::Rental>

=cut

__PACKAGE__->has_many(
  "rentals",
  "TestSchema::Sakila::Result::Rental",
  { "foreign.customer_id" => "self.customer_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);


# Created by DBIx::Class::Schema::Loader v0.07010 @ 2013-02-17 16:15:04
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:VjyzmGea6edtdAUrjNJakQ


# You can replace this text with custom code or comments, and it will be preserved on regeneration
1;

t/lib/TestSchema/Sakila/Result/Film.pm  view on Meta::CPAN

Type: has_many

Related object: L<TestSchema::Sakila::Result::FilmActor>

=cut

__PACKAGE__->has_many(
  "film_actors",
  "TestSchema::Sakila::Result::FilmActor",
  { "foreign.film_id" => "self.film_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

=head2 film_categories

Type: has_many

Related object: L<TestSchema::Sakila::Result::FilmCategory>

=cut

__PACKAGE__->has_many(
  "film_categories",
  "TestSchema::Sakila::Result::FilmCategory",
  { "foreign.film_id" => "self.film_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

=head2 inventories

Type: has_many

Related object: L<TestSchema::Sakila::Result::Inventory>

=cut

__PACKAGE__->has_many(
  "inventories",
  "TestSchema::Sakila::Result::Inventory",
  { "foreign.film_id" => "self.film_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);


# Created by DBIx::Class::Schema::Loader v0.07010 @ 2013-02-17 16:15:04
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Ulh+bL2NSPJo0qWtNss1pA


# You can replace this text with custom code or comments, and it will be preserved on regeneration
1;

t/lib/TestSchema/Sakila/Result/Inventory.pm  view on Meta::CPAN

Type: has_many

Related object: L<TestSchema::Sakila::Result::Rental>

=cut

__PACKAGE__->has_many(
  "rentals",
  "TestSchema::Sakila::Result::Rental",
  { "foreign.inventory_id" => "self.inventory_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);


# Created by DBIx::Class::Schema::Loader v0.07010 @ 2013-02-17 16:15:04
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:oOSD/75feHU/lQ7Op28KYw


# You can replace this text with custom code or comments, and it will be preserved on regeneration
1;

t/lib/TestSchema/Sakila/Result/Language.pm  view on Meta::CPAN

Type: has_many

Related object: L<TestSchema::Sakila::Result::Film>

=cut

__PACKAGE__->has_many(
  "film_languages",
  "TestSchema::Sakila::Result::Film",
  { "foreign.language_id" => "self.language_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

=head2 film_original_languages

Type: has_many

Related object: L<TestSchema::Sakila::Result::Film>

=cut

__PACKAGE__->has_many(
  "film_original_languages",
  "TestSchema::Sakila::Result::Film",
  { "foreign.original_language_id" => "self.language_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);


# Created by DBIx::Class::Schema::Loader v0.07010 @ 2013-02-17 16:15:04
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:JK+DOUbIw1Lhrmp6PE2Q4A


# You can replace this text with custom code or comments, and it will be preserved on regeneration
1;

t/lib/TestSchema/Sakila/Result/Rental.pm  view on Meta::CPAN

Type: has_many

Related object: L<TestSchema::Sakila::Result::Payment>

=cut

__PACKAGE__->has_many(
  "payments",
  "TestSchema::Sakila::Result::Payment",
  { "foreign.rental_id" => "self.rental_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

=head2 staff

Type: belongs_to

Related object: L<TestSchema::Sakila::Result::Staff>

=cut

t/lib/TestSchema/Sakila/Result/Staff.pm  view on Meta::CPAN

Type: has_many

Related object: L<TestSchema::Sakila::Result::Payment>

=cut

__PACKAGE__->has_many(
  "payments",
  "TestSchema::Sakila::Result::Payment",
  { "foreign.staff_id" => "self.staff_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

=head2 rentals

Type: has_many

Related object: L<TestSchema::Sakila::Result::Rental>

=cut

__PACKAGE__->has_many(
  "rentals",
  "TestSchema::Sakila::Result::Rental",
  { "foreign.staff_id" => "self.staff_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

=head2 store

Type: belongs_to

Related object: L<TestSchema::Sakila::Result::Store>

=cut

t/lib/TestSchema/Sakila/Result/Staff.pm  view on Meta::CPAN

Type: might_have

Related object: L<TestSchema::Sakila::Result::Store>

=cut

__PACKAGE__->might_have(
  "store",
  "TestSchema::Sakila::Result::Store",
  { "foreign.manager_staff_id" => "self.staff_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);


# Created by DBIx::Class::Schema::Loader v0.07010 @ 2013-02-17 16:15:04
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:vsAR5vX9nl/POAW1SXr5vA


# You can replace this text with custom code or comments, and it will be preserved on regeneration
1;

t/lib/TestSchema/Sakila/Result/Store.pm  view on Meta::CPAN

Type: has_many

Related object: L<TestSchema::Sakila::Result::Customer>

=cut

__PACKAGE__->has_many(
  "customers",
  "TestSchema::Sakila::Result::Customer",
  { "foreign.store_id" => "self.store_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

=head2 inventories

Type: has_many

Related object: L<TestSchema::Sakila::Result::Inventory>

=cut

__PACKAGE__->has_many(
  "inventories",
  "TestSchema::Sakila::Result::Inventory",
  { "foreign.store_id" => "self.store_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

=head2 staffs

Type: has_many

Related object: L<TestSchema::Sakila::Result::Staff>

=cut

__PACKAGE__->has_many(
  "staffs",
  "TestSchema::Sakila::Result::Staff",
  { "foreign.store_id" => "self.store_id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

=head2 manager_staff

Type: belongs_to

Related object: L<TestSchema::Sakila::Result::Staff>

=cut

t/lib/TestSchema/Three/Result/Position.pm  view on Meta::CPAN

__PACKAGE__->add_columns(
  "name"		=> { data_type => "varchar", is_nullable => 0, size => 32 },
);
__PACKAGE__->set_primary_key("name");


__PACKAGE__->has_many(
  "players",
  "TestSchema::Three::Result::Player",
  { "foreign.position" => "self.name" },
  { cascade_copy => 0, cascade_delete => 0 },
);


    
1;

t/lib/TestSchema/Three/Result/Team.pm  view on Meta::CPAN

  "id"			=> { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
  "name"			=> { data_type => "varchar", is_nullable => 0, size => 32 },
);
__PACKAGE__->set_primary_key("id");


__PACKAGE__->has_many(
  "players",
  "TestSchema::Three::Result::Player",
  { "foreign.team_id" => "self.id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

1;

t/lib/TestSchema/Two/Result/Position.pm  view on Meta::CPAN

__PACKAGE__->add_columns(
  "name"		=> { data_type => "varchar", is_nullable => 0, size => 32 },
);
__PACKAGE__->set_primary_key("name");


__PACKAGE__->has_many(
  "players",
  "TestSchema::Two::Result::Player",
  { "foreign.position" => "self.name" },
  { cascade_copy => 0, cascade_delete => 0 },
);


    
1;

t/lib/TestSchema/Two/Result/Team.pm  view on Meta::CPAN

  "id"			=> { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
  "name"			=> { data_type => "varchar", is_nullable => 0, size => 32 },
);
__PACKAGE__->set_primary_key("id");


__PACKAGE__->has_many(
  "players",
  "TestSchema::Two::Result::Player",
  { "foreign.team_id" => "self.id" },
  { cascade_copy => 0, cascade_delete => 0 },
);

1;

t/lib/TestSchema/WackyRels.pm  view on Meta::CPAN

  __PACKAGE__->table("grade");
  __PACKAGE__->add_columns(
    "letter"    => { data_type => "char", is_nullable => 0, size => 1 },
  );
  __PACKAGE__->set_primary_key("letter");
	
	__PACKAGE__->has_many(
    "things",
    "TestSchema::WackyRels::Thing",
    { "foreign.grade" => "self.letter" },
    { cascade_copy => 0, cascade_delete => 0 },
  );
};


{
  package TestSchema::WackyRels::Size;
  use base 'DBIx::Class::Core';
    
  __PACKAGE__->table("size");
  __PACKAGE__->add_columns(
    "name"    => { data_type => "char", is_nullable => 0, size => 32 },
    "detail"  => { data_type => "varchar", is_nullable => 1, size => 255 },
  );
  __PACKAGE__->set_primary_key("name");

  __PACKAGE__->has_many(
    "parents",
    "TestSchema::WackyRels::Parent",
    { "foreign.size" => "self.name" },
    { cascade_copy => 0, cascade_delete => 0 },
  );
	
	__PACKAGE__->has_many(
    "products",
    "TestSchema::WackyRels::Product",
    { "foreign.size" => "self.name" },
    { cascade_copy => 0, cascade_delete => 0 },
  );
	
	__PACKAGE__->has_many(
    "things",
    "TestSchema::WackyRels::Thing",
    { "foreign.size" => "self.name" },
    { cascade_copy => 0, cascade_delete => 0 },
  );
};

{
  package TestSchema::WackyRels::Parent;
  use base 'DBIx::Class::Core';
    
  __PACKAGE__->table("parent");
  __PACKAGE__->add_columns(
    "id"      => { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },

t/lib/TestSchema/WackyRels.pm  view on Meta::CPAN

    { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
  );

  __PACKAGE__->has_many(
    "children",
    "TestSchema::WackyRels::Child",
    { 
      "foreign.color" => "self.color",
      "foreign.size" => "self.size",
    },
    { cascade_copy => 0, cascade_delete => 0 },
  );
};

{
  package TestSchema::WackyRels::Child;
  use base 'DBIx::Class::Core';
  
  __PACKAGE__->table("child");
  __PACKAGE__->add_columns(
    "id"      => { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },



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