Merge 'trunk' into 'DBIx-Class-current'
Brandon L. Black [Tue, 17 Oct 2006 15:28:41 +0000 (15:28 +0000)]
r7941@positron (orig r2836):  castaway | 2006-10-14 12:33:13 -0500
Minor consistency, layout and grammar updates

r7942@positron (orig r2837):  castaway | 2006-10-14 14:24:15 -0500
Added examples for ResultSetColumn

r7943@positron (orig r2838):  castaway | 2006-10-14 14:41:07 -0500
Add func example for resultsetcolumn

r7944@positron (orig r2839):  castaway | 2006-10-14 14:43:52 -0500
Added resultsetcolumn question to FAQ

r7945@positron (orig r2840):  castaway | 2006-10-14 14:46:26 -0500
Fix typo

r7946@positron (orig r2841):  castaway | 2006-10-14 15:11:40 -0500
Funky hashref inflating example

r7947@positron (orig r2842):  castaway | 2006-10-14 15:21:26 -0500
Add find_or_new / in_storage example

r9870@positron (orig r2843):  dwc | 2006-10-17 02:40:56 -0500
Add (currently failing) tests for single relationship accessors with objects and for PK mutation

1  2 
lib/DBIx/Class/Manual/Cookbook.pod
lib/DBIx/Class/Manual/FAQ.pod

@@@ -72,8 -72,10 +72,10 @@@ L<SQL::Abstract/WHERE CLAUSES>
  
  =head3 Using specific columns
  
- When you only want selected columns from a table, you can use C<cols> to
- specify which ones you need:
+ When you only want specific columns from a table, you can use
+ C<columns> to specify which ones you need. This is useful to avoid
+ loading columns with large amounts of data that you aren't about to
+ use anyway:
  
    my $rs = $schema->resultset('Artist')->search(
      undef,
@@@ -85,6 -87,9 +87,9 @@@
    # Equivalent SQL:
    # SELECT artist.name FROM artist
  
+ This is a shortcut for C<select> and C<as>, see below. C<columns>
+ cannot be used together with C<select> and C<as>.
  =head3 Using database functions or stored procedures
  
  The combination of C<select> and C<as> can be used to return the result of a
@@@ -94,7 -99,7 +99,7 @@@ stored procedure name). You then use C<
  to access the returned value:
  
    my $rs = $schema->resultset('Artist')->search(
-     undef,
+     {},
      {
        select => [ 'name', { LENGTH => 'name' } ],
        as     => [qw/ name name_length /],
    # SELECT name name, LENGTH( name ) name_length
    # FROM artist
  
- If your alias exists as a column in your base class (i.e. it was added with
- C<add_columns>), you just access it as normal. Our C<Artist> class has a C<name>
- column, so we just use the C<name> accessor:
+ If your alias exists as a column in your base class (i.e. it was added
+ with C<add_columns>), you just access it as normal. Our C<Artist>
+ class has a C<name> column, so we just use the C<name> accessor:
  
    my $artist = $rs->first();
    my $name = $artist->name();
  
  If on the other hand the alias does not correspond to an existing column, you
- can get the value using the C<get_column> accessor:
+ have to fetch the value using the C<get_column> accessor:
  
    my $name_length = $artist->get_column('name_length');
  
@@@ -129,7 -134,7 +134,7 @@@ any of your aliases using either of the
  =head3 SELECT DISTINCT with multiple columns
  
    my $rs = $schema->resultset('Foo')->search(
-     undef,
+     {},
      {
        select => [
          { distinct => [ $source->columns ] }
  =head3 SELECT COUNT(DISTINCT colname)
  
    my $rs = $schema->resultset('Foo')->search(
-     undef,
+     {},
      {
        select => [
          { count => { distinct => 'colname' } }
  L<DBIx::Class> supports C<GROUP BY> as follows:
  
    my $rs = $schema->resultset('Artist')->search(
-     undef,
+     {},
      {
        join     => [qw/ cds /],
        select   => [ 'name', { count => 'cds.cdid' } ],
  
  =head3 Predefined searches
  
- You can write your own DBIx::Class::ResultSet class by inheriting from it
+ You can write your own L<DBIx::Class::ResultSet> class by inheriting from it
  and define often used searches as methods:
  
    package My::DBIC::ResultSet::CD;
@@@ -382,7 -387,7 +387,7 @@@ From 0.04999_05 onwards, C<prefetch> ca
  deep using the same syntax as a multi-step join:
  
    my $rs = $schema->resultset('Tag')->search(
-     undef,
+     {},
      {
        prefetch => {
          cd => 'artist'
@@@ -401,6 -406,55 +406,55 @@@ SQL statements
    my $tag = $rs->first;
    print $tag->cd->artist->name;
  
+ =head2 Columns of data
+ If you want to find the sum of a particular column there are several
+ ways, the obvious one is to use search:
+   my $rs = $schema->resultset('Items')->search(
+     {},
+     { 
+        select => [ { sum => 'Cost' } ],
+        as     => [ 'total_cost' ],
+     }
+   );
+   my $tc = $rs->first->get_column('total_cost');
+ Or, you can use the L<DBIx::Class::ResultSetColumn>, which gets
+ returned when you ask the C<ResultSet> for a column using
+ C<get_column>:
+   my $cost = $schema->resultset('Items')->get_column('Cost');
+   my $tc = $cost->sum;
+ With this you can also do:
+   my $minvalue = $cost->min;
+   my $maxvalue = $cost->max;
+ Or just iterate through the values of this column only:
+   while ( my $c = $cost->next ) {
+     print $c;
+   }
+   foreach my $c ($cost->all) {
+     print $c;
+   }
+ C<ResultSetColumn> only has a limited number of built-in functions, if
+ you need one that it doesn't have, then you can use the C<func> method
+ instead:
+   my $avg = $cost->func('AVERAGE');
+ This will cause the following SQL statement to be run:
+   SELECT AVERAGE(Cost) FROM Items me
+ Which will of course only work if your database supports this function.
+ See L<DBIx::Class::ResultSetColumn> for more documentation.
  =head2 Using relationships
  
  =head3 Create a new row in a related table
@@@ -433,7 -487,7 +487,7 @@@ To order C<< $book->pages >> by descend
  =head2 Transactions
  
  As of version 0.04001, there is improved transaction support in
 -L<DBIx::Class::Storage::DBI> and L<DBIx::Class::Schema>.  Here is an
 +L<DBIx::Class::Storage> and L<DBIx::Class::Schema>.  Here is an
  example of the recommended way to use it:
  
    my $genus = $schema->resultset('Genus')->find(12);
@@@ -539,7 -593,7 +593,7 @@@ For more complex stringification, you c
    use overload '""' => sub { $_[0]->name . ", " .
                               $_[0]->address }, fallback => 1;
  
- =head3 Stringifcation Example
+ =head3 Stringification Example
  
  Suppose we have two tables: C<Product> and C<Category>. The table
  specifications are:
@@@ -723,33 -777,35 +777,35 @@@ The schema update can be deployed to cu
  
  =head2 Setting limit dialect for SQL::Abstract::Limit
  
- In some cases, SQL::Abstract::Limit cannot determine the dialect of the remote
- SQL-server by looking at the database-handle. This is a common problem when
- using the DBD::JDBC, since the DBD-driver only know that in has a Java-driver
- available, not which JDBC-driver the Java component has loaded.
- This specifically sets the limit_dialect to Microsoft SQL-server (Se more names
- in SQL::Abstract::Limit -documentation.
+ In some cases, SQL::Abstract::Limit cannot determine the dialect of
+ the remote SQL server by looking at the database handle. This is a
+ common problem when using the DBD::JDBC, since the DBD-driver only
+ know that in has a Java-driver available, not which JDBC driver the
+ Java component has loaded.  This specifically sets the limit_dialect
+ to Microsoft SQL-server (See more names in SQL::Abstract::Limit
+ -documentation.
  
    __PACKAGE__->storage->sql_maker->limit_dialect('mssql');
  
- The JDBC-bridge is one way of getting access to a MSSQL-server from a platform
+ The JDBC bridge is one way of getting access to a MSSQL server from a platform
  that Microsoft doesn't deliver native client libraries for. (e.g. Linux)
  
- =head2 Setting quotes for the generated SQL. 
+ =head2 Setting quoting for the generated SQL. 
  
- If the database contains columnames with spaces and/or reserved words, the
- SQL-query needs to be quoted. This is done using:
+ If the database contains column names with spaces and/or reserved words, they
+ need to be quoted in the SQL queries. This is done using:
  
    __PACKAGE__->storage->sql_maker->quote_char([ qw/[ ]/] );
    __PACKAGE__->storage->sql_maker->name_sep('.');
  
- The first sets the quotesymbols. If the quote i "symmetric" as " or '
+ The first sets the quote characters. Either a pair of matching
+ brackets, or a C<"> or C<'>:
    
    __PACKAGE__->storage->sql_maker->quote_char('"');
  
- is enough. If the left quote differs form the right quote, the first 
- notation should be used. name_sep needs to be set to allow the 
- SQL generator to put the quotes the correct place. 
+ Check the documentation of your database for the correct quote
+ characters to use. C<name_sep> needs to be set to allow the SQL
+ generator to put the quotes the correct place.
  
  =head2 Overloading methods
  
@@@ -774,11 -830,11 +830,11 @@@ You can accomplish this by overriding C
    }
  
  Note that the hard work is done by the call to C<next::method>, which
- redispatches your call to store_column to the superclass(es).
+ redispatches your call to store_column in the superclass(es).
  
  =head3 Automatically creating related objects
  
- You might have a class C<Artist> which has many C<CD>s.  Further, you
+ You might have a class C<Artist> which has many C<CD>s.  Further, if you
  want to create a C<CD> object every time you insert an C<Artist> object.
  You can accomplish this by overriding C<insert> on your objects:
  
@@@ -838,18 -894,18 +894,18 @@@ L<Data::Dumper/EXAMPLES> for more infor
  
  =head2 Retrieving a row object's Schema
  
- It is possible to get a Schema object from a row object like so,
+ It is possible to get a Schema object from a row object like so:
  
    my $schema = $cd->result_source->schema;
-   my $artist_rs = $schema->resultset('Artist');
-            # for example
+   # use the schema as normal:
+   my $artist_rs = $schema->resultset('Artist'); 
  
  This can be useful when you don't want to pass around a Schema object to every
  method.
  
  =head2 Profiling
  
 -When you enable L<DBIx::Class::Storage::DBI>'s debugging it prints the SQL
 +When you enable L<DBIx::Class::Storage>'s debugging it prints the SQL
  executed as well as notifications of query completion and transaction
  begin/commit.  If you'd like to profile the SQL you can subclass the
  L<DBIx::Class::Storage::Statistics> class and write your own profiling
@@@ -923,19 -979,22 +979,22 @@@ not work, but then you already know th
  =head2 Dynamic Sub-classing DBIx::Class proxy classes 
  (AKA multi-class object inflation from one table) 
   
- L<DBIx::Class> classes are proxy classes, therefore some different techniques 
- need to be employed for more than basic subclassing.  In this example we have  
- a single user table that carries a boolean bit for admin.  We would like  
- like to give the admin users objects(L<DBIx::Class::Row>) the same methods as  
- a regular user but also special admin only methods.  It doesn't make sense to  
- create two seperate proxy-class files for this.  We would be copying all the  
- user methods into the Admin class.  There is a cleaner way to accomplish this. 
- Overriding the C<inflate_results()> method within the User proxy-class gives 
- us the effect we want.  This method is called by L<DBIx::Class::ResultSet> when  
- inflating a result from storage.  So we grab the object being returned, inspect 
- the values we are looking for, bless it if it's an admin object, and then  
- return it.  Running the test file below will confirm this works. 
+ L<DBIx::Class> classes are proxy classes, therefore some different
+ techniques need to be employed for more than basic subclassing.  In
+ this example we have a single user table that carries a boolean bit
+ for admin.  We would like like to give the admin users
+ objects(L<DBIx::Class::Row>) the same methods as a regular user but
+ also special admin only methods.  It doesn't make sense to create two
+ seperate proxy-class files for this.  We would be copying all the user
+ methods into the Admin class.  There is a cleaner way to accomplish
+ this.
+ Overriding the C<inflate_result> method within the User proxy-class
+ gives us the effect we want.  This method is called by
+ L<DBIx::Class::ResultSet> when inflating a result from storage.  So we
+ grab the object being returned, inspect the values we are looking for,
+ bless it if it's an admin object, and then return it.  See the example
+ below:
   
  B<Schema Definition> 
   
@@@ -957,7 -1016,7 +1016,7 @@@ B<Proxy-Class definitions
      ### Defined what our admin class is for ensure_class_loaded 
      my $admin_class = __PACKAGE__ . '::Admin'; 
       
-     __PACKAGE__->load_components(qw/PK::Auto Core/); 
+     __PACKAGE__->load_components(qw/Core/); 
       
      __PACKAGE__->table('users'); 
       
@@@ -1037,4 -1096,54 +1096,54 @@@ B<Test File> test.p
      ### The statement below will print 
      print "I can do admin stuff\n" if $admin->can('do_admin_stuff'); 
  
+ =head2 Skip object creation for faster results
+ DBIx::Class is not built for speed, it's built for convenience and
+ ease of use, but sometimes you just need to get the data, and skip the
+ fancy objects. Luckily this is also fairly easy using
+ C<inflate_result>:
+   # Define a class which just returns the results as a hashref:
+   package My::HashRefInflator;
+   ## $me is the hashref of cols/data from the immediate resultsource
+   ## $prefetch is a deep hashref of all the data from the prefetched
+   ##   related sources.
+   sub mk_hash {
+      my ($me, $rest) = @_;
+      return { %$me, 
+         map { ($_ => mk_hash(@{$rest->{$_}})) } keys %$rest } 
+      };
+   }
+   sub inflate_result {
+      my ($self, $source, $me, $prefetch) = @_;
+      return mk_hash($me, $prefetch); 
+   }
+   # Change the object inflation to a hashref for just this resultset:
+   $rs->result_class('My::HashRefInflator');
+   my $datahashref = $rs->next;
+   foreach my $col (keys $datahashref) {
+      if(!ref($datahashref->{$col}) {
+         # It's a plain value
+      }
+      elsif(ref($datahashref->{$col} eq 'HASH')) {
+         # It's a related value in a hashref
+      }
+   }
+ =head2 Want to know if find_or_create found or created a row?
+ Just use C<find_or_new> instead, then check C<in_storage>:
+   my $obj = $rs->find_or_new({ blah => 'blarg' });
+   unless ($obj->in_storage) {
+     $obj->insert;
+     # do whatever else you wanted if it was a new row
+   }
  =cut
@@@ -245,10 -245,16 +245,16 @@@ documentation
  
  =over 4
  
- =item .. fetch as much data as possible in as few select calls as possible? (prefetch)
+ =item .. fetch as much data as possible in as few select calls as possible?
  
  See the prefetch examples in the L<Cookbook|DBIx::Class::Manual::Cookbook>.
  
+ =item .. fetch a whole column of data instead of a row?
+ Call C<get_column> on a L<DBIx::Class::ResultSet>, this returns a
+ L<DBIx::Class::ResultSetColumn>, see it's documentation and the
+ L<Cookbook|DBIx::Class::Manual::Cookbook> for details.
  =back
  
  =head2 Inserting and updating data
@@@ -311,7 -317,7 +317,7 @@@ to work around this issue
  
  =item See the SQL statements my code is producing?
  
 -Turn on debugging! See L<DBIx::Class::Storage::DBI> for details of how
 +Turn on debugging! See L<DBIx::Class::Storage> for details of how
  to turn on debugging in the environment, pass your own filehandle to
  save debug to, or create your own callback.