[Bast-commits] r3949 - in trunk: . Bookmarks-Parser/t DBIx-Class-Journal DBIx-Class-Journal/lib/DBIx/Class DBIx-Class-Journal/lib/DBIx/Class/Schema DBIx-Class-Journal/t DBIx-Class-Tutorial DBIx-Class-Tutorial/lib DBIx-Class-Tutorial/lib/DBIx DBIx-Class-Tutorial/lib/DBIx/Class DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial Locale-Object Locale-Object/lib/Locale Locale-Object/lib/Locale/Object Locale-Object/lib/Locale/Object/Currency

castaway at dev.catalyst.perl.org castaway at dev.catalyst.perl.org
Thu Jan 17 15:42:33 GMT 2008


Author: castaway
Date: 2008-01-17 15:42:33 +0000 (Thu, 17 Jan 2008)
New Revision: 3949

Added:
   trunk/DBIx-Class-Tutorial/
   trunk/DBIx-Class-Tutorial/NOTES
   trunk/DBIx-Class-Tutorial/lib/
   trunk/DBIx-Class-Tutorial/lib/DBIx/
   trunk/DBIx-Class-Tutorial/lib/DBIx/Class/
   trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/
   trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Database.pod
   trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Part1.pod
   trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Part2.pod
   trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Part3.pod
   trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Resultsets.pod
Modified:
   trunk/Bookmarks-Parser/t/04a9.t
   trunk/DBIx-Class-Journal/Changes
   trunk/DBIx-Class-Journal/MANIFEST
   trunk/DBIx-Class-Journal/lib/DBIx/Class/Journal.pm
   trunk/DBIx-Class-Journal/lib/DBIx/Class/Schema/Journal.pm
   trunk/DBIx-Class-Journal/t/01test.t
   trunk/Locale-Object/CHANGES
   trunk/Locale-Object/META.yml
   trunk/Locale-Object/lib/Locale/Object.pm
   trunk/Locale-Object/lib/Locale/Object/Continent.pm
   trunk/Locale-Object/lib/Locale/Object/Country.pm
   trunk/Locale-Object/lib/Locale/Object/Currency.pm
   trunk/Locale-Object/lib/Locale/Object/Currency/Converter.pm
   trunk/Locale-Object/lib/Locale/Object/DB.pm
   trunk/Locale-Object/lib/Locale/Object/Language.pm
   trunk/Locale-Object/locale.sql
Log:
Initial commit

Modified: trunk/Bookmarks-Parser/t/04a9.t
===================================================================
--- trunk/Bookmarks-Parser/t/04a9.t	2008-01-17 00:03:16 UTC (rev 3948)
+++ trunk/Bookmarks-Parser/t/04a9.t	2008-01-17 15:42:33 UTC (rev 3949)
@@ -18,7 +18,7 @@
 # 3 check parse function
 can_ok('Bookmarks::Parser', 'parse');
 
-# 4 parse netscape style file
+# 4 parse A9 service bookmarks
 $parser->parse({user => $ENV{A9_USER},
                 url => 'a9.com',
                 passwd => $ENV{A9_PASS}});

Modified: trunk/DBIx-Class-Journal/Changes
===================================================================
--- trunk/DBIx-Class-Journal/Changes	2008-01-17 00:03:16 UTC (rev 3948)
+++ trunk/DBIx-Class-Journal/Changes	2008-01-17 15:42:33 UTC (rev 3949)
@@ -1,5 +1,5 @@
 
-0.01 2007-05-18:
+0.01 2007-08-11:
 Initial version
 
 

Modified: trunk/DBIx-Class-Journal/MANIFEST
===================================================================
--- trunk/DBIx-Class-Journal/MANIFEST	2008-01-17 00:03:16 UTC (rev 3948)
+++ trunk/DBIx-Class-Journal/MANIFEST	2008-01-17 15:42:33 UTC (rev 3949)
@@ -4,7 +4,6 @@
 lib/DBIx/Class/Schema/Journal/DB.pm
 lib/DBIx/Class/Schema/Journal/DB/AuditHistory.pm
 lib/DBIx/Class/Schema/Journal/DB/AuditLog.pm
-lib/DBIx/Class/Schema/Journal/DB/AuduitLog.pm
 lib/DBIx/Class/Schema/Journal/DB/Base.pm
 lib/DBIx/Class/Schema/Journal/DB/Change.pm
 lib/DBIx/Class/Schema/Journal/DB/ChangeSet.pm
@@ -16,3 +15,4 @@
 t/lib/DBICTest/Schema/Artist.pm
 t/lib/DBICTest/Schema/CD.pm
 t/lib/DBICTest/Schema/Track.pm
+META.yml                                 Module meta-data (added by MakeMaker)

Modified: trunk/DBIx-Class-Journal/lib/DBIx/Class/Journal.pm
===================================================================
--- trunk/DBIx-Class-Journal/lib/DBIx/Class/Journal.pm	2008-01-17 00:03:16 UTC (rev 3948)
+++ trunk/DBIx-Class-Journal/lib/DBIx/Class/Journal.pm	2008-01-17 15:42:33 UTC (rev 3949)
@@ -2,6 +2,11 @@
 
 use base qw/DBIx::Class/;
 
+use strict;
+use warnings;
+
+our $VERSION = '0.01';
+
 ## On create/insert, add new entry to AuditLog
 
 # sub new
@@ -92,6 +97,197 @@
     $self->next::method($upd, @rest);
 }
 
+=head1 NAME
 
+DBIx::Class::Journal - auditing for tables managed by DBIx::Class
 
+=head1 SYNOPSIS
+
+  package My::Schema;
+  use base 'DBIx::Class::Schema';
+
+  __PACKAGE__->load_components(qw/+DBIx::Class::Schema::Journal/);
+
+  __PACKAGE__->journal_connection(['dbi:SQLite:t/var/Audit.db']);
+  __PACKAGE__->journal_user(['My::Schema::User', {'foreign.userid' => 'self.user_id'}]);
+
+
+ ########
+
+  $schema->changeset_user($user->id);
+  my $new_artist = $schema->txn_do( sub {
+   return = $schema->resultset('Artist')->create({ name => 'Fred' });
+  });
+
+
+=head1 DESCRIPTION
+
+The purpose of this L<DBIx::Class> component module is to create an
+audit-trail for all changes made to the data in your database (via a
+DBIx::Class schema). It creates changesets and assigns each
+create/update/delete operation an id. The creation and deletion date
+of each row is stored, as well as the previous contents of any row
+that gets changed.
+
+All queries which want auditing should be called using
+L<DBIx::Class::Schema/txn_do>, which is used to create changesets for
+each transaction.
+
+To track who did which changes, the user_id (an integer) of the
+current user can be set, a session_id can also be set, both are
+optional.
+
+To access the auditing schema to look at the auditdata or revert a
+change, use C<< $schema->_journal_schema >>.
+
+=head2 TABLES
+
+The journal schema contains a number of tables. 
+
+=over
+
+=item ChangeSet
+
+Each changeset row has an auto-incremented ID, optional user_id and
+session_id, and a set_date which defaults to the current datetime.
+
+A ChangeSet has_many Changes.
+
+=item Change
+
+Each change/operation done in the transaction is recorded as a row in
+the Change table. It contains an auto-incrementing ID, the
+changeset_id and an order column for the ordering of each change in
+the changeset.
+
+=item AuditLog
+
+For every table in the original database that is to be audited, an
+AuditLog table is created. Each auditlog row has an id which will
+contain the primary key of the table it is associated with. (NB:
+currently only supports integer-based single column PKs). The
+create_id and delete_id fields contain the IDs of the Changes that
+created or deleted this row.
+
+=item AuditHistory
+
+For every table in the original database to be audited, an
+AuditHistory table is created. Each row has a change_id field
+containing the ID of the Change row. The other fields correspond to
+all the fields from the original table. Each time a column value in
+the original table is changed, the entire row contents before the
+change are added as a new row in this table.
+
+=back
+
+=head2 METHODS
+
+=over
+
+=item journal_connection
+
+=item Arguments: \@connect_info
+
+=back
+
+Set the connection information for the database to save your audit
+information to. Leaving this blank assumes you want to store the audit
+data into your current database.
+
+=over
+
+=item journal_sources
+
+=item Arguments: \@source_names
+
+=back
+
+Set a list of source names you would like to audit, if unset, all
+sources are used.
+
+NOTE: Currently only sources with a single-column PK are supported, so
+use this method if you have sources with multi-column PKs.
+
+=over
+
+=item journal_storage_type
+
+=item Arguments: $storage_type
+
+=back
+
+Enter the special storage type of your journal schema if needed. See
+L<DBIx::Class::Storage::DBI> for more information on storage types.
+
+=over
+
+=item journal_user
+
+=item Arguments: \@relation_args
+
+=back
+
+The user_id column in the L</ChangeSet> will be linked to your user id
+with a belongs_to relation, if this is set with the appropriate
+arguments.
+
+=over
+
+=item changeset_user
+
+=item Arguments: $user_id
+
+=back
+
+Set the user_id for the following changeset(s). This must be an integer.
+
+=over
+
+=item changeset_session
+
+=item Arguments: $user_id
+
+=back
+
+Set the session_id for the following changeset(s). This must be an integer.
+
+=over
+
+=item txn_do
+
+=iitem Arguments: $code_ref
+
+=back
+
+Overloaded L<DBIx::Class::Schema/txn_do>, this must be used to start a
+new changeset to cover a group of changes. Each subsequent change to
+an audited table will use the changeset_id created in the most recent
+txn_do call.
+
+=head1 SEE ALSO
+
+L<DBIx::Class> - You'll need it to use this.
+
+=head1 NOTES
+
+Only single-column integer primary key'd tables are supported for auditing so far.
+
+Updates made via L<DBIx::Class::ResultSet/update> are not yet supported.
+
+No API for viewing or restoring changes yet.
+
+Patches for the above welcome ;)
+
+=head1 AUTHOR
+
+Jess Robinson <castaway at desert-island.me.uk>
+
+Matt S. Trout <mst at shadowcatsystems.co.uk> (ideas and prodding)
+
+=head1 LICENCE
+
+You may distribute this code under the same terms as Perl itself.
+
+=cut
+
 1;

Modified: trunk/DBIx-Class-Journal/lib/DBIx/Class/Schema/Journal.pm
===================================================================
--- trunk/DBIx-Class-Journal/lib/DBIx/Class/Schema/Journal.pm	2008-01-17 00:03:16 UTC (rev 3948)
+++ trunk/DBIx-Class-Journal/lib/DBIx/Class/Schema/Journal.pm	2008-01-17 15:42:33 UTC (rev 3949)
@@ -9,21 +9,24 @@
 __PACKAGE__->mk_classdata('journal_connection');
 __PACKAGE__->mk_classdata('journal_sources'); ## [ source names ]
 __PACKAGE__->mk_classdata('journal_user'); ## [ class, field for user id ]
-__PACKAGE__->mk_classdata('_journal_schema');
+__PACKAGE__->mk_classdata('_journal_schema'); ## schema object for journal
 
 our $VERSION = '0.01';
 
-sub throw_exception
-{
-}
+use strict;
+use warnings;
 
-sub exception_action
-{
-    my $self = shift;
-#    print STDERR Carp::longmess;
+# sub throw_exception
+# {
+# }
+
+# sub exception_action
+# {
+#     my $self = shift;
+# #    print STDERR Carp::longmess;
     
-    $self->next::method(@_);
-}
+#     $self->next::method(@_);
+# }
 
 # sub load_classes
 # {
@@ -130,8 +133,24 @@
     my $cs = $self->_journal_schema->resultset('ChangeSet');
 
     $self->txn_begin;
-    my %changesetdata = ( $self->_journal_schema->current_user() ? ( 'user_id', $self->_journal_schema->current_user()) : () ),
-    ( $self->_journal_schema->current_session() ? ( session_id => $self->_journal_schema->current_session() ) : () );
+    my %changesetdata;
+    if( defined $self->_journal_schema->current_user() )
+    {
+        $changesetdata{user_id} = $self->_journal_schema->current_user();
+    }
+    if( defined $self->_journal_schema->current_session() )
+    {
+        $changesetdata{session_id} = $self->_journal_schema->current_session();
+    }
+
+#         ( 
+#           $self->_journal_schema->current_user() 
+#           ? ( user_id => $self->_journal_schema->current_user()) 
+#           : (),
+#           $self->_journal_schema->current_session() 
+#           ? ( session_id => $self->_journal_schema->current_session() ) 
+#           : () 
+#         );
     if(!%changesetdata)
     {
         %changesetdata = ( ID => undef );
@@ -142,4 +161,23 @@
     $self->next::method($code);
 }
 
+sub changeset_user
+{
+    my ($self, $userid) = @_;
+
+    return $self->_journal_schema->current_user() if(@_ == 1);
+
+    $self->_journal_schema->current_user($userid);
+}
+
+sub changeset_session
+{
+    my ($self, $sessionid) = @_;
+
+    return $self->_journal_schema->current_session() if(@_ == 1);
+
+    $self->_journal_schema->current_session($sessionid);
+}
+
+
 1;

Modified: trunk/DBIx-Class-Journal/t/01test.t
===================================================================
--- trunk/DBIx-Class-Journal/t/01test.t	2008-01-17 00:03:16 UTC (rev 3948)
+++ trunk/DBIx-Class-Journal/t/01test.t	2008-01-17 15:42:33 UTC (rev 3949)
@@ -10,7 +10,7 @@
     eval "use DBD::SQLite";
     plan $@
         ? ( skip_all => 'needs DBD::SQLite for testing' )
-        : ( tests => 9 );
+        : ( tests => 12 );
 }
 
 my $schema = DBICTest->init_schema(no_populate => 1);
@@ -60,3 +60,29 @@
 my $alentry = $search->find({ ID => $new_cd->get_column($new_cd->primary_columns) });
 ok(defined($alentry->deleted), 'Deleted set in audit_log');
 
+$schema->changeset_user(1);
+$schema->txn_do( sub {
+    $schema->resultset('CD')->create({
+        title => 'Something 2',
+        artist => $artist,
+        year => 1999,
+    });
+} );
+
+ok($search->count > 1, 'Created an second entry in the CD audit history');
+
+my $cset = $schema->_journal_schema->resultset('ChangeSet')->find(5);
+is($cset->user_id, 1, 'Set user id for 5th changeset');
+
+$schema->changeset_session(1);
+$schema->txn_do( sub {
+    $schema->resultset('CD')->create({
+        title => 'Something 3',
+        artist => $artist,
+        year => 1999,
+    });
+} );
+
+my $cset2 = $schema->_journal_schema->resultset('ChangeSet')->find(6);
+is($cset2->session_id, 1, 'Set session id for 6th changeset');
+

Added: trunk/DBIx-Class-Tutorial/NOTES
===================================================================
--- trunk/DBIx-Class-Tutorial/NOTES	                        (rev 0)
+++ trunk/DBIx-Class-Tutorial/NOTES	2008-01-17 15:42:33 UTC (rev 3949)
@@ -0,0 +1,14 @@
+
+inflate/deflate, std inflators
+changing accessors, adding non-column accessors
+
+pk ids, discard_changes, sequences etc
+resultset get_column
+other relationships..
+
+resultset_class / resultset_attributes
+
+add CONCLUSIONS - Now you should be able to ...
+and EXERCISES ?
+
+add ASSUMPTIONS to the top/toc/intro ? (user understands perl, sql etc)
\ No newline at end of file

Added: trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Database.pod
===================================================================
--- trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Database.pod	                        (rev 0)
+++ trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Database.pod	2008-01-17 15:42:33 UTC (rev 3949)
@@ -0,0 +1,34 @@
+=head1 NAME 
+
+DBIx::Class::Tutorial::Database - database tables for the tutorial
+
+=head1 DESCRIPTION
+
+A simple-ish database for holding site breadcrumbs.
+
+Assumptions: 
+
+=over
+
+=item No Path translation
+
+=back
+
+=head2 Lang
+
+    ID          | Language
+  ------------------------------
+   int auto-inc |  varchar
+
+=head2 Path
+
+    ID           |  Path   | Parent     | LastModified
+  --------------------------------------------------
+   int auto-inc  | varchar | integer fk | datetime
+
+=head2 Name
+
+    ID           | Name    | LangID  | PathID  |  LastModified
+  ----------------------------------------------------------
+   int auto-inc  | varchar | int fk  | int fk  |  datetime
+

