Notes and updates based on riba's most recent comments
Jess Robinson [Wed, 7 Mar 2012 18:03:26 +0000 (18:03 +0000)]
lib/DBIx/Class/Manual/SQLHackers/CREATE.pod
lib/DBIx/Class/Manual/SQLHackers/DELETE.pod
lib/DBIx/Class/Manual/SQLHackers/INSERT.pod
lib/DBIx/Class/Manual/SQLHackers/Introduction.pod
lib/DBIx/Class/Manual/SQLHackers/SELECT.pod
lib/DBIx/Class/Manual/SQLHackers/UPDATE.pod

index 7220b5d..7601a74 100644 (file)
@@ -24,16 +24,20 @@ DBIx::Class::Manual::SQLHackers::CREATE - DBIx::Class for SQL Hackers - CREATE
 
 =head1 Database structure
 
-### complete paragraph rewording suggestion
-###
-To use DBIx::Class, we need to teach it about the layout of the underlying database. Several methods of doing this are available.
-If you have an existing database the most straightforward way is to use the module L<DBIx::Class::Schema::Loader>, which
-will introspect your database and generate individual classes representing every table and view in your database.
-For new projects one usually writes these classes by hand as described below. If you find the methods provided by
-L<DBIx::Class> core overly verbose, you can try to define your result classes via the more concise syntax of
-L<DBIx::Class::Candy> (the result is fully compatible with L<DBIx::Class>).
-
-Once a DBIx::Class schema (set of classes describing the database) has been created, built-in methods can be used to export it as SQL DDL using L<SQL::Translator>.
+To use DBIx::Class, we need to teach it about the layout of the
+underlying database. Several methods of doing this are available.  If
+you have an existing database the most straightforward way is to use
+the module L<DBIx::Class::Schema::Loader>, which will introspect your
+database and generate individual classes representing every table and
+view in your database.  For new projects one usually writes these
+classes by hand as described below. If you find the methods provided
+by L<DBIx::Class> core overly verbose, you can try to define your
+result classes via the more concise syntax of L<DBIx::Class::Candy>
+(the result is fully compatible with L<DBIx::Class>).
+
+Once a DBIx::Class schema (set of classes describing the database) has
+been created, built-in methods can be used to export it as SQL DDL
+using L<SQL::Translator>.
 
 =head2 Using Loader 
 
@@ -50,6 +54,7 @@ Run the included L<dbicdump> script.
 =head2 Manual Result class creation (and understanding Loader results)
 
 # note - CREATE INDEX is a bitch these days (requires a deploy hook) - perhaps not mentioning it at all is wise-ish?
+# Leaving in as it is possible, and anyway the only index I mentioned so far below was a unique one (really should add the deploy hook stuff, this is about describing the possible, not the simple)
 This section covers the common and oft used CREATE DDL statements that DBIx::Class can replaces with Perl classes: B<CREATE TABLE>, B<CREATE VIEW> and B<CREATE INDEX>. The classes can be used to write the actual SQL DDL to the database or disc, if required.
 
 =head3 CREATE TABLE
@@ -103,6 +108,7 @@ The recommended version:
 The fully descriptive version is required if you want to have DBIx::Class create your CREATE TABLE sql for you later. Many DBIC components also use settings in the column info hashrefs to decide how to treat the data for those columns.
 
 # perhaps "... with declared relations / Declaring relationships" ? "references" doesn't sound right in the context imho
+# in SQL land a relation == a table, since I'm talking to SQL heads I don't want to get that wrong.
 =head4 Table creation with references:
 
 A relational database isn't worth much if we don't actually use references and constraints, so here is an example which constrains the B<user_id> column to only contain B<id> values from the *users* table.
@@ -227,6 +233,8 @@ To add extra unique indexes, add the B<add_unique_constraint> call to your Resul
 
     __PACKAGE__->add_unique_constraint('username_idx' => ['username']);
 
+## Should add how to create a non-unique index via deploy hook here.
+
 =head3 Outputting SQL DDL
 
 Once the DBIC schema has been defined, you can outout the SQL DDL needed to create the schema in your database (using the RDBMS-specific flavor of SQL DDL) in one of several ways.
