# i.e. first release of 0.XX *must* be 0.XX000. This avoids fBSD ports
# brain damage and presumably various other packaging systems too
-$VERSION = '0.06000';
+$VERSION = '0.05999_04';
sub MODIFY_CODE_ATTRIBUTES {
my ($class,$code,@attrs) = @_;
1;
- =head1 NAME
+ =head1 NAME
DBIx::Class - Extensible and flexible object <-> relational mapper.
=head1 SYNOPSIS
-Create a schema class called DB/Main.pm:
+Create a base schema class called DB/Main.pm:
package DB::Main;
use base qw/DBIx::Class::Schema/;
1;
-Create a table class to represent artists, who have many CDs, in DB/Main/Artist.pm:
+Create a class to represent artists, who have many CDs, in DB/Main/Artist.pm:
package DB::Main::Artist;
use base qw/DBIx::Class/;
__PACKAGE__->table('artist');
__PACKAGE__->add_columns(qw/ artistid name /);
__PACKAGE__->set_primary_key('artistid');
- __PACKAGE__->has_many(cds => 'DB::Main::CD');
+ __PACKAGE__->has_many('cds' => 'DB::Main::CD');
1;
-A table class to represent a CD, which belongs to an artist, in DB/Main/CD.pm:
+A class to represent a CD, which belongs to an artist, in DB/Main/CD.pm:
package DB::Main::CD;
use base qw/DBIx::Class/;
__PACKAGE__->load_components(qw/PK::Auto Core/);
__PACKAGE__->table('cd');
- __PACKAGE__->add_columns(qw/ cdid artist title year /);
+ __PACKAGE__->add_columns(qw/ cdid artist title year/);
__PACKAGE__->set_primary_key('cdid');
- __PACKAGE__->belongs_to(artist => 'DB::Main::Artist');
+ __PACKAGE__->belongs_to('artist' => 'DB::Main::Artist');
1;
Then you can use these classes in your application's code:
# Connect to your database.
- use DB::Main;
- my $schema = DB::Main->connect($dbi_dsn, $user, $pass, \%dbi_params);
+ my $ds = DB::Main->connect(@dbi_dsn);
# Query for all artists and put them in an array,
# or retrieve them as a result set object.
- my @all_artists = $schema->resultset('Artist')->all;
- my $all_artists_rs = $schema->resultset('Artist');
+ my @all_artists = $ds->resultset('Artist')->all;
+ my $all_artists_rs = $ds->resultset('Artist');
# Create a result set to search for artists.
# This does not query the DB.
- my $johns_rs = $schema->resultset('Artist')->search(
- # Build your WHERE using an L<SQL::Abstract> structure:
- { name => { like => 'John%' } }
+ my $johns_rs = $ds->resultset('Artist')->search(
+ # Build your WHERE using an SQL::Abstract structure:
+ { 'name' => { 'like', 'John%' } }
);
- # Execute a joined query to get the cds.
+ # This executes a joined query to get the cds
my @all_john_cds = $johns_rs->search_related('cds')->all;
- # Fetch only the next row.
+ # Queries but only fetches one row so far.
my $first_john = $johns_rs->next;
- # Specify ORDER BY on the query.
my $first_john_cds_by_title_rs = $first_john->cds(
undef,
{ order_by => 'title' }
);
- # Create a result set that will fetch the artist relationship
- # at the same time as it fetches CDs, using only one query.
- my $millennium_cds_rs = $schema->resultset('CD')->search(
+ my $millennium_cds_rs = $ds->resultset('CD')->search(
{ year => 2000 },
{ prefetch => 'artist' }
);
my $cd = $millennium_cds_rs->next; # SELECT ... FROM cds JOIN artists ...
my $cd_artist_name = $cd->artist->name; # Already has the data so no query
- my $new_cd = $schema->resultset('CD')->new({ title => 'Spoon' });
+ my $new_cd = $ds->resultset('CD')->new({ title => 'Spoon' });
$new_cd->artist($cd->artist);
$new_cd->insert; # Auto-increment primary key filled in after INSERT
$new_cd->title('Fork');
- $schema->txn_do(sub { $new_cd->update }); # Runs the update in a transaction
+ $ds->txn_do(sub { $new_cd->update }); # Runs the update in a transaction
$millennium_cds_rs->update({ year => 2002 }); # Single-query bulk update
DBIx::Class can handle multi-column primary and foreign keys, complex
queries and database-level paging, and does its best to only query the
-database in order to return something you've directly asked for. If a
-resultset is used as an iterator it only fetches rows off the statement
-handle as requested in order to minimise memory usage. It has auto-increment
-support for SQLite, MySQL, PostgreSQL, Oracle, SQL Server and DB2 and is
-known to be used in production on at least the first four, and is fork-
-and thread-safe out of the box (although your DBD may not be).
+database when it actually needs to in order to return something you've directly
+asked for. If a resultset is used as an iterator it only fetches rows off
+the statement handle as requested in order to minimise memory usage. It
+has auto-increment support for SQLite, MySQL, PostgreSQL, Oracle, SQL
+Server and DB2 and is known to be used in production on at least the first
+four, and is fork- and thread-safe out of the box (although your DBD may not
+be).
This project is still under rapid development, so features added in the
-latest major release may not work 100% yet -- check the Changes if you run
+latest major release may not work 100% yet - check the Changes if you run
into trouble, and beware of anything explicitly marked EXPERIMENTAL. Failing
test cases are *always* welcome and point releases are put out rapidly as
bugs are found and fixed.
Even so, we do our best to maintain full backwards compatibility for published
-APIs, since DBIx::Class is used in production in a number of organisations.
-The test suite is quite substantial, and several developer releases are
+APIs since DBIx::Class is used in production in a number of organisations;
+the test suite is now fairly substantial and several developer releases are
generally made to CPAN before the -current branch is merged back to trunk for
a major release.
-The community can be found via:
+The community can be found via -
Mailing list: http://lists.rawmode.org/mailman/listinfo/dbix-class/
#DBIx::Class::ObjIndexStubs
1;
- =head1 NAME
+ =head1 NAME
DBIx::Class::CDBICompat - Class::DBI Compatibility layer.
DBIx::Class features a fully featured compatibility layer with L<Class::DBI>
to ease transition for existing CDBI users. In fact, this class is just a
receipe containing all the features emulated. If you like, you can choose
- which features to emulate by building your own class and loading it like
+ which features to emulate by building your own class and loading it like
this:
__PACKAGE__->load_own_components(qw/CDBICompat/);
- this will automatically load the features included in My::DB::CDBICompat,
+ this will automatically load the features included in My::DB::CDBICompat,
provided it looks something like this:
package My::DB::CDBICompat;
CDBICompat::MightHave
/);
-=head1 COMPONENTS
+=head1 Components
=over 4
=item HasA
+Responsible for HasA relationships.
+
=item HasMany
+Responsible for HasMany relationships.
+
=item ImaDBI
=item LazyLoading
=item MightHave
+Responsible for MightHave relationships.
+
=item ObjIndexStubs
=item ReadOnly
=item Triggers
+This class implements the trigger functionality.
+
=item PassThrough
=back
1;
- =head1 NAME
+ =head1 NAME
DBIx::Class::Core - Core set of DBIx::Class modules
=over 4
-=item L<DBIx::Class::Serialize::Storable>
-
=item L<DBIx::Class::InflateColumn>
=item L<DBIx::Class::Relationship>
use base qw/DBIx::Class/;
- =head1 NAME
+ =head1 NAME
DBIx::Class::Relationship::Base - Inter-table relationships
This class provides methods to describe the relationships between the
tables in your database model. These are the "bare bones" relationships
- methods, for predefined ones, look in L<DBIx::Class::Relationship>.
+ methods, for predefined ones, look in L<DBIx::Class::Relationship>.
=head1 METHODS
=over 4
-=item Arguments: 'relname', 'Foreign::Class', $cond, $attrs
+=item Arguments: ('relname', 'Foreign::Class', $cond, $attrs)
=back
=over 4
-=item Arguments: $relname, $rel_info
+=item Arguments: ($relname, $rel_info)
=back
=over 4
-=item Arguments: $relationship_name
+=item Arguments: ($relationship_name)
-=item Return Value: $related_resultset
+=item Returns: $related_resultset
=back
=head1 METHODS
- =head2 new
+ =head2 new
=over 4
=item Return Value: $rs
+=item
+
=back
The resultset constructor. Takes a source object (usually a
# year = 2005 OR year = 2004
If you need to pass in additional attributes but no additional condition,
-call it as C<search(undef, \%attrs)>.
+call it as C<search(undef, \%attrs);>.
# "SELECT name, artistid FROM $artist_table"
my @all_artists = $schema->resultset('Artist')->search(undef, {
=over 4
-=item Arguments: @values | \%cols, \%attrs?
+=item Arguments: (@values | \%cols), \%attrs?
=item Return Value: $row_object
return keys %{$rs->{collapse}} ? $rs->next : $rs->single;
} else {
return keys %{$self->{collapse}} ?
- $self->search($query)->next :
- $self->single($query);
+ $self->search($query)->next :
+ $self->single($query);
}
}
name => 'Emo-R-Us',
});
-Searches the specified relationship, optionally specifying a condition and
+Search the specified relationship, optionally specify a condition and
attributes for matching records. See L</ATTRIBUTES> for more information.
=cut
if ($where) {
if (defined $attrs->{where}) {
$attrs->{where} = {
- '-and' =>
+ '-and' =>
[ map { ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_ }
$where, delete $attrs->{where} ]
};
# WHERE title LIKE '%blue%'
$cd_rs = $rs->search_like({ title => '%blue%'});
-Performs a search, but uses C<LIKE> instead of C<=> as the condition. Note
+Perform a search, but use C<LIKE> instead of C<=> as the condition. Note
that this is simply a convenience method. You most likely want to use
L</search> with specific operators.
=back
Returns a resultset or object list representing a subset of elements from the
-resultset slice is called on. Indexes are from 0, i.e., to get the first
-three records, call:
+resultset slice is called on. Indexes are from 0 - i.e. to get the first
+three records, call
my ($one, $two, $three) = $rs->slice(0, 2);
return ($self->all)[0];
}
my @row = (exists $self->{stashed_row} ?
- @{delete $self->{stashed_row}} :
- $self->cursor->next
+ @{delete $self->{stashed_row}} :
+ $self->cursor->next
);
# warn Dumper(\@row); use Data::Dumper;
return unless (@row);
my @collapse;
if (defined $prefix) {
@collapse = map {
- m/^\Q${prefix}.\E(.+)$/ ? ($1) : ()
+ m/^\Q${prefix}.\E(.+)$/ ? ($1) : ()
} keys %{$self->{collapse}}
} else {
@collapse = keys %{$self->{collapse}};
my (@final, @raw);
while ( !(grep {
!defined($tree->[0]->{$_}) ||
- $co_check{$_} ne $tree->[0]->{$_}
+ $co_check{$_} ne $tree->[0]->{$_}
} @co_key) ) {
push(@final, $tree);
last unless (@raw = $self->cursor->next);
=over 4
-=item Arguments: $cond, \%attrs??
+=item Arguments: ($cond, \%attrs?)?
=item Return Value: $count
@distinct = ($column);
last;
}
- }
+ }
}
$select = { count => { distinct => \@distinct } };
=back
Resets the resultset and returns an object for the first result (if the
-resultset returns anything).
+resultset contains anything).
=cut
=back
-Fetches all objects and updates them one at a time. Note that C<update_all>
-will run DBIC cascade triggers, while L</update> will not.
+Fetches all objects and updates them one at a time. Note that C<update_all>
+will run cascade triggers while L</update> will not.
=cut
=back
Deletes the contents of the resultset from its result source. Note that this
-will not run DBIC cascade triggers. See L</delete_all> if you need triggers
-to run.
+will not run cascade triggers. See L</delete_all> if you need triggers to run.
=cut
=back
-Fetches all objects and deletes them one at a time. Note that C<delete_all>
-will run DBIC cascade triggers, while L</delete> will not.
+Fetches all objects and deletes them one at a time. Note that C<delete_all>
+will run cascade triggers while L</delete> will not.
=cut
Returns a resultset for the $page_number page of the resultset on which page
is called, where each page contains a number of rows equal to the 'rows'
-attribute set on the resultset (10 by default).
+attribute set on the resultset, or 10 by default
=cut
$class->update_or_create({ col => $val, ... });
-First, searches for an existing row matching one of the unique constraints
-(including the primary key) on the source of this resultset. If a row is
-found, updates it with the other given column values. Otherwise, creates a new
+First, search for an existing row matching one of the unique constraints
+(including the primary key) on the source of this resultset. If a row is
+found, update it with the other given column values. Otherwise, create a new
row.
Takes an optional C<key> attribute to search on a specific unique constraint.
If no C<key> is specified, it searches on all unique constraints defined on the
source, including the primary key.
-If the C<key> is specified as C<primary>, it searches only on the primary key.
+If the C<key> is specified as C<primary>, search only on the primary key.
See also L</find> and L</find_or_create>.
=back
-Gets the contents of the cache for the resultset, if the cache is set.
+Gets the contents of the cache for the resultset if the cache is set
=cut
=item Value: ($order_by | \@order_by)
-=back
-
Which column(s) to order the results by. This is currently passed
through directly to SQL, so you can give e.g. C<year DESC> for a
descending order on the column `year'.
=back
- Contains one or more relationships that should be fetched along with the main
+ Contains one or more relationships that should be fetched along with the main
query (when they are accessed afterwards they will have already been
"prefetched"). This is useful for when you know you will need the related
objects, because it saves at least one query:
... do stuff ...
}
- $rs->first; # without cache, this would issue a query
+ $rs->first; # without cache, this would issue a query
By default, searches are not cached.
__PACKAGE__->mk_group_accessors('component_class' => qw/resultset_class
result_class/);
- =head1 NAME
+ =head1 NAME
DBIx::Class::ResultSource - Result source object
$table->add_columns('col1' => \%col1_info, 'col2' => \%col2_info, ...);
-Adds columns to the result source. If supplied key => hashref pairs, uses
-the hashref as the column_info for that column. Repeated calls of this
-method will add more columns, not replace them.
+Adds columns to the result source. If supplied key => hashref pairs uses
+the hashref as the column_info for that column.
-The contents of the column_info are not set in stone. The following
-keys are currently recognised/used by DBIx::Class:
+Repeated calls of this method will add more columns, not replace them.
+
+The contents of the column_info are not set in stone, the following
+keys are currently recognised/used by DBIx::Class.
=over 4
- =item accessor
+ =item accessor
Use this to set the name of the accessor for this column. If unset,
the name of the column will be used.
=item data_type
-This contains the column type. It is automatically filled by the
+This contains the column type, it is automatically filled by the
L<SQL::Translator::Producer::DBIx::Class::File> producer, and the
-L<DBIx::Class::Schema::Loader> module. If you do not enter a
+L<DBIx::Class::Schema::Loader> module. If you do not enter the
data_type, DBIx::Class will attempt to retrieve it from the
-database for you, using L<DBI>'s column_info method. The values of this
+database for you, using L<DBI>s column_info method. The values of this
key are typically upper-cased.
-Currently there is no standard set of values for the data_type. Use
-whatever your database supports.
+Currently there is no standard set of values for the data_type, use
+whatever your database(s) support.
=item size
The length of your column, if it is a column type that can have a size
- restriction. This is currently not used by DBIx::Class.
+ restriction. This is currently not used by DBIx::Class.
=item is_nullable
-Set this to a true value for a columns that is allowed to contain
-NULL values. This is currently not used by DBIx::Class.
+If the column is allowed to contain NULL values, set a true value
+(typically 1), here. This is currently not used by DBIx::Class.
=item is_auto_increment
-Set this to a true value for a column whose value is somehow
-automatically set. This is used to determine which columns to empty
+Set this to a true value if this is a column that is somehow
+automatically filled. This is used to determine which columns to empty
when cloning objects using C<copy>.
=item is_foreign_key
-Set this to a true value for a column that contains a key from a
+Set this to a true value if this column represents a key from a
foreign table. This is currently not used by DBIx::Class.
=item default_value
-Set this to the default value which will be inserted into a column
-by the database. Can contain either a value or a function. This is
+Set this to the default value which will be inserted into this column
+by the database. Can contain either values or functions. This is
- currently not used by DBIx::Class.
+ currently not used by DBIx::Class.
=item sequence
-Set this on a primary key column to the name of the sequence used to
-generate a new key value. If not specified, L<DBIx::Class::PK::Auto>
-will attempt to retrieve the name of the sequence from the database
-automatically.
+Sets the name of the sequence to use to generate values. If not
+specified, L<DBIx::Class::PK::Auto> will attempt to retrieve the
+name of the sequence from the database automatically.
=back
$table->add_column('col' => \%info?);
-Convenience alias to add_columns.
+Convenience alias to add_columns
=cut
if ($obj->has_column($col)) { ... }
-Returns true if the source has a column of this name, false otherwise.
+Returns 1 if the source has a column of this name, 0 otherwise.
=cut
sub column_info {
my ($self, $column) = @_;
- $self->throw_exception("No such column $column")
+ $self->throw_exception("No such column $column")
unless exists $self->_columns->{$column};
#warn $self->{_columns_info_loaded}, "\n";
- if ( ! $self->_columns->{$column}{data_type}
- and ! $self->{_columns_info_loaded}
+ if ( ! $self->_columns->{$column}{data_type}
+ and ! $self->{_columns_info_loaded}
and $self->schema and $self->storage )
{
$self->{_columns_info_loaded}++;
my $info;
- # eval for the case of storage without table
+ # eval for the case of storage without table
eval { $info = $self->storage->columns_info_for($self->from) };
unless ($@) {
foreach my $col ( keys %{$self->_columns} ) {
my @column_names = $obj->columns;
-Returns all column names in the order they were declared to add_columns.
+Returns all column names in the order they were declared to add_columns
=cut
=over 4
-=item Arguments: @cols
+=item Arguments: (@cols)
=back
Additionally, defines a unique constraint named C<primary>.
The primary key columns are used by L<DBIx::Class::PK::Auto> to
- retrieve automatically created values from the database.
+ retrieve automatically created values from the database.
=cut
Declare a unique constraint on this source. Call once for each unique
constraint. Unique constraints are used when you call C<find> on a
-L<DBIx::Class::ResultSet>. Only columns in the constraint are searched,
-for example:
+L<DBIx::Class::ResultSet>, only columns in the constraint are searched,
+
+e.g.,
# For UNIQUE (column1, column2)
__PACKAGE__->add_unique_constraint(
=head2 from
Returns an expression of the source to be supplied to storage to specify
-retrieval from this source. In the case of a database, the required FROM
-clause contents.
+retrieval from this source; in the case of a database the required FROM clause
+contents.
=cut
=head2 storage
- Returns the storage handle for the current schema.
+ Returns the storage handle for the current schema.
See also: L<DBIx::Class::Storage>
'foreign.book_id' => 'self.id',
});
-The condition C<$cond> needs to be an L<SQL::Abstract>-style
+The condition C<$cond> needs to be an SQL::Abstract-style
representation of the join between the tables. For example, if you're
creating a rel from Author to Book,
Then, assuming LinerNotes has an accessor named notes, you can do:
my $cd = CD->find(1);
- # set notes -- LinerNotes object is created if it doesn't exist
- $cd->notes('Notes go here');
+ $cd->notes('Notes go here'); # set notes -- LinerNotes object is
+ # created if it doesn't exist
=item accessor
Specifies the type of accessor that should be created for the
- relationship. Valid values are C<single> (for when there is only a single
- related object), C<multi> (when there can be many), and C<filter> (for
- when there is a single related object, but you also want the relationship
- accessor to double as a column accessor). For C<multi> accessors, an
- add_to_* method is also created, which calls C<create_related> for the
+ relationship. Valid values are C<single> (for when there is only a single
+ related object), C<multi> (when there can be many), and C<filter> (for
+ when there is a single related object, but you also want the relationship
+ accessor to double as a column accessor). For C<multi> accessors, an
+ add_to_* method is also created, which calls C<create_related> for the
relationship.
=back
eval { $self->resolve_join($rel, 'me') };
if ($@) { # If the resolve failed, back out and re-throw the error
- delete $rels{$rel}; #
+ delete $rels{$rel}; #
$self->_relationships(\%rels);
$self->throw_exception("Error creating relationship $rel: $@");
}
=head2 relationships
-Returns all relationship names for this source.
+Returns all valid relationship names for this source
=cut
=over 4
-=item Arguments: $relname
+=item Arguments: ($relname)
=back
-Returns a hash of relationship information for the specified relationship
-name.
+Returns the relationship information for the specified relationship name
=cut
sub relationship_info {
my ($self, $rel) = @_;
return $self->_relationships->{$rel};
- }
+ }
=head2 has_relationship
=over 4
-=item Arguments: $rel
+=item Arguments: ($rel)
=back
-Returns true if the source has a relationship of this name, false otherwise.
+Returns 1 if the source has a relationship of this name, 0 otherwise.
=cut
=over 4
-=item Arguments: $relation
+=item Arguments: ($relation)
=back
-Returns the join structure required for the related result source.
+Returns the join structure required for the related result source
=cut
=over 4
-=item Arguments: $cond, $as, $alias|$object
+=item Arguments: ($cond, $as, $alias|$object)
=back
while (my ($k, $v) = each %{$cond}) {
# XXX should probably check these are valid columns
$k =~ s/^foreign\.// ||
- $self->throw_exception("Invalid rel cond key ${k}");
+ $self->throw_exception("Invalid rel cond key ${k}");
$v =~ s/^self\.// ||
- $self->throw_exception("Invalid rel cond val ${v}");
+ $self->throw_exception("Invalid rel cond val ${v}");
if (ref $for) { # Object
#warn "$self $k $for $v";
$ret{$k} = $for->get_column($v);
=over 4
-=item Arguments: hashref/arrayref/scalar
+=item Arguments: (hashref/arrayref/scalar)
=back
# 'artist.name',
# 'producer.producerid',
# 'producer.name'
- #)
+ #)
=cut
=over 4
-=item Arguments: $relname
+=item Arguments: ($relname)
=back
-Returns the result source object for the given relationship.
+Returns the result source object for the given relationship
=cut
=over 4
-=item Arguments: $relname
+=item Arguments: ($relname)
=back
-Returns the class name for objects in the given relationship.
+Returns the class object for the given relationship
=cut
=head2 throw_exception
-See L<DBIx::Class::Schema/"throw_exception">.
+See throw_exception in L<DBIx::Class::Schema>.
=cut
sub throw_exception {
my $self = shift;
- if (defined $self->schema) {
+ if (defined $self->schema) {
$self->schema->throw_exception(@_);
} else {
croak(@_);
}
}
+
=head1 AUTHORS
Matt S. Trout <mst@shadowcatsystems.co.uk>
__PACKAGE__->mk_group_accessors('simple' => 'result_source');
- =head1 NAME
+ =head1 NAME
DBIx::Class::Row - Basic row methods
unless ref($attrs) eq 'HASH';
while (my ($k, $v) = each %$attrs) {
$new->throw_exception("No such column $k on $class")
- unless $class->has_column($k);
+ unless $class->has_column($k);
$new->store_column($k => $v);
}
}
$obj->delete
- Deletes the object from the database. The object is still perfectly usable,
- but ->in_storage() will now return 0 and the object must re inserted using
+ Deletes the object from the database. The object is still perfectly usable,
+ but ->in_storage() will now return 0 and the object must re inserted using
->insert() before ->update() can be used on it.
=cut
$self->throw_exception("Cannot safely delete a row in a PK-less table")
if ! keys %$ident_cond;
foreach my $column (keys %$ident_cond) {
- $self->throw_exception("Can't delete the object unless it has loaded the primary keys")
- unless exists $self->{_column_data}{$column};
+ $self->throw_exception("Can't delete the object unless it has loaded the primary keys")
+ unless exists $self->{_column_data}{$column};
}
$self->result_source->storage->delete(
$self->result_source->from, $ident_cond);
sub store_column {
my ($self, $column, $value) = @_;
- $self->throw_exception( "No such column '${column}'" )
+ $self->throw_exception( "No such column '${column}'" )
unless exists $self->{_column_data}{$column} || $self->has_column($column);
- $self->throw_exception( "set_column called for ${column} without value" )
+ $self->throw_exception( "set_column called for ${column} without value" )
if @_ < 3;
return $self->{_column_data}{$column} = $value;
}
if (ref($pre_val->[0]) eq 'ARRAY') { # multi
my @pre_objects;
foreach my $pre_rec (@$pre_val) {
- unless ($pre_source->primary_columns == grep { exists $pre_rec->[0]{$_}
+ unless ($pre_source->primary_columns == grep { exists $pre_rec->[0]{$_}
and defined $pre_rec->[0]{$_} } $pre_source->primary_columns) {
next;
}
$new->related_resultset($pre)->set_cache(\@pre_objects);
} elsif (defined $pre_val->[0]) {
my $fetched;
- unless ($pre_source->primary_columns == grep { exists $pre_val->[0]{$_}
+ unless ($pre_source->primary_columns == grep { exists $pre_val->[0]{$_}
and !defined $pre_val->[0]{$_} } $pre_source->primary_columns)
{
$fetched = $pre_source->result_class->inflate_result(
- $pre_source, @{$pre_val});
+ $pre_source, @{$pre_val});
}
my $accessor = $source->relationship_info($pre)->{attrs}{accessor};
$class->throw_exception("No accessor for prefetched $pre")
=over 4
-=item Arguments: $column, $column_info
+=item Arguments: ($column, $column_info)
=back
with your classes.
NB: If you're used to L<Class::DBI> it's worth reading the L</SYNOPSIS>
-carefully, as DBIx::Class does things a little differently. Note in
+carefully as DBIx::Class does things a little differently. Note in
particular which module inherits off which.
=head1 METHODS
=over 4
-=item Arguments: $moniker, $component_class
+=item Arguments: ($moniker, $component_class)
=back
Registers a class which isa L<DBIx::Class::ResultSourceProxy>. Equivalent to
-calling:
+calling
$schema->register_source($moniker, $component_class->result_source_instance);
=over 4
-=item Arguments: $moniker, $result_source
+=item Arguments: ($moniker, $result_source)
=back
$map{$source->result_class} = $moniker;
$self->class_mappings(\%map);
}
- }
+ }
=head2 class
=over 4
-=item Arguments: $moniker
+=item Arguments: ($moniker)
-=item Return Value: $classname
+=item Returns: $classname
=back
-Retrieves the result class name for the given moniker. For example:
+Retrieves the result class name for the given moniker.
+
+e.g.,
my $class = $schema->class('CD');
=over 4
-=item Arguments: $moniker
+=item Arguments: ($moniker)
-=item Return Value: $result_source
+=item Returns: $result_source
=back
=over 4
-=item Return Value: @source_monikers
+=item Returns: @source_monikers
=back
Returns the source monikers of all source registrations on this schema.
-For example:
+
+e.g.,
my @source_monikers = $schema->sources;
=over 4
-=item Arguments: $moniker
+=item Arguments: ($moniker)
-=item Return Value: $result_set
+=item Returns: $result_set
=back
the schema's namespace. Otherwise, this method loads the classes you specify
(using L<use>), and registers them (using L</"register_class">).
-It is possible to comment out classes with a leading C<#>, but note that perl
-will think it's a mistake (trying to use a comment in a qw list), so you'll
-need to add C<no warnings 'qw';> before your load_classes call.
+It is possible to comment out classes with a leading '#', but note that perl
+will think it's a mistake (trying to use a comment in a qw list) so you'll
+need to add "no warnings 'qw';" before your load_classes call.
-Example:
+e.g.,
My::Schema->load_classes(); # loads My::Schema::CD, My::Schema::Artist,
- # etc. (anything under the My::Schema namespace)
+ # etc. (anything under the My::Schema namespace)
# loads My::Schema::CD, My::Schema::Artist, Other::Namespace::Producer but
# not Other::Namespace::LinerNotes nor My::Schema::Track
my $comp_class = "${prefix}::${comp}";
eval "use $comp_class"; # If it fails, assume the user fixed it
if ($@) {
- $comp_class =~ s/::/\//g;
+ $comp_class =~ s/::/\//g;
die $@ unless $@ =~ /Can't locate.+$comp_class\.pm\sin\s\@INC/;
- warn $@ if $@;
+ warn $@ if $@;
}
push(@to_register, [ $comp, $comp_class ]);
}
=over 4
-=item Arguments: $target_namespace, @db_info
+=item Arguments: ($target_namespace, @db_info)
-=item Return Value: $new_schema
+=item Returns: $new_schema
=back
-Calls L<DBIx::Class::Schema/"compose_namespace"> to the target namespace,
-calls L<DBIx::Class::Schema/connection> with @db_info on the new schema,
-then injects the L<DBix::Class::ResultSetProxy> component and a
-resultset_instance classdata entry on all the new classes, in order to support
+Calls L<DBIx::Class::schema/"compose_namespace"> to the target namespace,
+calls L<DBIx::Class::Schema/connection>(@db_info) on the new schema, then
+injects the L<DBix::Class::ResultSetProxy> component and a resultset_instance
+classdata entry on all the new classes in order to support
$target_namespaces::$class->search(...) method calls.
This is primarily useful when you have a specific need for class method access
=item Arguments: $target_namespace, $additional_base_class?
-=item Return Value: $new_schema
+=item Returns: $new_schema
=back
classes will inherit from first the corresponding classe from the current
schema then the base class.
-For example, for a schema with My::Schema::CD and My::Schema::Artist classes,
+e.g. (for a schema with My::Schema::CD and My::Schema::Artist classes),
$schema->compose_namespace('My::DB', 'Base::Class');
print join (', ', @My::DB::CD::ISA) . "\n";
print join (', ', @My::DB::Artist::ISA) ."\n";
-will produce the output
+Will produce the output
My::Schema::CD, Base::Class
My::Schema::Artist, Base::Class
=over 4
-=item Arguments: $target, @info
+=item Arguments: ($target, @info)
=back
=over 4
-=item Arguments: @args
+=item Arguments: (@args)
-=item Return Value: $new_schema
+=item Returns: $new_schema
=back
=over 4
-=item Arguments: @info
+=item Arguments: (@info)
-=item Return Value: $new_schema
+=item Returns: $new_schema
=back
=over 4
-=item Arguments: C<$coderef>, @coderef_args?
+=item Arguments: (C<$coderef>, @coderef_args?)
-=item Return Value: The return value of $coderef
+=item Returns: The return value of $coderef
=back
$self->txn_begin; # If this throws an exception, no rollback is needed
my $wantarray = wantarray; # Need to save this since the context
- # inside the eval{} block is independent
- # of the context that called txn_do()
+ # inside the eval{} block is independent
+ # of the context that called txn_do()
eval {
# Need to differentiate between scalar/list context to allow for
my $rollback_error = $@;
my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
$self->throw_exception($error) # propagate nested rollback
- if $rollback_error =~ /$exception_class/;
+ if $rollback_error =~ /$exception_class/;
$self->throw_exception(
"Transaction aborted: $error. Rollback failed: ${rollback_error}"
=over 4
-=item Return Value: $new_schema
+=item Returns: $new_schema
=back
=over 4
-=item Arguments: $moniker, \@data;
+=item Arguments: ($moniker, \@data);
=back
=head2 throw_exception
- =over 4
+ =over 4
-=item Arguments: $message
+=item Arguments: ($message)
=back
=over 4
-=item Arguments: $sqlt_args
+=item Arguments: ($sqlt_args)
=back
__END__
- =head1 NAME
+ =head1 NAME
DBIx::Class::Serialize::Storable - hooks for Storable freeze/thaw
+ (EXPERIMENTAL)
=head1 SYNOPSIS
# meanwhile, in a nearby piece of code
my $cd = $schema->resultset('CD')->find(12);
- # if the cache uses Storable, this will work automatically
- $cache->set($cd->ID, $cd);
+ $cache->set($cd->ID, $cd); # if the cache uses Storable, this
+ # will work automatically
=head1 DESCRIPTION
This component adds hooks for Storable so that row objects can be
serialized. It assumes that your row object class (C<result_class>) is
-the same as your table class, which is the normal situation.
+the same as your table class, which is the normal situation. However,
+this code is not yet well tested, and so should be considered
+experimental.
=head1 AUTHORS
__PACKAGE__->load_components(qw/AccessorGroup/);
__PACKAGE__->mk_group_accessors('simple' =>
- qw/connect_info _dbh _sql_maker _conn_pid _conn_tid debug debugfh
+ qw/_connect_info _dbh _sql_maker _conn_pid _conn_tid debug debugfh
cursor on_connect_do transaction_depth/);
sub new {
croak($msg);
}
- =head1 NAME
+ =head1 NAME
DBIx::Class::Storage::DBI - DBI storage handler
=cut
+=head2 connect_info
+
+Connection information arrayref. Can either be the same arguments
+one would pass to DBI->connect, or a code-reference which returns
+a connected database handle. In either case, there is an optional
+final element in the arrayref, which can hold a hashref of
+connection-specific Storage::DBI options. These include
+C<on_connect_do>, and the sql_maker options C<limit_dialect>,
+C<quote_char>, and C<name_sep>. Examples:
+
+ ->connect_info([ 'dbi:SQLite:./foo.db' ]);
+ ->connect_info(sub { DBI->connect(...) });
+ ->connect_info([ 'dbi:Pg:dbname=foo',
+ 'postgres',
+ '',
+ { AutoCommit => 0 },
+ { quote_char => q{`}, name_sep => q{@} },
+ ]);
+
=head2 on_connect_do
Executes the sql statements given as a listref on every db connect.
return $self->_sql_maker;
}
+sub connect_info {
+ my ($self, $info_arg) = @_;
+
+ if($info_arg) {
+ my $info = [ @$info_arg ]; # copy because we can alter it
+ my $last_info = $info->[-1];
+ if(ref $last_info eq 'HASH') {
+ my $used;
+ if(my $on_connect_do = $last_info->{on_connect_do}) {
+ $used = 1;
+ $self->on_connect_do($self->{on_connect_do});
+ }
+ foreach my $sql_maker_opt (qw/limit_dialect quote_char name_sep/) {
+ if(my $opt_val = $last_info->{$sql_maker_opt}) {
+ $used = 1;
+ $self->sql_maker->$sql_maker_opt($opt_val);
+ }
+ }
+
+ # remove our options hashref if it was there, to avoid confusing
+ # DBI in the case the user didn't use all 4 DBI options, as in:
+ # [ 'dbi:SQLite:foo.db', { quote_char => q{`} } ]
+ pop(@$info) if $used;
+ }
+
+ $self->_connect_info($info);
+ }
+
+ $self->_connect_info;
+}
+
sub _populate_dbh {
my ($self) = @_;
- my @info = @{$self->connect_info || []};
+ my @info = @{$self->_connect_info || []};
$self->_dbh($self->_connect(@info));
my $driver = $self->_dbh->{Driver}->{Name};
eval "require DBIx::Class::Storage::DBI::${driver}";
$self->dbh->commit unless $self->dbh->{AutoCommit};
}
else {
- $self->dbh->commit if --$self->{transaction_depth} == 0;
+ $self->dbh->commit if --$self->{transaction_depth} == 0;
}
}
$self->throw_exception("no sth generated via sql: $sql") unless $sth;
@bind = map { ref $_ ? ''.$_ : $_ } @bind; # stringify args
my $rv;
- if ($sth) {
+ if ($sth) {
$rv = $sth->execute(@bind)
or $self->throw_exception("Error executing '$sql': " . $sth->errstr);
- } else {
+ } else {
$self->throw_exception("'$sql' did not generate a statement.");
}
return (wantarray ? ($rv, $sth, @bind) : $rv);
eval "use SQL::Translator";
$self->throw_exception("Can't deploy without SQL::Translator: $@") if $@;
eval "use SQL::Translator::Parser::DBIx::Class;";
- $self->throw_exception($@) if $@;
+ $self->throw_exception($@) if $@;
eval "use SQL::Translator::Producer::${type};";
$self->throw_exception($@) if $@;
my $tr = SQL::Translator->new(%$sqltargs);
foreach(split(";\n", @statements)) {
$self->debugfh->print("$_\n") if $self->debug;
$self->dbh->do($_) or warn "SQL was:\n $_";
- }
+ }
}
sub DESTROY { shift->disconnect }