Added: trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Part1.pod
===================================================================
--- trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Part1.pod	                        (rev 0)
+++ trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Part1.pod	2008-01-17 15:42:33 UTC (rev 3949)
@@ -0,0 +1,406 @@
+=head1 NAME 
+
+DBIx::Class::Tutorial::Part1
+
+=head1 DESCRIPTION
+
+This is part one of a DBIx::Class tutorial I started writing for the
+folks at work, I hope to turn it into a multi-part releasable
+document.
+
+=head1 GLOSSARY
+
+See L<DBIx::Class::Manual::Glossary>.
+
+Some terms needed for this doc:
+
+=over 
+
+=item Schema
+
+The schema object is the main point of contact with the rest of
+DBIx::Class, we create one initially using the database's connection
+details, and keep it around until we are completely done with the
+database.
+
+A L<DBIx::Class::Schema> object is created by calling C<< ->connect >>
+on our Schema subclass, and passing it the DSN (and other possible
+values, see L<DBIx::Class::Schema>). Eg: C<< my $schema =
+Breadcrumbs::Schema->connect('dbi:mysql;dbname=Breadcrumbs',
+'user', 'passwd'); >> 
+
+NB: Creating this object does not attempt to connect to the database
+yet.
+
+NB2: To make use of an existing mechanism to store credentials for
+databases, we can do: C<< my $schema = Breadcrumbs::Schema->connect(
+sub { get_dbh('Breadcrumbs') } ); >>.
+
+=item ResultSet
+
+A L<DBIx::Class::ResultSet>, an object which represents a database
+query, including all conditions/clauses. Creating one does not run the
+associated query, it is stored and used when actual data objects are
+requested. The simplest form of ResultSet represents an entire table,
+and can be retrieved from the schema object like this: C<< my $rs =
+$schema->resultset('Path') >>.
+
+=item Result class
+
+A class whose objects represent a single result from a resultset,
+usually corresponding to a single row of a table.
+
+=item Row
+
+A L<DBIx::Class::Row> represents an actual row of data resulting
+from a database query. This could be an entire row, or just certain
+fields as restricted by a ResultSet.
+
+=head1 GETTING STARTED
+
+To create a new set of DBIx::Class Result classes, you can either
+write them by hand, or create from an existing database.
+
+=head2 Create Result classes from existing database
+
+Install the separate module L<DBIx::Class::Schema::Loader>.
+
+Use its C<make_schema_at> to extract your schema definitions from
+existing databases and create a complete L<DBIx::Class> schema for
+you, example:
+
+  perl -MDBIx::Class::Schema::Loader=make_schema_at,dump_to_dir:./lib -e 'make_schema_at("Breadcrumbs::Schema", { debug => 1 }, [ "dbi:mysql:dbname=Breadcrumbs","user", "passwd" ])'
+
+This will create a file for each database table (in
+F<lib/Breadcrumbs/Schema/>), plus the file F<Breadcrumbs/Schema.pm> which is
+the L<DBIx::Class::Schema> file.
+
+The table files will contain information about the columns and their
+types. If the (mysql) database is innodb, it will also extract
+relationships based on foreign key references etc. An md5 sum of the
+contents is added, so that the user can add more relations or other
+methods to the file, and a later update will not overwrite them.
+
+Look in the files that have been created. For help on what has been
+created, see L<DBIx::Class::ResultSource>.
+
+=head2 If the database layout changes
+
+Re-run the C<make_schema_at> command shown above. 
+
+=head2 Create Result classes from scratch
+
+See L<DBIx::Class::Manual::Intro/SETTING UP DBIx::Class>.
+
+=head2 Setting up relationships
+
+If your database is mysql and not using innodb, you will have
+to add the table relationships yourself. These are the most useful
+part of DBIx::Class, otherwise we might as well just use DBI..
+
+There are two main/useful relationship types, for the rest and a more wordy
+description, see L<DBIx::Class::Relationship>.
+
+The B<name> of each relationship (the first argument), is important,
+it is used both as an accessor and as a key to join across tables.
+
+=head2 belongs_to (foreign keys)
+
+Breadcrumbs's C<Name> table has a C<PathID> column which contains
+an ID from the C<Path> table. To make the Path object simple to
+retrieve and update, we add the following to the F<Name.pm> file,
+after the md5 sum from Loader:
+
+  __PACKAGE__->belongs_to('path', 'Breadcrumbs::Schema::Path', 'PathID');
+
+Read as: The value in the C<PathID> column belongs_to the table
+represented by C<Breadcrumbs::Schema::Path>. Since we didn't specify,
+this will default to assuming that the C<PathID> field contains the
+C<ID> of the C<Path> table.
+
+(Yes, we think this relationship type should be renamed too, probably
+to C<refers_to> or similar)
+
+This creates an accessor C<path>, which we can call on a Name
+L<object|DBIx::Class::Row> which will retrieve the related
+L<object|DBIx::Class::Row> in the C<Path> table.
+
+  ## Print the path of the current name entry
+  print $name->path->path;
+
+We can also set a PathID for a new Name row by calling:
+
+  $name->path($pathobj);
+  $name->update;
+
+=head2 has_many (reverse foreign key)
+
+Going in the opposite direction, each C<Path> row has 0 to many
+C<Name> entries associated with it, indicated by the C<PathID> column
+in the C<Name> table. We can make it simple to retrieve all the name
+values for a particular C<Path> row:
+
+  __PACKAGE__->has_many('names', 'Breadcrumbs::Schema::Name', 'PathID');
+
+Read as: This class has many C<names> in C<Breadcrumbs::Schema::Name>
+linked via the C<PathID> column.
+
+This creates an accessor C<names> which can return a
+L<DBIx::Class::ResultSet> (of which more later), or an array of
+C<Name> objects.
+
+  ## find all names for current path entry
+  foreach my $name ($path->names->all)
+  {
+     print $name->name;
+  }
+
+Add a new name for the current path, assuming we have a language
+object as well:
+
+  $path->create_related('names', 
+                        { name => 'Products',
+                          lang => $lang }
+                       );
+
+
+=head1 Creating a Schema object
+
+To use a L<DBIx::Class> schema, you must first create a C<$schema>
+object. This object must not go out of scope while you are using any
+objects created from it.
+
+  my $schema = Breadcrumbs::Schema::Path->connect('dbi:mysql:dbname=breadcrumbs', 'user', 'pass');
+
+For more information on the arguments to connect, see
+L<DBIx::Class::Schema/connect_info>
+
+=head1 Getting data
+
+Whether fetching complete rows, searching for rows, or fetching data
+from multiple tables, the methods are much the same, all return
+L<DBIx::Class::Row> objects eventually.
+
+Remember L</ResultSet>s? To start any query we need to start from a
+resultset representing the main table accessed in the query. To fetch
+a resultset, we call C<resultset> on our L</Schema> object, and pass
+it the B<name> of a C</Result class>.
+
+  ## ResultSet for the Breadcrumbs::Schema::Name class
+  $schema->resultset('Name')
+
+=head2 find (single row by unique key)
+
+To fetch a full row using its Primary Key (they all have PKs,
+right?), we can retrieve a Row object directly from a ResultSet
+representing the table:
+
+  ## Just PK:
+  my $name1 = $schema->resultset('Name')->find(1);
+
+  ## More meaningful:
+  my $name1 = $schema->resultset('Name')->find({ id => 1 });
+
+The Row object contains all the values of all the fields defined in
+the Result class. Not necessarily in the table. Each column has an
+accessor which is by default the name of the column lower-cased (When
+using Loader).
+
+  my $namename = $name1->name;   ## Japan
+  my $langid   = $name1->langid; ## 1
+
+=head2 search (multiple objects)
+
+To fetch a particular Name row and its Path at the
+same time, using only one database query:
+
+  my $name_rs = $schema->resultset('Name')->search(
+    { 'me.id' => 1 },             ## WHERE
+    { prefetch => [ 'path' ] }    ## JOIN/SELECT
+
+This creates a L<DBIx::Class::ResultSet>, to retrieve the actual Row object:
+
+  my $namerow = $name_rs->next;
+
+The following SQL is executed:
+
+  SELECT me.ID, me.Name, me.LangID, me.PathID, path.ID, path.Path, path.Parent, path.Position, path.MenuID FROM Name me  JOIN Path path ON ( path.ID = me.PathID ) WHERE ( me.id = ? ): '1'
+
+L<DBIx::Class::ResultSet/prefetch> takes the B<name> of the
+relationship for the table we want to join to. In this case, the
+B<name> of the L</belongs_to> relationship we defined in the C<Name>
+class earlier.
+
+As with the find, the data is retrieved using the column-name
+accessors. We can also retrieve a Row object representing the path:
+
+  my $pathrow = $namerow->path;
+
+  my $actualpath = $pathrow->path;   ## companyinfo/careers/jp
+  my $pathparent = $pathrow->parent; ## 36
+
+To fetch just a few columns:
+
+  my $name_rs = $schema->resultset('Name')->search(
+    { 'me.id' => 1 },                                ## WHERE
+    { 
+      select   => [ qw/id name/ ],                   ## SELECT
+      as       => [ qw/id name/ ],
+    }
+  );
+
+This will only select the ID and Name columns. The C<as> attribute
+names the columns.
+
+To add more complex conditions:
+
+  ## All names where the path matches '/support/%'
+  my $name_search = $schema->resultset('Name')->search(
+    {
+      'path.path' => { 'like' => '/support/%' },  ## WHERE .. LIKE ..
+    },
+    { 
+      'join' => [ 'path' ],                       ## JOIN
+    }
+  );
+
+For more conditions, functions etc, see the L<SQL::Abstract> docs.
+
+=head1 Inserting data
+
+To insert new rows, call C<create> on a ResultSet object. This will
+first instantiate a new Row object, then call C<insert> on it. This
+can be done individually if needed.
+
+  ## INSERT INTO .. 
+  my $newname = $schema->resultset('Name')->create(
+  {
+     name   => 'Support',
+     pathid => $pathid,
+     langid => $langid,
+  });
+  print $newname->in_storage();  ## 1 (TRUE)
+
+C<in_storage> tells us whether the Row object is in the database or
+not. This is set when fetching data, and when we insert a new row.
+
+C<new> just creates a local Row object, it doesn't exist in the
+database until we call C<insert>.
+
+  my $newpath = $schema->resultset('Path')->new(
+  {
+     path => 'support',
+  });
+  print $newpath->in_storage();  ## 0 (FALSE)
+
+  $newpath->insert();
+  print $newpath->in_storage();  ## 1 (TRUE)
+
+=head1 Changing data
+
+=head2 Updating one row
+
+The column-name accessors used to fetch data from a row can also be
+used to set new values, eg:
+
+  ## Nonsensically change the language of a given Name row
+  my $namerow = $schema->resultset('Name')->find({ name => 'Japan' });
+  $namerow->langid(2);
+  $namerow->update;    ## UPDATE 
+
+=head2 Updating many rows with a resultset
+
+Create a resultset containing the condition to select all the rows to
+update. Calling C<update> on the resultset will run the C<UPDATE>
+command using the condition in the resultset.
+
+  ## All name rows with value 'Evaluation'
+  my $name_rs = $schema->resultset('Name')->search(
+  {
+    'me.name' => 'Evaluation',
+  });
+  $name_rs->update({ name => 'Free Trial' });  ## UPDATE .. WHERE
+  
+=head3 Deleting a row
+
+Just call C<delete> on a C<Row> object.
+
+  ## No more products/es !
+  my $pathrow = $schema->resultset('Path')->find({ path => 'products/es' });
+  $pathrow->delete;
+
+This will also delete related rows that would otherwise be
+inconsistent. It will remove them *after* the main row. This cascading
+can be turned off on a relationship if necessary.
+
+=head3 Delete multiple rows
+
+Call C<delete> on a ResultSet object instead. This will run a
+C<DELETE> statement with a C<WHERE> clause, and will not cascade the
+deletes.
+
+  my $path_rs = $schema->resultset('Path')->search(
+  {
+    'me.path' => 'products/es',
+  });
+  $path_rs->delete;     ## DELETE .. WHERE 
+
+To delete multiple rows with cascading, call C<delete_all> on the
+ResultSet, which will delete each row and its related rows
+individually.
+
+  $path_rs->delete_all;    ## many DELETE statements
+
+=head1 CONCLUSIONS
+
+You should now be able to:
+
+=over
+
+=item *
+
+Create a set of new DBIx::Class classes from an existing database.
+
+=item *
+
+Add and understand simple relationships between tables.
+
+=item *
+
+Connect to the database and create a schema object.
+
+=item *
+
+Fetch rows from the database using primary keys or simple search conditions.
+
+=item *
+
+Create new rows in the database.
+
+=item *
+
+Update or delete rows in the database.
+
+=back
+
+=head1 EXERCISES
+
+=head1 WHERE TO GO NEXT
+
+L<Part 2 of the tutorial|DBIx::Class::Tutorial::Part2>
+
+L<Loader documentation|DBIx::Class::Schema::Loader>
+
+L<More about searching|DBIx::Class::ResultSet/search>
+
+
+=head1 TODO
+
+Add some sorta table descriptions to this doc. 
+
+Patches and suggestions welcome.
+
+=head1 AUTHOR
+
+Jess Robinson <castaway at desert-island.me.uk>
+

Added: trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Part2.pod
===================================================================
--- trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Part2.pod	                        (rev 0)
+++ trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Part2.pod	2008-01-17 15:42:33 UTC (rev 3949)
@@ -0,0 +1,390 @@
+=head1 NAME
+
+DBIx::Class::Tutorial::Part2
+
+=head1 DESCRIPTION
+
+This is part two of the tutorial. See L<DBIx::Class::Tutorial::Part1>
+if you haven't already.
+
+In which we discuss more about resultsets and rows, and do some
+funky related data dealing.
+
+=head1 GLOSSARY
+
+=over
+
+=item Relationship(s)
+
+In case you didn't catch this in Part1.
+
+Relationships definitions are what DBIx::Class uses to C<JOIN> tables
+in the SQL queries it produces.
+
+You can define relationships in your
+L<Result class|DBIx::Class::Tutorial::Part1/Result class>es. Even
+relationships that your database does not know about.
+
+To access a relationship from both ends, you need to define it
+twice, once at each Result class end.
+
+=item Accessors
+
+An accessor is a method for getting/setting some data on an object.
+
+DBIx::Class defines accessors for all of the columns defined in your
+Result classes. It also defines an accessor for each
+relationship you define.
+
+In fact, it creates two accessors for C<has_many> relationships. 
+
+  __PACKAGE__->has_many('names', 'Breadcrumbs::Schema::Name', 'PathID');
+
+Here, the C<names> accessor will return a list of Row objects in list
+context, and a L</ResultSet> in scalar context.
+
+Another accessor named C<names_rs> is added, which will always return
+a ResultSet, no matter which context it is called in. This is useful
+for templating with L<Template::Toolkit>.
+
+When doing complex searches and naming fake-columns such as a
+C<COUNT(*)> column, no accessor is created. This is intentional, as it
+may override methods you have written yourself. Examples of this
+later.
+
+=item Unique constraints
+
+If your database has unique indexes defined that are not the primary
+key, then L<DBIx::Class::Schema::Loader> should export them into your
+Result classes for you.
+
+You can create your own, independent of the database indexes, for
+DBIx::Class to use, just add a C<add_unique_constraint> call to your
+Result class.
+
+  Breadcrumbs::Schema::Path->add_unique_constraint('pathconst' => [qw/path/]);
+
+This is the name of the constraint, followed by a list of columns that
+are unique.
+
+=back
+
+=head1 More about ResultSets
+
+A Hint:
+
+Set C<DBIC_TRACE=1> in your environment, or call C<<
+$schema->storage->debug(1); >> to make L<DBIx::Class> dump all the SQL
+it is producing to STDERR.
+
+=head2 Creating ResultSets
+
+The simplest resultset just represents a query that would return an
+entire table full of data.
+
+  ## ResultSet for the Breadcrumbs::Schema::Name class
+  my $name_rs = $schema->resultset('Name')
+
+Every C<search> in scalar context also returns a resultset. I also
+snuck in an ordering example here.
+
+  ## Just the names beginning with a:
+  my $anames_rs = $schema->resultset('Name')->search(
+    { 'me.name' => { 'like' => 'a%' } },      ## WHERE 
+    { order_by  => [ 'me.name' ] }            ## ORDER BY
+  );
+
+We can add to the query conditions of an existing resultset:
+
+  ## Names beginning with a, in path '/support':
+  my $anames_short_rs = $anames_rs->search(
+    { 'path.path' => { like => '/support/%' } }, ## WHERE
+    { join        => [ 'path' ] },               ## JOIN
+  );
+
+When this query runs it will produce SQL something like:
+
+SELECT me.id, me.name FROM Name me
+JOIN Path path ON path.ID = me.PathID
+WHERE me.name LIKE 'a%'
+AND path.path LIKE '/support/%'
+ORDER BY me.name
+
+If we already have a row object, then we can easily fetch resultsets
+of data related to it, via the L</Relationships>. For example starting
+at a Path object, fetching a resultset of all the related names can be
+done by calling the accessor C<names>.
+
+  ## Get Path object for '/support':
+  my $support = $schema->resultset('Path')->find({ path => '/support' });
+
+  ## Resultset of all the names for this path:
+  my $supportnames_rs = $support->names;
+
+The resultset returned from the relationship accessor contains the
+query conditions for only fetching the C<Name> rows for the C<Path>
+object we started out with, the SQL will look something like:
+
+SELECT me.id, me.name FROM Name
+WHERE me.PathID = 10;
+
+=head2 Fetching data from ResultSets
+
+Calling any of these methods will cause DBIx::Class to actually run
+the query represented by the resultset. All the searching above did
+not run any queries.
+
+As we saw in Part1, we can fetch a single Row using C<find>. This is
+just for fetching a row based on a known unique value, often the
+primary key.
+
+  ## Name row with PK 1:
+  my $name1 = $schema->resultset('Name')->find({ id => 1 });
+
+If L</Unique constraints> have been defined, we can also C<find> a Row
+based on those, we can force C<find> to use a unique constraint instead
+of the primary key, which is set up internally as a constraint named
+C<primary>.
+
+  ## Find path '/support', use pathconst index:
+  my $supppath = $schema->resultset('Path')->find(
+    { path => '/support' },
+    { key => 'pathconst' }
+  );
+
+To fetch multiple rows from a resultset, we can simply turn it into an
+array of Row objects. If your resultset is large, this may take a
+while and use some memory.
+
+  ## All results in an array:
+  my @anames = $anames_rs->all;
+
+  foreach my $name (@anames)
+  {
+     print $name->id;
+  }
+
+To fetch the rows one at a time, we can treat the resultset like an
+iterator. This only uses memory for one object at a time.
+
+  ## One at a time.
+  while (my $aname = $anames_rs->next)
+  {
+     print $name->id;
+  }
+
+If we only ever wanted the first result of a search, we can also call
+C<first> to get the first row in the result. This is probably only
+useful if we searched using ordering to sort the results.
+
+  ## First A-name:
+  my $aname = $aname_rs->first;
+  print $aname->id;
+
+We can also get columns of data from a resultset, rather than
+rows. This is a handy way to fetch all the IDs of a search. 
+
+  ## IDs of all Names beginning with A:
+  my @aids = $aname_rs->get_column('id')->all;
+
+Or a sum across all the rows in our resultset.
+
+  ## Sum of all the IDs, for no useful reason:
+  my $sumids = $aname_rs->get_column('id')->sum;
+
+Or an arbitrary function, like the lengths of all the names.
+
+  ## Slightly less contrived:
+  my @lengths = $aname_rs->get_column('name')->func('LENGTH');
+
+For more of these see L<DBIx::Class::ResultSetColumn>.
+
+=head1 Related data
+
+Each search starts from one main table and from it you can fetch any
+related rows or data.
+
+=head2 Simple relations
+
+Just call the relationship accessors. For example, C<path> is the
+relationship from the Name table to the Path table using the C<PathID>
+column in the Name table.
+
+  ## Get Name object for 'Support' in english:
+  my $support_rs = $schema->resultset('Name')->find(
+    { name => 'Support',
+      lang => 1,
+    });
+
+SELECT me.id, me.name FROM Name WHERE name = 'Support' AND lang = 1
+
+  ## Get the path object for a name result:
+  my $supportname = $support_rs->first;
+  my $supportpath = $supportname->path;
+
+SELECT me.id, me.path FROM Path = WHERE PathID = ?
+
+Or use C<prefetch> to get them both in the same query. Call the
+accessor on the result as above to retrieve the prefetched data.
+
+  ## Get Name for Support and its Path:
+  my $support_rs = $schema->resultset('Name')->search(
+   { name => 'Support',
+     lang => 1,
+   }, 
+   { prefetch => [ 'path' ],          ## JOIN/SELECT
+   });
+
+  my $supportpath = $support_rs->first->path;
+
+SELECT me.id, me.name, path.id, path.path FROM Name me 
+JOIN Path path ON ( path.id = me.PathID )
+
+=head2 Advanced joins
+
+The C<join> and C<prefetch> attributes can also be used to join across
+more than one level of related tables.
+
+To join across multiple relationships from the same table, supply an
+array of relation names to the attribute.
+
+  ## Prefetch both Path and Lang data from Name:
+  my $support_rs = $schema->resultset('Name')->search(
+   { name => 'Support',
+     lang => 1,
+   }, 
+   { prefetch => [ 'path', lang' ],          ## JOIN/SELECT
+   });
+  
+
+To create a join that drills down into relations of related tables,
+use a hashref.
+
+  ## Fetch all names for Path '/support', plus the language object of
+  ## each Name.
+  my $path_rs = $schema->resultset('Path')->search(
+    { path => '/support' },
+    { prefetch => { names => 'lang' } }
+  );
+
+Be aware that this cannot prefetch to multiple has_many relationships
+on the same level. The data fetching code cannot untangle the result
+into objects.
+
+=head2 Restrict search based on related data
+
+We can just use the related tables to join to without actually
+retrieving their data, for that we use the search attribute C<join>.
+
+  ## Find all names for path '/support':
+  my $supportnames = $schema->resultset('Name')->search(
+    { 'path.path' => '/support' },        ## WHERE
+    { join        => [ 'path' ] }         ## JOIN
+  );
+
+In the SQL produced, the names of the relations are used as aliases
+for the related tables. Thus you can use constructs like C<path.path>
+in your search condition to refer to a column on the related table.
+
+The default alias for the main table in the query is C<me>.
+
+=head2 Fetch extra values from related data
+
+Instead of prefetching an entire related object, we can just add a
+needed column to our query.
+
+  ## Get Name for Support and its Path:
+  my $support_rs = $schema->resultset('Name')->search(
+   { name => 'Support',
+     lang => 1,
+   }, 
+   {  '+select'  => [ 'path.path ' ],
+      '+as'      => [ 'path' ],
+      join       => [ 'path' ],
+   });
+
+SELECT me.id, me.path, path.path FROM Path me
+LEFT JOIN Name names ON ( names.PathID = me.id )
+
+The C<Result> of this is an object of class
+C<Breadcrumbs::Schema::Path>, but it will have an extra data item,
+called C<path>. Since this is not a predefined column in the Path
+result class, it will not have an accessor. We can retrieve it's
+contents using C<get_column>.
+
+  my $path = $support_rs->first->get_column('path');
+
+The C<+select> and C<+as> search attributes are used to include extra
+columns or expressions in the query. The names supplied for these
+using C<+as> are just for DBIx::Class' benefit, no C<AS> is added to
+the query.
+
+=head2 Aggregate functions
+
+We can also make up data using aggregate functions, for example, how
+many C<Name> entries does each C<Path> row have?
+
+  ## Count names per path:
+  my $namecounts_rs = $schema->resultset('Path')->search(
+    { },
+    { '+select'   => [ { count => '*' } ],
+      '+as'       => [ 'namecount' ],
+      'join'      => [ 'names' ],
+      'group_by'  => [ 'me.id', 'me.path' ],
+    }
+  );
+
+SELECT me.id, me.path, COUNT( * ) FROM Path me
+LEFT JOIN Name names ON ( names.PathID = me.id )
+GROUP BY me.id, me.path
+
+C<group_by> is another search attribute that adds the obvious clause
+to the SQL query. To get a count of names per path, we must add a
+grouping to force a count per group entry.
+
+  ## Output results:
+  while (my $result = $namecounts_rs->next) {
+    print "Path ", $result->path, " has ", 
+      $result->get_column('namecount'), " names.\n";
+    
+  }
+
+=head1 CONCLUSIONS
+
+Now you should understand:
+
+=over
+
+=item *
+
+How to create a resultset containing one or many rows from one or many
+related tables.
+
+=item *
+
+How to retrieve the data from a resultset for both the main table and
+related tables.
+
+=item *
+
+How to use aggregate functions in a search or on an entire row.
+
+=back
+
+=head1 EXERCISES
+
+=head1 WHERE TO GO NEXT
+
+L<Part 3 of the tutorial|DBIx::Class::Tutorial::Part3>
+
+L<More about searching|DBIx::Class::ResultSet/search>
+
+L<Search attributes|DBIx::Class::ResultSet/ATTRIBUTES>
+
+L<Column objects|DBIx::Class::ResultSetColumn>
+
+L<Search query format|SQL::Abstract>
+
+=head1 AUTHOR
+
+Jess Robinson <castaway at desert-island.me.uk>

Added: trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Part3.pod
===================================================================
--- trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Part3.pod	                        (rev 0)
+++ trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Part3.pod	2008-01-17 15:42:33 UTC (rev 3949)
@@ -0,0 +1,209 @@
+=head1 NAME
+
+DBIx::Class::Tutorial::Part3
+
+=head1 DESCRIPTION
+
+If you missed the previous parts, go and start reading at
+L<DBIx::Class::Tutorial::Part1>.
+
+Stay here if you're just after ways to deal with the data you're
+getting out of DBIx::Class, or adding your own accessors.
+
+=head1 GLOSSARY
+
+=over
+
+=item Inflation and Deflation
+
+The act of converting data coming out of the database, into a useful
+object in order to call methods on it, is called C<Inflation>. This is
+usually done for the data from one column of a Row. The classic
+example is a field containing data representing a specific date and
+time. The data type for these fields is usually C<datetime> or
+C<timestamp>. An C<Inflator> can turn the datetime data into a
+L<DateTime> object.
+
+Deflation is the opposite. Turning a supplied object back into a
+string or other piece of data suitable for inserting into the
+database.
+
+=item Auto-Incrementing and Sequences
+
+Most databases provide a way to auto-increment a numeric column,
+usually an integer column, to use as a primary key. Some allow you to
+create a sequence which can be queried for it's next value, to use as
+the primary key. The difficulty with creating new rows using
+auto-increment primary keys is retrieving the value of the key after a
+new row has been inserted.
+
+=item Non-column data
+
+An oft-asked question is: How can I add accessors to my Result classes
+to store non-column data?
+
+We can easily add new accessors to Row objects to set and retrieve
+data not stored in the database.
+
+=back
+
+=head1 Dealing with Primary Keys
+
+L<DBIx::Class> automatically fetches primary keys from the database
+for you, and stores it in your new row object.
+
+  ## Fetch a new path and print its ID:
+  my $path = $schema->resultset('Path')->create(
+    { path => '/support', }
+  );
+  print $path->id;
+
+This is done using L<last_insert_id|DBI>.
+
+Tables using sequences for their Primary keys should be updated using
+a trigger to update the PK value. The name of the sequence can be set
+in the L<add_columns|DBIx::Class::ResultSource/add_columns> so that
+the last value can be fetched by L<DBIx::Class::PK::Auto>.
+
+=head1 Turning values into useful objects
+
+Just retrieving raw data from the database is only half the
+battle. You likely want to also do something useful with it, or
+manipulate it and re-insert. For example, many tables have a field
+containing the date and time the row was created, or last modified.
+
+If we want to take that date and display, for example, how long since
+the row was modified in days/hours/minutes, it would be useful to have
+that datetime value as a L<DateTime> object, then we can use
+L<DateTime::Duration> or similar to display the elapsed time.
+
+To do this, we can add a new C<component> to the C<Result class>es. In
+F<lib/Breadcrumbs/Schema/Path.pm> you'll notice a line that says:
+
+  __PACKAGE__->load_components(qw/ Core/);
+
+It may contain other components as well. Add the
+L<InflateColumn::DateTime|DBIx::Class::InflateColumn::DateTime>
+component in front of the existing ones.
+
+  __PACKAGE__->load_components(qw/ InflateColumn::DateTime Core /);
+
+Order is important. Core must go last.
+
+The accessors of any columns of type C<datetime>, C<timestamp> and
+C<date> will now return L<DateTime> objects when called.
+
+  ## print last_modified as an iso formatted string
+  my $dt = $path->last_modified();
+  print $dt->iso_string;
+
+You can now also set the value of last_modified using a L<DateTime>
+object.
+
+  ## Set last_modified
+  my $dtnow = DateTime->now();
+  $path->last_modified($dtnow);
+  $path->update();
+
+To see how to create more inflators and deflators for other types of
+objects, read L<DBIx::Class::InflateColumn>.
+
+=head1 Changing the standard accessors
+
+L<DBIx::Class> creates standard getter/setter accessors for you, for
+all your values. If you would like to change or manipulate the value
+of a particular column on the way into or out of the database, you can
+write your own accessors.
+
+To do this you will first have to edit the Result class, adding the
+C<accessor> key in your L<DBIx::Class::ResultSource/add_columns> call.
+
+  ## add accessor for path column, in 
+  ## Breadcrumbs::Schema::Path
+  __PACKAGE__->add_columns( .. 
+                           path => {
+                             data_type => 'varchar',
+                             size      => 255,
+                             accessor  => '_path',
+                           }
+                           .. 
+                           );
+
+DBIx::Class will now create this accessor with the name C<_path>. We
+can now write our own C<path> method.
+
+  ## Clean extra slashes off paths
+
+  sub path {
+    my ($self, $value) = @_;
+
+    if(@_ > 1) {
+      $value = s{^/}{};
+      $value = s{/$}{};
+      $self->_path($value);
+    }
+    return $self->_path();
+  }
+
+=head1 Adding your own data and methods
+
+You can add your own accessors for non-column (database) data to your
+Result classes quite easily. Just edit the Result classes.
+
+  ## Add accessor for storing whether a path has been checked
+  ## to Breadcrumbs::Schema::Path
+
+  __PACKAGE__->mk_group_accessors('simple' => qw/is_checked/);
+
+  $path->is_checked(1);
+
+Or, just add an entire method to do the work and return the result.
+
+  ## Add method to check if the path exists:
+
+  sub check {
+    my ($self, $root) = @_l
+
+    return 1 if(-d catfile($root, $self->path));
+
+    return 0;
+  }
+
+=head1 Adding ResultSet methods
+
+Putting methods in your Result classes will make them available to the
+Row objects. To add methods to entire resultsets, you will first need
+to subclass L<LDBIx::Class::ResultSet>.
+
+  package Breadcrumbs::Schema::Path::ResultSet;
+  use base 'DBIx::Class::ResultSet';
+
+  sub check_paths {
+    ## $self is a resultset object!
+    my ($self, $root) = @_;
+
+    my $ok = 1;
+    foreach my $path ($self->all) {
+       $ok = 0 if(!-d catfile($root, $path->path));
+    }
+
+    return $ok; 
+  }
+
+To make this module your default resultset for all Path resultsets,
+call C<resultset_class> in your Result class.
+
+  ## Set the new resultset class, in Breadcrumbs::Schema::Path:
+  __PACKAGE__->resultset_class('Breadcrumbs::Schema::Path::ResultSet');
+
+=head1 CONCLUSIONS
+
+=head1 EXERCISES
+
+=head1 WHERE TO GO NEXT
+
+L<Part 4 of the tutorial|DBIx::Class::Tutorial::Part4>
+
+=head1 AUTHOR
+
+Jess Robinson <castaway at desert-island.me.uk>

Added: trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Resultsets.pod
===================================================================
--- trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Resultsets.pod	                        (rev 0)
+++ trunk/DBIx-Class-Tutorial/lib/DBIx/Class/Tutorial/Resultsets.pod	2008-01-17 15:42:33 UTC (rev 3949)
@@ -0,0 +1,41 @@
+
+=head2 Paged resultsets
+
+Quite often we want to cut lists of data into pages for
+display. DBIx::Class provides some useful search attributes to make
+this simple.
+
+C<search> attributes are the second hashref argument to the
+L<DBIx::Class::ResultSet/search> method. You can find descriptions of
+all the available attributes at L<DBIx::Class::ResultSet/ATTRIBUTES>.
+
+To just retrieve the first 10 rows of a query, we can use the C<rows>
+attribute in the search.
+
+  ## Only 10 rows please
+  my $anames_rs = $schema->resultset('Name')->search(
+    { 'me.name' => { 'like' => 'a%' } },
+    { order_by  => [ 'me.name' ],
+      rows      => 10,
+    }
+  );
+
+This appends the appropriate LIMIT or equivalent clause to the SQL clause.
+
+SELECT me.id, me.name FROM Name me
+JOIN Path path ON path.ID = me.PathID
+WHERE me.name LIKE 'a%'
+ORDER BY me.name
+LIMIT 10
+
+  
+=====
+
+To only fetch that one row in the first place, rather than let the database think we wanted them 
+
+  ## Just the names beginning with a:
+  my $anames_rs = $schema->resultset('Name')->search(
+    { 'me.name' => { 'like' => 'a%' } },
+    { order_by  => [ 'me.name' ] }
+  );
+

Modified: trunk/Locale-Object/CHANGES
===================================================================
--- trunk/Locale-Object/CHANGES	2008-01-17 00:03:16 UTC (rev 3948)
+++ trunk/Locale-Object/CHANGES	2008-01-17 15:42:33 UTC (rev 3949)
@@ -1,3 +1,7 @@
+2007-10-22: 0.78
+  - Added "Republic of Serbia" and "Republic of Montenegro", new countries since
+    last year.
+
 2007-09-04: 0.77
   - The Unicode edition. Added currency symbols for numerous currencies
     that had previously been spelt out, like "slashed C" for the Costa Rican

Modified: trunk/Locale-Object/META.yml
===================================================================
--- trunk/Locale-Object/META.yml	2008-01-17 00:03:16 UTC (rev 3948)
+++ trunk/Locale-Object/META.yml	2008-01-17 15:42:33 UTC (rev 3949)
@@ -1,6 +1,6 @@
 ---
 name: Locale-Object
-version: 0.77
+version: 0.78
 author:
   - 'Earle Martin <hex at cpan.org>'
 abstract: An object-oriented representation of locale information.
@@ -23,26 +23,26 @@
 provides:
   Locale::Object:
     file: lib/Locale/Object.pm
-    version: 0.77
+    version: 0.78
   Locale::Object::Continent:
     file: lib/Locale/Object/Continent.pm
-    version: 0.77
+    version: 0.78
   Locale::Object::Country:
     file: lib/Locale/Object/Country.pm
-    version: 0.77
+    version: 0.78
   Locale::Object::Currency:
     file: lib/Locale/Object/Currency.pm
-    version: 0.77
+    version: 0.78
   Locale::Object::Currency::Converter:
     file: lib/Locale/Object/Currency/Converter.pm
-    version: 0.77
+    version: 0.78
   Locale::Object::DB:
     file: lib/Locale/Object/DB.pm
-    version: 0.77
+    version: 0.78
   Locale::Object::Language:
     file: lib/Locale/Object/Language.pm
-    version: 0.77
-generated_by: Module::Build version 0.2805
+    version: 0.78
+generated_by: Module::Build version 0.28
 meta-spec:
   url: http://module-build.sourceforge.net/META-spec-v1.2.html
   version: 1.2

Modified: trunk/Locale-Object/lib/Locale/Object/Continent.pm
===================================================================
--- trunk/Locale-Object/lib/Locale/Object/Continent.pm	2008-01-17 00:03:16 UTC (rev 3948)
+++ trunk/Locale-Object/lib/Locale/Object/Continent.pm	2008-01-17 15:42:33 UTC (rev 3949)
@@ -10,7 +10,7 @@
 use Locale::Object::Country;
 use Locale::Object::DB;
 
-our $VERSION = '0.77';
+our $VERSION = '0.78';
 
 my $db = Locale::Object::DB->new();
 

Modified: trunk/Locale-Object/lib/Locale/Object/Country.pm
===================================================================
--- trunk/Locale-Object/lib/Locale/Object/Country.pm	2008-01-17 00:03:16 UTC (rev 3948)
+++ trunk/Locale-Object/lib/Locale/Object/Country.pm	2008-01-17 15:42:33 UTC (rev 3949)
@@ -14,7 +14,7 @@
 
 use DateTime::TimeZone;
 
-our $VERSION = '0.77';
+our $VERSION = '0.78';
 
 my $db = Locale::Object::DB->new();
 

Modified: trunk/Locale-Object/lib/Locale/Object/Currency/Converter.pm
===================================================================
--- trunk/Locale-Object/lib/Locale/Object/Currency/Converter.pm	2008-01-17 00:03:16 UTC (rev 3948)
+++ trunk/Locale-Object/lib/Locale/Object/Currency/Converter.pm	2008-01-17 15:42:33 UTC (rev 3949)
@@ -6,7 +6,7 @@
 
 use Scalar::Util qw(looks_like_number);
 
-our $VERSION = '0.77';
+our $VERSION = '0.78';
 
 my ($use_xe, $xe_error, $use_yahoo, $yahoo_error);
 

Modified: trunk/Locale-Object/lib/Locale/Object/Currency.pm
===================================================================
--- trunk/Locale-Object/lib/Locale/Object/Currency.pm	2008-01-17 00:03:16 UTC (rev 3948)
+++ trunk/Locale-Object/lib/Locale/Object/Currency.pm	2008-01-17 15:42:33 UTC (rev 3949)
@@ -10,7 +10,7 @@
 use Locale::Object::Country;
 use Locale::Object::DB;
 
-our $VERSION = '0.77';
+our $VERSION = '0.78';
 
 my $db = Locale::Object::DB->new();
 

Modified: trunk/Locale-Object/lib/Locale/Object/DB.pm
===================================================================
--- trunk/Locale-Object/lib/Locale/Object/DB.pm	2008-01-17 00:03:16 UTC (rev 3948)
+++ trunk/Locale-Object/lib/Locale/Object/DB.pm	2008-01-17 15:42:33 UTC (rev 3949)
@@ -7,7 +7,7 @@
 use DBI;
 use File::Spec;
 
-our $VERSION = '0.77';
+our $VERSION = '0.78';
 
 # The database should be in the same directory as this file. Get the location.
 my (undef, $path) = File::Spec->splitpath(__FILE__);

Modified: trunk/Locale-Object/lib/Locale/Object/Language.pm
===================================================================
--- trunk/Locale-Object/lib/Locale/Object/Language.pm	2008-01-17 00:03:16 UTC (rev 3948)
+++ trunk/Locale-Object/lib/Locale/Object/Language.pm	2008-01-17 15:42:33 UTC (rev 3949)
@@ -10,7 +10,7 @@
 use Locale::Object::Country;
 use Locale::Object::DB;
 
-our $VERSION = '0.77';
+our $VERSION = '0.78';
 
 my $db = Locale::Object::DB->new();
 

Modified: trunk/Locale-Object/lib/Locale/Object.pm
===================================================================
--- trunk/Locale-Object/lib/Locale/Object.pm	2008-01-17 00:03:16 UTC (rev 3948)
+++ trunk/Locale-Object/lib/Locale/Object.pm	2008-01-17 15:42:33 UTC (rev 3949)
@@ -9,7 +9,7 @@
 use Locale::Object::Currency;
 use Locale::Object::Language;
 
-our $VERSION = '0.77';
+our $VERSION = '0.78';
 
 sub new
 {

Modified: trunk/Locale-Object/locale.sql
===================================================================
--- trunk/Locale-Object/locale.sql	2008-01-17 00:03:16 UTC (rev 3948)
+++ trunk/Locale-Object/locale.sql	2008-01-17 15:42:33 UTC (rev 3949)
@@ -128,6 +128,7 @@
 INSERT INTO continent VALUES('ml','Africa');
 INSERT INTO continent VALUES('mm','Asia');
 INSERT INTO continent VALUES('mn','Asia');
+INSERT INTO continent VALUES('me','Europe');
 INSERT INTO continent VALUES('mo','Asia');
 INSERT INTO continent VALUES('mq','North America');
 INSERT INTO continent VALUES('mr','Africa');
@@ -163,6 +164,7 @@
 INSERT INTO continent VALUES('qa','Asia');
 INSERT INTO continent VALUES('ro','Europe');
 INSERT INTO continent VALUES('ru','Europe');
+INSERT INTO continent VALUES('rs','Europe');
 INSERT INTO continent VALUES('rw','Africa');
 INSERT INTO continent VALUES('sa','Asia');
 INSERT INTO continent VALUES('sb','Oceania');
@@ -385,6 +387,7 @@
 INSERT INTO country VALUES('ly','lby','434','Libyan Arab Jamahiriya',218);
 INSERT INTO country VALUES('ma','mar','504','Morocco',212);
 INSERT INTO country VALUES('mc','mco','492','Monaco',377);
+INSERT INTO country VALUES('me','mne','499','Republic of Montenegro',382);
 INSERT INTO country VALUES('md','mda','498','Moldova, Republic of',373);
 INSERT INTO country VALUES('mg','mdg','450','Madagascar',261);
 INSERT INTO country VALUES('mh','mhl','584','Marshall Islands',692);
@@ -436,6 +439,7 @@
 INSERT INTO country VALUES('ro','rom','642','Romania',40);
 INSERT INTO country VALUES('ru','rus','643','Russian Federation',7);
 INSERT INTO country VALUES('rw','rwa','646','Rwanda',250);
+INSERT INTO country VALUES('rs','srb','688','Republic of Serbia',381);
 INSERT INTO country VALUES('sa','sau','682','Saudi Arabia',966);
 INSERT INTO country VALUES('sb','slb','090','Solomon Islands',677);
 INSERT INTO country VALUES('sc','syc','690','Seychelles',248);
@@ -504,247 +508,249 @@
     subunit_amount smallint,
     PRIMARY KEY  (country_code)
 );
-INSERT INTO currency VALUES('ad','Euro','EUR','978','€','cents',100);
-INSERT INTO currency VALUES('ae','dirham','AED','784','Dh','fils',100);
 INSERT INTO currency VALUES('af','afghani','AFA','004','Af','puls',100);
-INSERT INTO currency VALUES('ag','dollar','XCD','951','EC$','cents',100);
-INSERT INTO currency VALUES('ai','dollar','XCD','951','EC$','cents',100);
 INSERT INTO currency VALUES('al','lek','ALL','008','L','qindarka',100);
-INSERT INTO currency VALUES('am','dram','AMD','051','','luma',100);
-INSERT INTO currency VALUES('an','guilder','ANG','532','NAf','cents',100);
+INSERT INTO currency VALUES('dz','dinar','DZD','012','DA','centimes',100);
+INSERT INTO currency VALUES('as','dollar','USD','840','$','cents',100);
 INSERT INTO currency VALUES('ao','kwanza','AOA','024','Kz','lwei',100);
-INSERT INTO currency VALUES('aq','none','000',000,NULL,NULL,NULL);
+INSERT INTO currency VALUES('ai','dollar','XCD','951','EC$','cents',100);
+INSERT INTO currency VALUES('ag','dollar','XCD','951','EC$','cents',100);
 INSERT INTO currency VALUES('ar','peso','ARS','032','$','centavos',100);
-INSERT INTO currency VALUES('as','dollar','USD','840','$','cents',100);
-INSERT INTO currency VALUES('at','Euro','EUR','978','€','cents',100);
+INSERT INTO currency VALUES('am','dram','AMD','051','','luma',100);
+INSERT INTO currency VALUES('aw','guilder','AWG','533','Af.','cents',100);
 INSERT INTO currency VALUES('au','dollar','AUD','036','A$','cents',100);
-INSERT INTO currency VALUES('aw','guilder','AWG','533','Af.','cents',100);
+INSERT INTO currency VALUES('at','Euro','EUR','978','','cents',100);
 INSERT INTO currency VALUES('az','manat','AZM','031','','gopik',100);
-INSERT INTO currency VALUES('ba','convertible mark','BAM','977','KM','fennig',100);
+INSERT INTO currency VALUES('bs','dollar','BSD','044','B$','cents',100);
+INSERT INTO currency VALUES('bh','dinar','BHD','048','BD','fils',1000);
+INSERT INTO currency VALUES('bd','taka','BDT','050','Tk','paisa',100);
 INSERT INTO currency VALUES('bb','dollar','BBD','052','Bds$','cents',100);
-INSERT INTO currency VALUES('bd','taka','BDT','050','Tk','paisa',100);
-INSERT INTO currency VALUES('be','Euro','EUR','978','€','cents',100);
-INSERT INTO currency VALUES('bf','franc','XOF','952','CFAF','centimes',100);
-INSERT INTO currency VALUES('bg','leva','BGL','100','Lv','stotinki',100);
-INSERT INTO currency VALUES('bh','dinar','BHD','048','BD','fils',1000);
-INSERT INTO currency VALUES('bi','franc','BIF','108','FBu','centimes',100);
+INSERT INTO currency VALUES('by','ruble','BYR','112','BR','','');
+INSERT INTO currency VALUES('be','Euro','EUR','978','','cents',100);
+INSERT INTO currency VALUES('bz','dollar','BZD','084','BZ$','cents',100);
 INSERT INTO currency VALUES('bj','franc','XOF','952','CFAF','centimes',100);
 INSERT INTO currency VALUES('bm','dollar','BMD','060','Bd$','cents',100);
-INSERT INTO currency VALUES('bn','ringgit','BND','096','B$','sen',100);
+INSERT INTO currency VALUES('bt','ngultrum','BTN','064','Nu','chetrum',100);
 INSERT INTO currency VALUES('bo','boliviano','BOB','068','Bs','centavos',100);
+INSERT INTO currency VALUES('bw','pula','BWP','072','P','thebe',100);
+INSERT INTO currency VALUES('bv','krone','NOK','578','NKr','Ore',100);
 INSERT INTO currency VALUES('br','real','BRL','986','R$','centavos',100);
-INSERT INTO currency VALUES('bs','dollar','BSD','044','B$','cents',100);
-INSERT INTO currency VALUES('bt','ngultrum','BTN','064','Nu.','chhertum',100);
-INSERT INTO currency VALUES('bv','krone','NOK','578','NKr','Ore',100);
-INSERT INTO currency VALUES('bw','pula','BWP','072','P','thebe',100);
-INSERT INTO currency VALUES('by','ruble','BYR','112','BR','','');
-INSERT INTO currency VALUES('bz','dollar','BZD','084','BZ$','cents',100);
+INSERT INTO currency VALUES('bg','leva','BGL','100','Lv','stotinki',100);
+INSERT INTO currency VALUES('bf','franc','XOF','952','CFAF','centimes',100);
+INSERT INTO currency VALUES('bi','franc','BIF','108','FBu','centimes',100);
+INSERT INTO currency VALUES('kh','new riel','KHR','116','CR','sen',100);
+INSERT INTO currency VALUES('cm','franc','XAF','950','CFAF','centimes',100);
 INSERT INTO currency VALUES('ca','dollar','CAD','124','Can$','cents',100);
-INSERT INTO currency VALUES('cc','dollar','AUD','036','A$','cents',100);
-INSERT INTO currency VALUES('cd','franc','CDF','180','CFAF','centimes',100);
+INSERT INTO currency VALUES('ky','dollar','KYD','136','CI$','cents',100);
 INSERT INTO currency VALUES('cf','franc','XAF','950','CFAF','centimes',100);
-INSERT INTO currency VALUES('cg','franc','XAF','950','CFAF','centimes',100);
-INSERT INTO currency VALUES('ch','franc','CHF','756','SwF','centimes',100);
-INSERT INTO currency VALUES('ci','franc','XOF','952','CFAF','centimes',100);
-INSERT INTO currency VALUES('ck','dollar','NZD','554','NZ$','cents',100);
+INSERT INTO currency VALUES('td','franc','XAF','950','CFAF','centimes',100);
 INSERT INTO currency VALUES('cl','peso','CLP','152','Ch$','centavos',100);
-INSERT INTO currency VALUES('cm','franc','XAF','950','CFAF','centimes',100);
-INSERT INTO currency VALUES('cn','yuan renminbi','CNY','156','元','jiao',10);
+INSERT INTO currency VALUES('cn','yuan renminbi','CNY','156','Y','jiao',10);
+INSERT INTO currency VALUES('cx','dollar','AUD','036','A$','cents',100);
+INSERT INTO currency VALUES('cc','dollar','AUD','036','A$','cents',100);
 INSERT INTO currency VALUES('co','peso','COP','170','Col$','centavos',100);
-INSERT INTO currency VALUES('cr','colon','CRC','188','₡','centimos',100);
+INSERT INTO currency VALUES('km','franc','KMF','174','CF','','');
+INSERT INTO currency VALUES('cg','franc','XAF','950','CFAF','centimes',100);
+INSERT INTO currency VALUES('cr','colon','CRC','188','slashed C','centimos',100);
+INSERT INTO currency VALUES('hr','kuna','HRK','191','HRK','lipas',100);
 INSERT INTO currency VALUES('cu','peso','CUP','192','Cu$','centavos',100);
-INSERT INTO currency VALUES('cv','escudo','CVE','132','C.V.Esc','centavos',100);
-INSERT INTO currency VALUES('cx','dollar','AUD','036','A$','cents',100);
 INSERT INTO currency VALUES('cy','pound','CYP','196','C','cents',100);
 INSERT INTO currency VALUES('cz','koruna','CZK','203','Kc','haleru',100);
-INSERT INTO currency VALUES('de','Euro','EUR','978','€','cents',100);
+INSERT INTO currency VALUES('dk','krone','DKK','208','Dkr','Ore',100);
 INSERT INTO currency VALUES('dj','franc','DJF','262','DF','centimes',100);
-INSERT INTO currency VALUES('dk','krone','DKK','208','Dkr','Ore',100);
 INSERT INTO currency VALUES('dm','dollar','XCD','951','EC$','cents',100);
-INSERT INTO currency VALUES('do','peso','DOP','214','RD$','centavos',100);
-INSERT INTO currency VALUES('dz','dinar','DZD','012','DA','centimes',100);
 INSERT INTO currency VALUES('ec','sucre','ECS','218','S/','centavos',100);
-INSERT INTO currency VALUES('ee','kroon','EEK','233','KR','senti',100);
 INSERT INTO currency VALUES('eg','pound','EGP','818','E','piasters',100);
-INSERT INTO currency VALUES('eh','dirham','MAD','504','DH','centimes',100);
+INSERT INTO currency VALUES('sv','colon','SVC','222','','centavos',100);
+INSERT INTO currency VALUES('gq','franc','GQE','226','CFAF','centimos',100);
 INSERT INTO currency VALUES('er','nakfa','ERN','232','Nfa','cents',100);
-INSERT INTO currency VALUES('es','Euro','EUR','978','€','cents',100);
+INSERT INTO currency VALUES('ee','kroon','EEK','233','KR','senti',100);
 INSERT INTO currency VALUES('et','birr','ETB','230','Br','cents',100);
-INSERT INTO currency VALUES('fi','Euro','EUR','978','€','cents',100);
 INSERT INTO currency VALUES('fj','dollar','FJD','242','F$','cents',100);
-INSERT INTO currency VALUES('fk','pound','FKP','238','F','pence',100);
-INSERT INTO currency VALUES('fm','dollar','USD','840','$','cents',100);
-INSERT INTO currency VALUES('fo','krone','DKK','208','DKr','Ore',100);
-INSERT INTO currency VALUES('fr','Euro','EUR','978','€','cents',100);
-INSERT INTO currency VALUES('fx','Euro','EUR','978','€','cents',100);
+INSERT INTO currency VALUES('fi','Euro','EUR','978','','cents',100);
+INSERT INTO currency VALUES('fr','Euro','EUR','978','','cents',100);
+INSERT INTO currency VALUES('gf','Euro','EUR','978','','cents',100);
+INSERT INTO currency VALUES('pf','franc','XPF','953','CFPF','centimes',100);
 INSERT INTO currency VALUES('ga','franc','XAF','950','CFAF','centimes',100);
-INSERT INTO currency VALUES('gb','pound','GBP','826','£','pence',100);
-INSERT INTO currency VALUES('gd','dollar','XCD','951','EC$','cents',100);
+INSERT INTO currency VALUES('gm','dalasi','GMD','270','D','butut',100);
 INSERT INTO currency VALUES('ge','lari','GEL','981','','tetri',100);
-INSERT INTO currency VALUES('gf','Euro','EUR','978','€','cents',100);
+INSERT INTO currency VALUES('de','Euro','EUR','978','','cents',100);
 INSERT INTO currency VALUES('gh','new cedi','GHC','288','','psewas',100);
 INSERT INTO currency VALUES('gi','pound','GIP','292','G','pence',100);
+INSERT INTO currency VALUES('gr','Euro','EUR','978','','cents',100);
 INSERT INTO currency VALUES('gl','krone','DKK','208','Dkr','Ore',100);
-INSERT INTO currency VALUES('gm','dalasi','GMD','270','D','butut',100);
-INSERT INTO currency VALUES('gn','franc','GNF','324','','','');
-INSERT INTO currency VALUES('gp','Euro','EUR','978','€','cents',100);
-INSERT INTO currency VALUES('gq','franc','GQE','226','CFAF','centimos',100);
-INSERT INTO currency VALUES('gr','Euro','EUR','978','€','cents',100);
-INSERT INTO currency VALUES('gs','pound','GBP','826',NULL,'pence',100);
+INSERT INTO currency VALUES('gd','dollar','XCD','951','EC$','cents',100);
+INSERT INTO currency VALUES('gp','Euro','EUR','978','','cents',100);
+INSERT INTO currency VALUES('gu','dollar','USD','840','$','cents',100);
 INSERT INTO currency VALUES('gt','quetzal','GTQ','320','Q','centavos',100);
-INSERT INTO currency VALUES('gu','dollar','USD','840','$','cents',100);
 INSERT INTO currency VALUES('gw','franc','XOF','952','CFAF','centimes',100);
+INSERT INTO currency VALUES('gn','franc','GNF','324','','','');
 INSERT INTO currency VALUES('gy','dollar','GYD','328','G$','cents',100);
+INSERT INTO currency VALUES('ht','gourde','HTG','332','G','centimes',100);
+INSERT INTO currency VALUES('hn','lempira','HNL','340','L','centavos',100);
 INSERT INTO currency VALUES('hk','dollar','HKD','344','HK$','cents',100);
-INSERT INTO currency VALUES('hm','dollar','AUD','036','A$','cents',100);
-INSERT INTO currency VALUES('hn','lempira','HNL','340','L','centavos',100);
-INSERT INTO currency VALUES('hr','kuna','HRK','191','HRK','lipas',100);
-INSERT INTO currency VALUES('ht','gourde','HTG','332','G','centimes',100);
 INSERT INTO currency VALUES('hu','forint','HUF','348','Ft','','');
+INSERT INTO currency VALUES('is','krna','ISK','352','IKr','aurar',100);
+INSERT INTO currency VALUES('in','rupee','INR','356','Rs','paise',100);
 INSERT INTO currency VALUES('id','rupiah','IDR','360','Rp','sen',100);
-INSERT INTO currency VALUES('ie','Euro','EUR','978','€','cents',100);
-INSERT INTO currency VALUES('il','new sheqel','ILS','376','₪','new agorot',100);
-INSERT INTO currency VALUES('in','rupee','INR','356','Rs','paise',100);
-INSERT INTO currency VALUES('io','pound','GBP','826',NULL,'pence',100);
 INSERT INTO currency VALUES('iq','dinar','IQD','368','ID','fils',1000);
-INSERT INTO currency VALUES('ir','rial','IRR','364','Rls','','');
-INSERT INTO currency VALUES('is','krna','ISK','352','IKr','aurar',100);
-INSERT INTO currency VALUES('it','Euro','EUR','978','€','cents',100);
+INSERT INTO currency VALUES('ie','Euro','EUR','978','','cents',100);
+INSERT INTO currency VALUES('il','new shekel','ILS','376','NIS','new agorot',100);
+INSERT INTO currency VALUES('it','Euro','EUR','978','','cents',100);
 INSERT INTO currency VALUES('jm','dollar','JMD','388','J$','cents',100);
+INSERT INTO currency VALUES('jp','yen','JPY','392','','sen',100);
 INSERT INTO currency VALUES('jo','dinar','JOD','400','JD','fils',1000);
-INSERT INTO currency VALUES('jp','yen','JPY','392','','sen',100);
+INSERT INTO currency VALUES('kz','tenge','KZT','398','','tiyn',100);
 INSERT INTO currency VALUES('ke','shilling','KES','404','K Sh','cents',100);
-INSERT INTO currency VALUES('kg','som','KGS','417','','tyyn',100);
-INSERT INTO currency VALUES('kh','new riel','KHR','116','CR','sen',100);
 INSERT INTO currency VALUES('ki','dollar','AUD','036','A$','cents',100);
-INSERT INTO currency VALUES('km','franc','KMF','174','CF','','');
-INSERT INTO currency VALUES('kn','dollar','XCD','951','EC$','cents',100);
-INSERT INTO currency VALUES('kp','won','KPW','408','₩','chon',100);
-INSERT INTO currency VALUES('kr','won','KRW','410','₩','chon',100);
 INSERT INTO currency VALUES('kw','dinar','KWD','414','KD','fils',1000);
-INSERT INTO currency VALUES('ky','dollar','KYD','136','CI$','cents',100);
-INSERT INTO currency VALUES('kz','tenge','KZT','398','','tiyn',100);
-INSERT INTO currency VALUES('la','new kip','LAK','418','₭','at',100);
+INSERT INTO currency VALUES('kg','som','KGS','417','','tyyn',100);
+INSERT INTO currency VALUES('lv','lat','LVL','428','Ls','santims',100);
 INSERT INTO currency VALUES('lb','pound','LBP','422','L.L.','piastres',100);
-INSERT INTO currency VALUES('lc','dollar','XCD','951','EC$','cents',100);
-INSERT INTO currency VALUES('li','franc','CHF','756','SwF','centimes',100);
-INSERT INTO currency VALUES('lk','rupee','LKR','144','SLRs','cents',100);
+INSERT INTO currency VALUES('ls','loti','LSL','426','L, pl., M','lisente',100);
 INSERT INTO currency VALUES('lr','dollar','LRD','430','$','cents',100);
-INSERT INTO currency VALUES('ls','loti','LSL','426','L','lisente',100);
-INSERT INTO currency VALUES('lt','litas','LTL','440','','centu',100);
+INSERT INTO currency VALUES('lt','litas, pl., litai','LTL','440','','centu',100);
 INSERT INTO currency VALUES('lu','Euro','EUR','978','','cents',100);
-INSERT INTO currency VALUES('lv','lat','LVL','428','Ls','santims',100);
-INSERT INTO currency VALUES('ly','dinar','LYD','434','LD','dirhams',1000);
-INSERT INTO currency VALUES('ma','dirham','MAD','504','DH','centimes',100);
-INSERT INTO currency VALUES('mc','Euro','EUR','978','€','cents',100);
-INSERT INTO currency VALUES('md','leu','MDL','498',NULL,NULL,NULL);
+INSERT INTO currency VALUES('mo','pataca','MOP','446','P','avos',100);
+INSERT INTO currency VALUES('mk','denar','MKD','807','MKD','deni',100);
 INSERT INTO currency VALUES('mg','ariayry','MGF','450','FMG','francs',5);
-INSERT INTO currency VALUES('mh','dollar','USD','840','$','cents',100);
-INSERT INTO currency VALUES('mk','denar','MKD','807','MKD','deni',100);
+INSERT INTO currency VALUES('mw','kwacha','MWK','454','MK','tambala',100);
+INSERT INTO currency VALUES('my','ringgit','MYR','458','RM','sen',100);
+INSERT INTO currency VALUES('mv','rufiyaa','MVR','462','Rf','lari',100);
 INSERT INTO currency VALUES('ml','franc','XOF','952','CFAF','centimes',100);
-INSERT INTO currency VALUES('mm','kyat','MMK','104','K','pyas',100);
-INSERT INTO currency VALUES('mn','tögrög','MNT','496','₮','möngö',100);
-INSERT INTO currency VALUES('mo','pataca','MOP','446','P','avos',100);
-INSERT INTO currency VALUES('mp','dollar','USD','840','$','cents',100);
-INSERT INTO currency VALUES('mq','Euro','EUR','978','€','cents',100);
+INSERT INTO currency VALUES('mt','lira, pl., liri','MTL','470','Lm','cents',100);
+INSERT INTO currency VALUES('mq','Euro','EUR','978','','cents',100);
 INSERT INTO currency VALUES('mr','ouguiya','MRO','478','UM','khoums',5);
-INSERT INTO currency VALUES('ms','dollar','XCD','951','EC$','cents',100);
-INSERT INTO currency VALUES('mt','lira','MTL','470','Lm','cents',100);
 INSERT INTO currency VALUES('mu','rupee','MUR','480','Mau Rs','cents',100);
-INSERT INTO currency VALUES('mv','rufiyaa','MVR','462','Rf','lari',100);
-INSERT INTO currency VALUES('mw','kwacha','MWK','454','MK','tambala',100);
 INSERT INTO currency VALUES('mx','peso','MXN','484','Mex$','centavos',100);
-INSERT INTO currency VALUES('my','ringgit','MYR','458','RM','sen',100);
+INSERT INTO currency VALUES('mc','Euro','EUR','978','','cents',100);
+INSERT INTO currency VALUES('mn','tughrik','MNT','496','Tug','mongos',100);
+INSERT INTO currency VALUES('ms','dollar','XCD','951','EC$','cents',100);
+INSERT INTO currency VALUES('ma','dirham','MAD','504','DH','centimes',100);
 INSERT INTO currency VALUES('mz','metical','MZM','508','Mt','centavos',100);
+INSERT INTO currency VALUES('mm','kyat','MMK','104','K','pyas',100);
+INSERT INTO currency VALUES('nr','dollar','AUD','036','A$','cents',100);
 INSERT INTO currency VALUES('na','dollar','NAD','516','N$','cents',100);
+INSERT INTO currency VALUES('np','rupee','NPR','524','NRs','paise',100);
+INSERT INTO currency VALUES('nl','Euro','EUR','978','','cents',100);
 INSERT INTO currency VALUES('nc','franc','XPF','953','CFPF','centimes',100);
+INSERT INTO currency VALUES('nz','dollar','NZD','554','NZ$','cents',100);
+INSERT INTO currency VALUES('ni','gold cordoba','NIO','558','C$','centavos',100);
 INSERT INTO currency VALUES('ne','franc','XOF','952','CFAF','centimes',100);
+INSERT INTO currency VALUES('ng','naira','NGN','566','double-dashed N','kobo',100);
 INSERT INTO currency VALUES('nf','dollar','AUD','036','A$','cents',100);
-INSERT INTO currency VALUES('ng','naira','NGN','566','₦','kobo',100);
-INSERT INTO currency VALUES('ni','gold cordoba','NIO','558','C$','centavos',100);
-INSERT INTO currency VALUES('nl','Euro','EUR','978','€','cents',100);
 INSERT INTO currency VALUES('no','krone','NOK','578','NKr','Ore',100);
-INSERT INTO currency VALUES('np','rupee','NPR','524','NRs','paise',100);
-INSERT INTO currency VALUES('nr','dollar','AUD','036','A$','cents',100);
-INSERT INTO currency VALUES('nu','dollar','NZD','554','NZ$','cents',100);
-INSERT INTO currency VALUES('nz','dollar','NZD','554','NZ$','cents',100);
 INSERT INTO currency VALUES('om','rial','OMR','512','RO','baizas',1000);
+INSERT INTO currency VALUES('pk','rupee','PKR','586','Rs','paisa',100);
+INSERT INTO currency VALUES('pw','dollar','USD','840','$','cents',100);
 INSERT INTO currency VALUES('pa','balboa','PAB','590','B','centesimos',100);
-INSERT INTO currency VALUES('pe','nuevo sol','PEN','604','S/.','centimos',100);
-INSERT INTO currency VALUES('pf','franc','XPF','953','CFPF','centimes',100);
 INSERT INTO currency VALUES('pg','kina','PGK','598','K','toeas',100);
-INSERT INTO currency VALUES('ph','peso','PHP','608','₱','centavos',100);
-INSERT INTO currency VALUES('pk','rupee','PKR','586','Rs','paisa',100);
-INSERT INTO currency VALUES('pl','zloty','PLN','985','zł','groszy',100);
-INSERT INTO currency VALUES('pm','Euro','EUR','978','€','cents',100);
-INSERT INTO currency VALUES('pn','dollar','NZD','554','NZ$','cents',100);
+INSERT INTO currency VALUES('py','guarani','PYG','600','slashed G','centimos',100);
+INSERT INTO currency VALUES('pe','new sol','PEN','604','S/.','centimos',100);
+INSERT INTO currency VALUES('ph','peso','PHP','608','dashed P','centavos',100);
+INSERT INTO currency VALUES('pl','zloty','PLN','985','z dashed l','groszy',100);
+INSERT INTO currency VALUES('pt','Euro','EUR','978','','cents',100);
 INSERT INTO currency VALUES('pr','dollar','USD','840','$','cents',100);
-INSERT INTO currency VALUES('ps','new shekel','ILS','376','NIS','new agorot',100);
-INSERT INTO currency VALUES('pt','Euro','EUR','978','€','cents',100);
-INSERT INTO currency VALUES('pw','dollar','USD','840','$','cents',100);
-INSERT INTO currency VALUES('py','guarani','PYG','600','G.','centimos',100);
 INSERT INTO currency VALUES('qa','riyal','QAR','634','QR','dirhams',100);
-INSERT INTO currency VALUES('re','Euro','EUR','978','€','cents',100);
+INSERT INTO currency VALUES('re','Euro','EUR','978','','cents',100);
 INSERT INTO currency VALUES('ro','leu','ROL','642','L','bani',100);
-INSERT INTO currency VALUES('ru','ruble','RUB','810','руб','kopecks',100);
 INSERT INTO currency VALUES('rw','franc','RWF','646','RF','centimes',100);
 INSERT INTO currency VALUES('sa','riyal','SAR','682','SRls','halalat',100);
-INSERT INTO currency VALUES('sb','dollar','SBD','090','SI$','cents',100);
+INSERT INTO currency VALUES('sn','franc','XOF','952','CFAF','centimes',100);
 INSERT INTO currency VALUES('sc','rupee','SCR','690','SR','cents',100);
-INSERT INTO currency VALUES('sd','dinar','SDP','736','','piastres',100);
-INSERT INTO currency VALUES('se','krona','SEK','752','Sk','Ore',100);
+INSERT INTO currency VALUES('sl','leone','SLL','694','Le','cents',100);
 INSERT INTO currency VALUES('sg','dollar','SGD','702','S$','cents',100);
-INSERT INTO currency VALUES('sh','pound','SHP','654','S','new pence',100);
+INSERT INTO currency VALUES('sk','koruna','SKK','703','Sk','halierov',100);
 INSERT INTO currency VALUES('si','tolar','SIT','705','SlT','stotinov',100);
-INSERT INTO currency VALUES('sj','krone','NOK','578','NKr','Ore',100);
-INSERT INTO currency VALUES('sk','koruna','SKK','703','Sk','halierov',100);
-INSERT INTO currency VALUES('sl','leone','SLL','694','Le','cents',100);
-INSERT INTO currency VALUES('sm','Euro','EUR','978','€','cents',100);
-INSERT INTO currency VALUES('sn','franc','XOF','952','CFAF','centimes',100);
 INSERT INTO currency VALUES('so','shilling','SOS','706','So. Sh.','centesimi',100);
+INSERT INTO currency VALUES('za','rand','ZAR','710','R','cents',100);
+INSERT INTO currency VALUES('es','Euro','EUR','978','','cents',100);
+INSERT INTO currency VALUES('lk','rupee','LKR','144','SLRs','cents',100);
+INSERT INTO currency VALUES('sd','dinar','SDP','736','','piastres',100);
 INSERT INTO currency VALUES('sr','guilder','SRG','740','Sf.','cents',100);
-INSERT INTO currency VALUES('st','dobra','STD','678','Db','centimos',100);
-INSERT INTO currency VALUES('sv','colon','SVC','222','','centavos',100);
-INSERT INTO currency VALUES('sy','pound','SYP','760','S','piasters',100);
 INSERT INTO currency VALUES('sz','lilangeni','SZL','748','L','cents',100);
-INSERT INTO currency VALUES('tc','dollar','USD','840','$','cents',100);
-INSERT INTO currency VALUES('td','franc','XAF','950','CFAF','centimes',100);
-INSERT INTO currency VALUES('tf','Euro','EUR','978','€','cents',100);
+INSERT INTO currency VALUES('se','krona','SEK','752','Sk','Ore',100);
+INSERT INTO currency VALUES('ch','franc','CHF','756','SwF','centimes',100);
+INSERT INTO currency VALUES('tj','somoni','TJS','762','','dirams',100);
+INSERT INTO currency VALUES('th','baht','THB','764','Bht or Bt','stang',100);
 INSERT INTO currency VALUES('tg','franc','XOF','952','CFAF','centimes',100);
-INSERT INTO currency VALUES('th','baht','THB','764','฿','stang',100);
-INSERT INTO currency VALUES('tj','somoni','TJS','762','','dirams',100);
-INSERT INTO currency VALUES('tk','dollar','NZD','554','NZ$','cents',100);
-INSERT INTO currency VALUES('tl','rupiah','IDR','360','Rp','sen',100);
-INSERT INTO currency VALUES('tm','manat','TMM','795','','tenga',100);
+INSERT INTO currency VALUES('to','pa''anga','TOP','776','PT or T$','seniti',100);
+INSERT INTO currency VALUES('tt','dollar','TTD','780','TT$','cents',100);
 INSERT INTO currency VALUES('tn','dinar','TND','788','TD','millimes',1000);
-INSERT INTO currency VALUES('to','pa''anga','TOP','776','PT or T$','seniti',100);
 INSERT INTO currency VALUES('tr','lira','TRL','792','TL','kurus',100);
-INSERT INTO currency VALUES('tt','dollar','TTD','780','TT$','cents',100);
+INSERT INTO currency VALUES('tm','manat','TMM','795','','tenga',100);
+INSERT INTO currency VALUES('tc','dollar','USD','840','$','cents',100);
 INSERT INTO currency VALUES('tv','dollar','AUD','036','A$','cents',100);
-INSERT INTO currency VALUES('tw','new dollar','TWD','901','NT$','cents',100);
-INSERT INTO currency VALUES('tz','shilling','TZS','834','TSh','cents',100);
+INSERT INTO currency VALUES('ug','shilling','UGX','800','USh','cents',100);
 INSERT INTO currency VALUES('ua','Hryvnia','UAH','980','','kopiykas',100);
-INSERT INTO currency VALUES('ug','shilling','UGX','800','USh','cents',100);
-INSERT INTO currency VALUES('um','dollar','USD','840','$','cents',100);
-INSERT INTO currency VALUES('us','dollar','USD','840','$','cents',100);
+INSERT INTO currency VALUES('ae','dirham','AED','784','Dh','fils',100);
 INSERT INTO currency VALUES('uy','peso uruguayo','UYU','858','$U','centsimos',100);
 INSERT INTO currency VALUES('uz','som','UZS','860','','tiyin',100);
-INSERT INTO currency VALUES('va','Euro','EUR','978','€','cents',100);
-INSERT INTO currency VALUES('vc','dollar','XCD','951','EC$','cents',100);
+INSERT INTO currency VALUES('vu','vatu','VUV','548','VT','centimes',100);
 INSERT INTO currency VALUES('ve','bolivar','VEB','862','Bs','centimos',100);
+INSERT INTO currency VALUES('vn','dong','VND','704','dashed d, or D','hao or 100 xu',10);
+INSERT INTO currency VALUES('ye','rial','YER','886','YRls','fils',100);
+INSERT INTO currency VALUES('rs','dinar','YUM','891','Din','paras',100);
+INSERT INTO currency VALUES('me','dinar','YUM','891','Din','paras',100);
+INSERT INTO currency VALUES('yu','dinar','YUM','891','Din','paras',100);
+INSERT INTO currency VALUES('zm','kwacha','ZMK','894','ZK','ngwee',100);
+INSERT INTO currency VALUES('zw','dollar','ZWD','716','Z$','cents',100);
+INSERT INTO currency VALUES('ba','convertible mark','BAM','977','KM','fennig',100);
 INSERT INTO currency VALUES('vg','dollar','USD','840','$','cents',100);
+INSERT INTO currency VALUES('bn','ringgit','BND','096','B$','sen',100);
+INSERT INTO currency VALUES('ci','franc','XOF','952','CFAF','centimes',100);
+INSERT INTO currency VALUES('do','peso','DOP','214','RD$','centavos',100);
+INSERT INTO currency VALUES('fk','pound','FKP','238','F','pence',100);
+INSERT INTO currency VALUES('gb','pound','GBP','826','£','pence',100);
+INSERT INTO currency VALUES('ir','rial','IRR','364','Rls','','');
+INSERT INTO currency VALUES('kp','won','KPW','408','Wn','chon',100);
+INSERT INTO currency VALUES('kr','won','KRW','410','W','chon',100);
+INSERT INTO currency VALUES('la','new kip','LAK','418','KN','at',100);
+INSERT INTO currency VALUES('ly','dinar','LYD','434','LD','dirhams',1000);
+INSERT INTO currency VALUES('ru','ruble','RUB','810','R','kopecks',100);
+INSERT INTO currency VALUES('sh','pound','SHP','654','S','new pence',100);
+INSERT INTO currency VALUES('sy','pound','SYP','760','S','piasters',100);
+INSERT INTO currency VALUES('tz','shilling','TZS','834','TSh','cents',100);
+INSERT INTO currency VALUES('us','dollar','USD','840','$','cents',100);
 INSERT INTO currency VALUES('vi','dollar','USD','840','$','cents',100);
-INSERT INTO currency VALUES('vn','đồng','VND','704','₫','hào',10);
-INSERT INTO currency VALUES('vu','vatu','VUV','548','VT','centimes',100);
 INSERT INTO currency VALUES('wf','franc','XPF','953','CFPF','centimes',100);
 INSERT INTO currency VALUES('ws','tala','WST','882','WS$','sene',100);
-INSERT INTO currency VALUES('ye','rial','YER','886','YRls','fils',100);
-INSERT INTO currency VALUES('yt','Euro','EUR','978','€','cents',100);
-INSERT INTO currency VALUES('yu','dinar','YUM','891','Din','paras',100);
-INSERT INTO currency VALUES('za','rand','ZAR','710','R','cents',100);
-INSERT INTO currency VALUES('zm','kwacha','ZMK','894','ZK','ngwee',100);
+INSERT INTO currency VALUES('tw','new dollar','TWD','901','NT$','cents',100);
+INSERT INTO currency VALUES('tl','rupiah','IDR','360','Rp','sen',100);
+INSERT INTO currency VALUES('ps','new shekel','ILS','376','NIS','new agorot',100);
+INSERT INTO currency VALUES('mh','dollar','USD','840','$','cents',100);
+INSERT INTO currency VALUES('ad','Euro','EUR','978',NULL,'cents',100);
+INSERT INTO currency VALUES('an','guilder','ANG','532','NAf','cents',100);
+INSERT INTO currency VALUES('aq','none','000',000,NULL,NULL,NULL);
+INSERT INTO currency VALUES('ck','dollar','NZD','554','NZ$','cents',100);
+INSERT INTO currency VALUES('cv','escudo','CVE','132','C.V.Esc','centavos',100);
+INSERT INTO currency VALUES('eh','dirham','MAD','504','DH','centimes',100);
+INSERT INTO currency VALUES('fm','dollar','USD','840','$','cents',100);
+INSERT INTO currency VALUES('fo','krone','DKK','208','DKr','Ore',100);
+INSERT INTO currency VALUES('fx','Euro','EUR','978','','cents',100);
+INSERT INTO currency VALUES('gs','pound','GBP','826',NULL,'pence',100);
+INSERT INTO currency VALUES('hm','dollar','AUD','036','A$','cents',100);
+INSERT INTO currency VALUES('io','pound','GBP','826',NULL,'pence',100);
+INSERT INTO currency VALUES('kn','dollar','XCD','951','EC$','cents',100);
+INSERT INTO currency VALUES('lc','dollar','XCD','951','EC$','cents',100);
+INSERT INTO currency VALUES('li','franc','CHF','756','SwF','centimes',100);
+INSERT INTO currency VALUES('md','leu','MDL','498',NULL,NULL,NULL);
+INSERT INTO currency VALUES('mp','dollar','USD','840','$','cents',100);
+INSERT INTO currency VALUES('nu','dollar','NZD','554','NZ$','cents',100);
+INSERT INTO currency VALUES('pm','Euro','EUR','978','null','cents',100);
+INSERT INTO currency VALUES('pn','dollar','NZD','554','NZ$','cents',100);
+INSERT INTO currency VALUES('sb','dollar','SBD','090','SI$','cents',100);
+INSERT INTO currency VALUES('sj','krone','NOK','578','NKr','Ore',100);
+INSERT INTO currency VALUES('sm','Euro','EUR','978','null','cents',100);
+INSERT INTO currency VALUES('st','dobra','STD','678','Db','centimos',100);
+INSERT INTO currency VALUES('tf','Euro','EUR','978','null','cents',100);
+INSERT INTO currency VALUES('tk','dollar','NZD','554','NZ$','cents',100);
+INSERT INTO currency VALUES('um','dollar','USD','840','$','cents',100);
+INSERT INTO currency VALUES('va','Euro','EUR','978','null','cents',100);
+INSERT INTO currency VALUES('vc','dollar','XCD','951','EC$','cents',100);
+INSERT INTO currency VALUES('yt','Euro','EUR','978','null','cents',100);
 INSERT INTO currency VALUES('zr','franc','XAF','950','CFAF','centimes',100);
-INSERT INTO currency VALUES('zw','dollar','ZWD','716','Z$','cents',100);
+INSERT INTO currency VALUES('cd','franc','CDF','180','CFAF','centimes',100);
 CREATE TABLE language (
     code_alpha2  char(2),
     code_alpha3  char(3),
@@ -1601,6 +1607,9 @@
 INSERT INTO language_mappings VALUES('cd_0','cd','fre','true');
 INSERT INTO language_mappings VALUES('cd_1','cd','lin','false');
 INSERT INTO language_mappings VALUES('cd_2','cd','swa','false');
+INSERT INTO language_mappings VALUES('rs_0','rs','srp','true');
+INSERT INTO language_mappings VALUES('rs_1','me','srp','true');
+-- Need more non-official serbian langs here!
 CREATE TABLE timezone (
     country_code          char(2),
     timezone              char(50),




More information about the Bast-commits mailing list