@@ -251,6 +259,7 @@ If called with no arguments, this method will create an SQL file each for MySQL,
 
 ### IIRC this is not true - one can not do diffs without Schema::Versioned
 ### which is not loaded by default (and will soon be deprecated anyway, given how far frew and jnap have gone)
+## No thats rubbish, my usual use-case is to not use versioned at all, but have create_ddl_dir output me the diff files, thats where they come from. (unless someone has stuffed that up and I havent noticed..)
 
 =head4 SQL files for upgrades (ALTER TABLE)
 
index 09f5463..151b5fa 100644 (file)
@@ -111,12 +111,14 @@ created by the user), should also be removed.
 NOTE: This is a rather drastic action, to prevent problems in your
 application, consider de-activating accounts instead of removing them!
 
-For the time being DBIx::Class defaults to cascade deletion for the following types
-of relationships: B<has_many>, B<has_one>, B<might_have>. That is, it
-will automatically issue the above statements. It is recommended not to rely
-on this implicit behavior, as it will be deprecated in a later version of DBIC.
-Instead declare proper cascading constraints in your RDBMS as described in
-L<DBIx::Class::Manual::SQLHackers::CREATE/Table creation with references>.
+For the time being DBIx::Class defaults to cascade deletion for the
+following types of relationships: B<has_many>, B<has_one>,
+B<might_have>. That is, it will automatically issue the above
+statements. It is recommended not to rely on this implicit behavior,
+as it will be deprecated in a later version of DBIC.  Instead declare
+proper cascading constraints in your RDBMS as described in
+L<DBIx::Class::Manual::SQLHackers::CREATE/Table creation with
+references>.
 
 If your database is already properly set up to cascade deletes for you,
 you can noop  DBIx::Class' extra cascading statements:
index b705bec..1c5325d 100644 (file)
@@ -48,8 +48,7 @@ In scalar or list context populate is a proxy to the B<create> method (on which
 
 Note that in void context you can skip passing primary key values that will be supplied by the database, and any other values that are allowed to DEFAULT. However no code in your Result classes will be run (eg InflateColumn components).
 
-# perhaps "Constructing and inserting Row objects" ?
-=head2 Inserting with Row objects
+=head2 Constructing and inserting Row object
 
     INSERT INTO users (username, dob, realname, password) 
     VALUES ('fredbloggs', '1910-02-01', 'Fred Bloggs', 'secretpass');
@@ -58,14 +57,14 @@ In the course of your application, you will often want to retrieve data from a u
 
 =over
 
-# perhaps s/Create/Obtain/ ?
-=item 1. Create a Schema object:
+=item 1. Obtain a Schema object:
 
         my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
 
 (ideally you will always have one of these handy, no need to make many connections to the database)
 
-# perhaps s/Create/Obtain/ ?
+NB: DBIx::Class does not store a Singleton schema object for you, calling C<connect> again will create a new Schema object with a new database connection. Avoid doing this, store and re-use the Schema object.
+
 =item 2. Create a User object:
 
         my $newuser = $schema->resultset('User')->new({ 
@@ -93,7 +92,7 @@ You can also shortcut these two methods if you don't need to build up the Row ob
           password  => 'secretpass',
         });
 
-Now *$newuser* is a Row object containing data that represents what is in the database.
+Now B<$newuser> is a Row object containing data that represents what is in the database.
 
 =back
 
@@ -166,12 +165,3 @@ This also can be shortcut using B<create>:
 
 =back
 
-### mattp is slowly working on this, do we need to mention it at all?
-
-=head2 Insert using a SELECT as input:
-
-    INSERT INTO users (id, username, dob, realname, password) 
-    SELECT (1, 'fredbloggs', '1910-02-01', 'Fred Bloggs', 'secretpass')
-    FROM nowhere;
-
-This is a TODO item for DBIC.
index 81344e8..44ea1dd 100644 (file)
@@ -4,8 +4,7 @@ DBIx::Class::Manual::SQLHackers::Introduction
 
 =head2 Introduction (Why ORMs and DBIx::Class)
 
-Almost every sizable Perl application these days needs a method of long term data storage. When the data needs to be easily retrieved as well as stored, we often use a database. Most databases can be comfortably accessed using SQL. Using the DBI module, and a DBD for the particular database, we can write SQL in our Perl code, and retrieve the results as arrays or hashes.
-^^ perhaps s/database/relational database/ ? just to save you from idiots "OOOOHHHH BUT MONGO IS A DB TOO!!!!"
+Almost every sizable Perl application these days needs a method of long term data storage. When the data needs to be easily retrieved as well as stored, we often use a relational database (or RDBMS). Most databases can be comfortably accessed using SQL. Using the DBI module, and a DBD for the particular database, we can write SQL in our Perl code, and retrieve the results as arrays or hashes.
 
     ## Example
     my $dbh = DBI->connect("dbi:SQLite:mydb.db");
@@ -21,10 +20,8 @@ There are several things we can do to make this code more usable, for example st
 
 The part we can't do much about is the SQL in the code. We can move it around, put it in libraries, but it's still there, somewhere. 
 
-Why is having SQL mixed with your Perl code not very optimal? For a start, it's just a string to pass to the database interpreter, there is no syntax checking at the Perl compilation level. Thus it fails late, not early. Your editor will also not syntax check what it just sees as strings of text.
+Why is having SQL mixed with your Perl code not optimal? For a start, it's just a string to pass to the database interpreter, there is no syntax checking at the Perl compilation level. Thus it fails late, not early. Your editor will also not syntax check what it just sees as strings of text.
 
-Modern Perl should also leverage code reuse and OO where it can. DBIx::Class promotes code reuse by allowing you to add methods for common queries, fetch related data in one query and cache data, also without refetching. DBIC still uses the DBI library underneath, so it gets things right while presenting the results in a more manageable way.
+Modern Perl should also leverage code re-use and OO where it can. DBIx::Class promotes code re-use by allowing you to add methods for common queries, fetch related data in one query and cache data, also without refetching. DBIC still uses the DBI library underneath, so it gets things right while presenting the results in a more manageable way.
 
-DBIx::Class solves these issues, you write your SQL in perl instead of plain text. The syntax will be checked for you, existance of columns, catching typos and so on. It uses objects so that you can write re-usable queries, and string methods together to create complex queries. You define the database layout once, or you export it from your actual database (with ability to re-export on update).
-^^
-this last paragraph is kinda misleading - we do not do any syntax checking of stuff - we just let the database throw. It would be waaaay to expensive to do otherwise.
+DBIx::Class solves these issues, you write your SQL in Perl instead of plain text. Pre-declaring your column names and types and using Perl data structures to create your queries means that the SQL produced will be at least syntactically correct. You can concentrate less on the structure of SQL, and more on the data your code is accessing. It uses objects so that you can write re-usable queries, and string methods together to create complex queries. You define the database layout once, or you export it from your actual database (with ability to re-export on update).
index 8e87800..42fad08 100644 (file)
@@ -206,10 +206,7 @@ To run the query, use the B<all> or B<next> methods show at the beginning of thi
 
 There's usually little reason to do this sort of query, as fetching all the data in a row doesn't cost any more time than fetching some of it. Unless of course your source is a View with calculations, or has huge blobs, or.. Okay, you might well want to do this occasionally.
 
-# this is completely false, is there a doc that states this that we need to fix?
-# find() takes all search() attributes, including things like prefetch
-^^ you never fixed this piece from last time
-B<find> will always pull all the columns for the found row, so use the *search* method for this.
+B<find> will always pull all the columns for the found row, so use the B<search> method for this.
 
 =over
 
@@ -364,49 +361,52 @@ The results will contain two columns with the usual accessors, "id" and "usernam
 
 Note: Remember to disambiguate the columns when joining two tables with identical column names.
 
-=head2 SELECT with simple ORDER BY
+=begin comment
 
-    SELECT users.id, username, dob, realname, password, posts.title
-    FROM users
-    JOIN posts posts ON posts.used_id = users.id
-    ORDER BY username, posts.title;
+Commented out section as ordering by a related source does not work yet. Fix in progress, will comment back in when DBIC is updated.
 
-To sort the results, use the B<order_by> attributes on a B<search> method. Content can of course be ordered by columns in the current table, or in a joined table
+    =head2 SELECT with simple ORDER BY
 
-=over
+        SELECT users.id, username, dob, realname, password, posts.title
+        FROM users
+        JOIN posts posts ON posts.used_id = users.id
+        ORDER BY username, posts.title;
 
-=item 1. Create a Schema object representing the database you are working with:
+    To sort the results, use the B<order_by> attributes on a B<search> method. Content can of course be ordered by columns in the current table, or in a joined table
 
-        my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
+    =over
 
-=item 2. Call the B<search> method on the resultset of the L<ResultSource|DBIx::Class::ResultSource> you wish to sort data on:
+    =item 1. Create a Schema object representing the database you are working with:
 
-# this will not collapse results (you will get users * (amount of posts || 1) as a result, sure you want to showcase this?
-^^ this is still true for what the DBIC on CPAN, I recommend pod-commenting the example out,
-^^ and reenabling it when I finally ship the blasted thing
-        my $sorted_users = $schema->resultset('User')->search(
-          { },
-          { '+columns' => [ qw/posts.id posts.title/ ],
-            join => 'posts',
-            order_by => [qw/username posts.title/],
-          }
-        );
+            my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
 
-=back
+    =item 2. Call the B<search> method on the resultset of the L<ResultSource|DBIx::Class::ResultSource> you wish to sort data on:
 
-Here "posts" refers to the name of the L<Relationship|DBIx::Class::Relationship> between the "User" source and the "Post" source.
+            my $sorted_users = $schema->resultset('User')->search(
+              { },
+              { '+columns' => [ qw/posts.id posts.title/ ],
+                join => 'posts',
+                order_by => [qw/username posts.title/],
+              }
+            );
 
-The results will be ordered by username, then post title, ready for outputting.
+    =back
 
-Note how we have added the title of each post, this prevents us having to fire off a second query to fetch the post data to output it. The B<+columns> attribute specifies an extended set of columns to fetch, in addition to the columns of the main query table.
+    Here "posts" refers to the name of the L<Relationship|DBIx::Class::Relationship> between the "User" source and the "Post" source.
 
-To retrieve the extra data, call the usual relationship accessor:
+    The results will be ordered by username, then post title, ready for outputting.
 
-    while( my $row = $sorted_users->next) {
-      print "user/post: ", $row->username;
-      print $_->title for $row->posts;
-      print "\n";
-    }
+    Note how we have added the title of each post, this prevents us having to fire off a second query to fetch the post data to output it. The B<+columns> attribute specifies an extended set of columns to fetch, in addition to the columns of the main query table.
+
+    To retrieve the extra data, call the usual relationship accessor:
+
+        while( my $row = $sorted_users->next) {
+          print "user/post: ", $row->username;
+          print $_->title for $row->posts;
+          print "\n";
+        }
+
+=end comment
 
 =head2 SELECT with HAVING
 
index 202ec06..9debfb4 100644 (file)
@@ -226,7 +226,7 @@ joining them for a select query and using data from both.
     COMMIT;
     
 DBIx::Class does not yet produce the non-standard MySQL "ON DUPLICATE KEY
-UPDATE", instead it has a shortcut for combining *find* and *update*.
+UPDATE", instead it has a shortcut for combining B<find> and B<update>.
 
 To avoid race conditions, this should be done in a transaction.
 
@@ -239,6 +239,8 @@ To avoid race conditions, this should be done in a transaction.
 =item 2. Call the B<txn_do> method on the schema object, passing it a coderef to execute inside the transaction:
 ^^ ouch! I didn't realize we don't do that automatically, this is a bug
 ^^ probably a good idea not to mention it - I'll fix it @ GPW
+## Not entirely sure what thing you mean here.. 
+
         $schema->txn_do( sub {
 
 =item 3. Call the B<update_or_create> method on the resultset for the L<ResultSource|DBIx::Class::ResultSource> you wish to update data in: