Search code examples
perlormrose-db-object

Perl Rose::DB non-static datasource registration


I'm writing a perl application which uses Rose::DB for persistence abstraction, but I'm running into an issue with initializing my Rose::DB subclass with values from a configuration file.

The documentation always presents hardcoded examples, like:

# Register your lone data source using the default type and domain
__PACKAGE__->register_db(
  driver   => 'pg',
  database => 'my_db',
  host     => 'localhost',
  username => 'joeuser',
  password => 'mysecret',
);

However, for maintainability's sake, I'd like to fill in these values from a separate config file at runtime.

The config file (Config::General format) section being used:

<database> 
    active_domain       development

    <db_domain development>
        db_driver       mysql
        db_name         stats_dev
        db_host         localhost
        db_user         stats_dev
        db_password     stats_dev
    </db_domain>
    <db_domain production>
        db_driver       mysql
        db_name         stats_prd
        db_host         localhost
        db_user         stats_prd
        db_password     stats_prd
    </db_domain>
</database>

My Rose::DB subclass, with initializer method:

package Utils::DBUtils;

use strict;
use base qw(Rose::DB);

__PACKAGE__->use_private_registry;

sub registerAllDBs {
    my ($self,$config_obj) = @_;
    my $db_config = $config_obj->getDatabaseSection(); ## subconfig starts here
    my $def_domain = $db_config->{"active_domain"};

    __PACKAGE__->default_domain($def_domain);
    __PACKAGE__->default_type('main');

    my $db_domains = $db_config->{'db_domain'};
    foreach my $domain (keys %$db_domains) {
        my $domain_conf = $db_domains->{$domain};

        __PACKAGE__->register_db(
            domain => $domain,
            type => __PACKAGE__->default_type(),
            driver   => $domain_conf->{'db_driver'},
            database => $domain_conf->{'db_name'},
            host     => $domain_conf->{'db_host'},
            username => $domain_conf->{'db_user'},
            password => $domain_conf->{'db_password'}
        );          
    }
}
1;

Then on my main script I call the method once to register all the data sources:

    Utils::DBUtils->registerAllDBs($conf);

My persistent objects all inherit from the PersistentObject package, which initializes the DB object with:

    sub init_db { Utils::DBUtils->new() }

However, this doesn't work as I expected. I get a compile-time error stating:

    No database information found for domain 'default' and type 'default' and no driver type specified in call to Utils::DBUtils->new(...) at PersistentObject.pm line 9

The problem, it seems, is that Rose::DB expects to have the full configuration data at compile time, which would be not possible to provide since it comes from the config file.

Am I missing something here? Isn't it possible to dynamically initialize a Rose::DB object?


Solution

  • I have managed to get it to work, it seems that the Rose::DB subclass needs at least one register_db statement at compile time.

    The (ugly) solution was to add

    __PACKAGE__->register_db(
      driver   => 'mysql',
      database => 'fake',
      host     => 'localhost',
      username => 'fake',
      password => 'fake'
    );
    

    to the package definition.