The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Rose::DB::Object::Loader - Automatically create Rose::DB::Object subclasses for all the tables in a database.

SYNOPSIS

Sample database schema:

  CREATE TABLE vendors
  (
    id    SERIAL NOT NULL PRIMARY KEY,
    name  VARCHAR(255) NOT NULL,

    UNIQUE(name)
  );

  CREATE TABLE products
  (
    id      SERIAL NOT NULL PRIMARY KEY,
    name    VARCHAR(255) NOT NULL,
    price   DECIMAL(10,2) NOT NULL DEFAULT 0.00,

    vendor_id  INT REFERENCES vendors (id),

    status  VARCHAR(128) NOT NULL DEFAULT 'inactive' 
              CHECK(status IN ('inactive', 'active', 'defunct')),

    date_created  TIMESTAMP NOT NULL DEFAULT NOW(),
    release_date  TIMESTAMP,

    UNIQUE(name)
  );

  CREATE TABLE prices
  (
    id          SERIAL NOT NULL PRIMARY KEY,
    product_id  INT NOT NULL REFERENCES products (id),
    region      CHAR(2) NOT NULL DEFAULT 'US',
    price       DECIMAL(10,2) NOT NULL DEFAULT 0.00,

    UNIQUE(product_id, region)
  );

  CREATE TABLE colors
  (
    id    SERIAL NOT NULL PRIMARY KEY,
    name  VARCHAR(255) NOT NULL,

    UNIQUE(name)
  );

  CREATE TABLE product_color_map
  (
    product_id  INT NOT NULL REFERENCES products (id),
    color_id    INT NOT NULL REFERENCES colors (id),

    PRIMARY KEY(product_id, color_id)
  );

To start, make a Rose::DB::Object::Loader object, specifying the database connection information and an optional class name prefix.

  $loader = 
    Rose::DB::Object::Loader->new(
      db_dsn       => 'dbi:Pg:dbname=mydb;host=localhost',
      db_username  => 'someuser',
      db_password  => 'mysecret',
      db_options   => { AutoCommit => 1, ChopBlanks => 1 },
      class_prefix => 'My::Corp');

It's even easier to specify the database information if you've set up Rose::DB (say, by following the instructions in Rose::DB::Tutorial). Just pass a Rose::DB-derived object pointing to the database you're interested in.

  $loader = 
    Rose::DB::Object::Loader->new(
      db           => My::Corp::DB->new('main'),
      class_prefix => 'My::Corp');

Finally, automatically create Rose::DB::Object subclasses for all the tables in the database. All it takes is one method call.

  $loader->make_classes;

Here's what you get for your effort.

  My::Corp::Product->new(name => 'Sled');

  $p->vendor(name => 'Acme');

  $p->prices({ price => 1.23, region => 'US' },
             { price => 4.56, region => 'UK' });

  $p->colors({ name => 'red'   }, 
             { name => 'green' });

  $p->save;

  $products = 
    My::Corp::Product::Manager->get_products_iterator(
      query           => [ name => { like => '%le%' } ],
      with_objects    => [ 'prices' ],
      require_objects => [ 'vendor' ],
      sort_by         => 'vendor.name');

  $p = $products->next;

  print $p->vendor->name; # Acme

  # US: 1.23, UK: 4.56
  print join(', ', map { $_->region . ': ' . $_->price } $p->prices);

See the Rose::DB::Object and Rose::DB::Object::Manager documentation for learn more about the features these classes provide.

The contents of the database now look like this.

  mydb=# select * from products;
   id |  name  | price | vendor_id |  status  |       date_created
  ----+--------+-------+-----------+----------+-------------------------
    1 | Sled 3 |  0.00 |         1 | inactive | 2005-11-19 22:09:20.7988 


  mydb=# select * from vendors;
   id |  name  
  ----+--------
    1 | Acme 3


  mydb=# select * from prices;
   id | product_id | region | price 
  ----+------------+--------+-------
    1 |          1 | US     |  1.23
    2 |          1 | UK     |  4.56


  mydb=# select * from colors;
   id | name  
  ----+-------
    1 | red
    2 | green


  mydb=# select * from product_color_map;
   product_id | color_id 
  ------------+----------
            1 |        1
            1 |        2

DESCRIPTION

Rose::DB::Object::Loader will automatically create Rose::DB::Object subclasses for all the tables in a database. It will configure column data types, default values, primary keys, unique keys, and foreign keys. It can also discover and set up inter-table relationships. It uses Rose::DB::Object's auto-initialization capabilities to do all of this.

To do its work, the loader needs to know how to connect to the database. This information can be provided in several ways. The recommended practice is to set up Rose::DB according to the instructions in the Rose::DB::Tutorial, and then pass a Rose::DB-derived object or class name to the loader. The loader will also accept traditional DBI-style connection information: DSN, username, password, etc.

Once the loader object is configured, the make_classes method does all the work. It takes a few options specifying which tables to make classes for, whether or not to make manager classes for each table, and a few other options. The convention manager is used to convert table names to class names, generate foreign key and relationship method names, and so on. The result of this process is a suite of Rose::DB::Object (and Rose::DB::Object::Manager) subclasses ready for use.

Rose::DB::Object::Loader inherits from, and follows the conventions of, Rose::Object. See the Rose::Object documentation for more information.

CONSTRUCTOR

new PARAMS

Returns a new Rose::DB::Object::Loader constructed according to PARAMS, where PARAMS are name/value pairs. Any object method is a valid parameter name.

OBJECT METHODS

base_class CLASS

This is an alias for the base_classes method.

base_classes [ CLASS | ARRAYREF ]

Get or set the list of base classes to use for the Rose::DB::Object subclasses created by the make_classes method. The argument may be a class name or a reference to an array of class names. At least one of the classes must inherit from Rose::DB::Object.

Returns a list (in list context) or reference to an array (in scalar context) of base class names. Defaults to a dynamically-generated Rose::DB::Object subclass name.

class_prefix [PREFIX]

Get or set the prefix affixed to all class names created by the make_classes method. If PREFIX doesn't end in "::", it will be added automatically.

convention_manager [ CLASS | MANAGER ]

Get or set the Rose::DB::Object::ConventionManager-derived class name or object to be used during the auto-initialization process for each class created by the make_classes method. Returns a Rose::DB::Object::ConventionManager-derived object, which defaults to a new Rose::DB::Object::ConventionManager object.

db [DB]

Get or set the Rose::DB-derived object used to connect to the database. This object will be used by the make_classes method when extracting information from the database. It will also be used as the prototype for the db object used by each Rose::DB::Object subclass to connect to the database.

Setting this attribute also sets the db_class attributes, overwriting any previously existing value, and sets the db_dsn value to undef.

db_catalog [CATALOG]

Get or set the catalog for the database connection.

db_class [CLASS]

Get or set the name of the Rose::DB-derived class used by the make_classes method to construct a db object if one has not been set via the method of the same name.

Setting this attribute sets the db attribute to undef unless its class is the same as CLASS.

db_dsn [DSN]

Get or set the DBI-style Data Source Name (DSN) used to connect to the database. This will be used by the make_classes method when extracting information from the database. The Rose::DB-derived objects used by each Rose::DB::Object subclass to connect to the database will be initialized with this DSN.

Setting this attribute immediately sets the dsn of the db attribute, if it is defined.

db_options [HASHREF]

Get or set the options used to connect to the database.

db_password [PASSWORD]

Get or set the password used to connect to the database.

db_schema [SCHEMA]

Get or set the schema for the database connection.

db_username [USERNAME]

Get or set the username used to connect to the database.

include_tables REGEX

Table names that do not match REGEX will be skipped by default during calls to the make_classes method.

exclude_tables REGEX

Table names that match REGEX will be skipped during calls to the make_classes method.

filter_tables CODEREF

A reference to a subroutine that takes a single table name argument and returns true if the table should be processed by default during calls to the make_classes method, false if the table should be skipped. The $_ variable will also be set to the table name before the call to CODEREF.

This attribute should not be combined with the exclude_tables or include_tables attributes.

generate_manager_class_name CLASS

Given the name of a Rose::DB::Object-derived class, returns a class name for a Rose::DB::Object::Manager-derived class to manage such objects. The default implementation calls the auto_manager_class_name method on the convention_manager object.

include_views BOOL

If true, database views will also be processed by default during calls to the make_classes method. Defaults to false.

make_classes [PARAMS]

Automatically create Rose::DB::Object and (optionally) Rose::DB::Object::Manager subclasses for some or all of the tables in a database. The process is controlled by the object attributes described above. Optional name/value pairs passed to this method may override some of those values. Valid PARAMS are:

db [DB]

The Rose::DB-derived object used to connect to the database. This object will also be used as the prototype for the db object used by each Rose::DB::Object subclass created by this call to make_classes. Defaults to the value of the loader object's db attribute.

db_class [CLASS]

The name of the Rose::DB-derived class used to construct a db object if one has not been set via the parameter or object attribute of the same name. Defaults to the value of the loader object's db_class attribute.

include_tables REGEX

Table names that do not match REGEX will be skipped. Defaults to the value of the loader object's include_tables attribute.

exclude_tables REGEX

Table names that match REGEX will be skipped. Defaults to the value of the loader object's exclude_tables attribute.

filter_tables CODEREF

A reference to a subroutine that takes a single table name argument and returns true if the table should be processed, false if it should be skipped. The $_ variable will also be set to the table name before the call. This parameter cannot be combined with the exclude_tables or include_tables options.

Defaults to the value of the loader object's filter_tables attribute, provided that both the exclude_tables and include_tables values are undefined.

include_views BOOL

If true, database views will also be processed. Defaults to the value of the loader object's include_views attribute.

pre_init_hook [ CODEREF | ARRAYREF ]

A reference to a subroutine or a reference to an array of code references that will be called just before each Rose::DB::Object-derived class is initializeed. Each referenced subroutine will be passed the class's metdata object plus any arguments to the initialize method. Defaults to the value of the loader object's pre_init_hook attribute.

with_foreign_keys BOOL

If true, set up foreign key metadata for each Rose::DB::Object-derived. Defaults to the value of the loader object's with_foreign_keys attribute.

with_managers BOOL

If true, create Rose::DB::Object::Manager-derived manager classes for each Rose::DB::Object subclass. Defaults to the value of the loader object's with_managers attribute.

The manager class name is determined by passing the Rose::DB::Object-derived class name to the generate_manager_class_name method.

The Rose::DB::Object subclass's metadata object's make_manager_class method will be used to create the manager class. It will be passed the return value of the convention manager's auto_manager_base_name method as an argument.

with_relationships [ BOOL | ARRAYREF ]

A boolean value or a reference to an array of relationship type names. If set to a simple boolean value, then all types of relationships will be considered when making classes. If set to a list of relationship type names, then only relationships of those types will be considered. Defaults to the value of the loader object's with_relationships attribute.

with_unique_keys BOOL

If true, set up unique key metadata for each Rose::DB::Object-derived. Defaults to the value of the loader object's with_unique_keys attribute.

Any remaining name/value parameters will be passed on to the call to auto_initialize used to set up each class. For example, to ask the loader not to create any relationships, pass the with_relationships parameter with a false value.

    $loader->make_classes(with_relationships => 0);

This parameter will be passed on to the auto_initialize method, which, in turn, will pass the parameter on to its own call to the auto_init_relationships method. See the Rose::DB::Object::Metadata documentation for more information on these methods.

Each Rose::DB::Object subclass will be created according to the "best practices" described in the Rose::DB::Object::Tutorial. If a base class is not provided, one (with a dynamically generated name) will be created automatically. The same goes for the db object. If one is not set, then a new (again, dynamically named) subclass of Rose::DB, with its own private data source registry, will be created automatically.

This method returns a list (in list context) or a reference to an array (in scalar context) of the names of all the classes that were created. (This list will include manager class names as well, if any were created.)

make_modules [PARAMS]

Automatically create Rose::DB::Object and (optionally) Rose::DB::Object::Manager subclasses for some or all of the tables in a database, then create Perl module (*.pm) files for each class.

This method calls make_classes to make the actual classes, and therefore takes all of the same parameters, with one addition.

module_dir DIR

The path to the directory where the Perl module files will be created. For example, given a DIR of "/home/john/lib", the Perl module file for the class My::DB::Object would be located at "/home/john/lib/My/DB/Object.pm".

Defaults to the value of the loader object's module_dir attribute. If the module_dir attribute is also undefined, then the current working directory (as determined by a call to cwd()) is used instead.

module_dir [DIR]

Get or set the path to the directory where make_modules will create its Perl modules files. For example, given a DIR of "/home/john/lib", make_modules would create the file "/home/john/lib/My/DB/Object.pm" for the class My::DB::Object.

pre_init_hook [CODE]

Get or set a reference to a subroutine to be called just before each Rose::DB::Object-derived class is initializeed within the make_classes method. The subroutine will be passed the class's metdata object as an argument.

with_foreign_keys BOOL

If true, the make_classes method will set up foreign key metadata for each Rose::DB::Object-derived class it creates. Defaults to true.

with_managers [BOOL]

If true, the make_classes method will create Rose::DB::Object::Manager-derived manager classes for each Rose::DB::Object subclass by default. Defaults to true.

The manager class name is determined by passing the Rose::DB::Object-derived class name to the generate_manager_class_name method.

The Rose::DB::Object subclass's metadata object's make_manager_class method will be used to create the manager class. It will be passed the return value of the convention manager's auto_manager_base_name method as an argument.

with_relationships [ BOOL | ARRAYREF ]

A boolean value or a reference to an array of relationship type names. If set to a simple boolean value, then the make_classes method will consider all types of relationships when making classes. If set to a list of relationship type names, then only relationships of those types will be considered by make_classes. Defaults to true.

with_unique_keys BOOL

If true, the make_classes method will set up unique key metadata for each Rose::DB::Object-derived class it creates. Defaults to true.

AUTHOR

John C. Siracusa (siracusa@mindspring.com)

COPYRIGHT

Copyright (c) 2005 by John C. Siracusa. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.