Max Maischein > DBIx-VersionedSubs-0.07 > DBIx::VersionedSubs

Download:
DBIx-VersionedSubs-0.07.tar.gz

Dependencies

Annotate this POD

CPAN RT

New  1
Open  0
View/Report Bugs
Module Version: 0.07   Source  

NAME ^

DBIx::VersionedSubs - all your code are belong into the DB

SYNOPSIS ^

    package My::App;
    use strict;
    use base 'DBIx::VersionedSubs';

    package main;
    use strict;

    My::App->startup($dsn);
    while (my $request = Some::Server->get_request) {
        My::App->update_code; # update code from the DB
        My::App->handle_request($request);
    }

And handle_request might look like the following in the DB:

    sub handle_request {
        my ($request) = @_;
        my %args = split /[=;]/, $request;
        my $method = delete $args{method};
        no strict 'refs';
        &{$method}( %args );
    }

See eg/ for a sample HTTP implementation of a framework based on this concept.

ABSTRACT ^

This module implements a minimal driver to load your application code from a database into a namespace and to update that code whenever the database changes.

TABLES USED ^

This module uses two tables in the database, code_live and code_history. The code_live table stores the current version of the code and is used to initialize the namespace. The code_history table stores all modifications to the code_live table, that is, insertions, deletions and modifications of rows in it. It is used to determine if the code has changed and what changes to apply to the namespace to bring it up to par with the database version.

The two tables are presumed to have a layout like the following:

    create table code_live (
        name varchar(256) not null primary key,
        code varchar(65536) not null
    );

    create table code_history (
        version integer primary key not null,
        timestamp varchar(15) not null,
        name varchar(256) not null,
        action varchar(1) not null, -- IUD, redundant with old_* and new_*
        old_code varchar(65536) not null,
        new_code varchar(65536) not null
    );

Additional columns are ignored by this code. It is likely prudent to create an index on code_history.version as that will be used for (descending) ordering of rows.

CLASS METHODS ^

Package->setup

Sets up the class data defaults:

    code_source  => {}
    code_live    => 'code_live',
    code_history => 'code_history',
    code_version => 0,
    verbose      => 0,

code_source contains the Perl source code for all loaded functions. code_live and code_history are the names of the two tables in which the live code and the history of changes to the live code are stored. code_version is the version of the code when it was last loaded from the database.

The verbose setting determines if progress gets output to STDERR. Likely, this package variable will get dropped in favour of a method to output (or discard) the progress.

Package->connect DSN,User,Pass,Options

Connects to the database with the credentials given.

If called in void context, stores the DBI handle in the dbh accessor, otherwise returns the DBI handle.

If you already have an existing database handle, just set the dbh accessor with it instead.

Package->create_sub NAME, CODE

Creates a subroutine in the Package namespace.

If you want a code block to be run automatically when loaded from the database, you can name it BEGIN. The loader code basically uses

    package $package;
    *{"$package\::$name"} = eval "sub { $code }"

so you cannot stuff attributes and other whatnot into the name of your subroutine, not that you should.

One name is special cased - BEGIN will be immediately executed instead of installed. This is most likely what you expect. As the code elements are loaded by init_code in alphabetical order on the name, your Aardvark and AUTOLOAD subroutines will still be loaded before your BEGIN block runs.

The BEGIN block will be called with the package name in @_.

Also, names like main::foo or Other::Package::foo are possible but get stuffed below $package. The practice doesn't get saner there.

Package->eval_sub PACKAGE, NAME, CODE

Helper method to take a piece of code and to return a code reference with the correct file/line information.

Raises a warning if code doesn't compile. Returns the reference to the code or undef if there was an error.

Package->destroy_sub $name

Destroy the subroutine named $name. For the default implementation, this replaces the subroutine with a dummy subroutine that croaks.

Package->live_code_version

Returns the version number of the live code in the database.

This is done with a SELECT max(version) FROM ... query, so this might scale badly on MySQL which (I hear) is bad with queries even against indexed tables. If this becomes a problem, changing the layout to a single-row table which stores the live version number is the best approach.

Package->init_code

Adds / overwrites subroutines/methods in the Package namespace from the database.

Package->update_code

Updates the namespace from the database by loading all changes.

Note that if you have/use closures or iterators, these will behave weird if you redefine a subroutine that was previously closed over.

Package->add_code_history Name,Old,New,Action

Inserts a new row in the code history table.

This would be done with triggers on a real database, but my development target includes MySQL 3 and 4.

Package->update_sub name,code

Updates the code for the subroutine Package::$name with the code given.

Note that the update only happens in the database, so the change will only take place on the next roundtrip / code refresh.

This cannot override subroutines that don't exist in the database.

Package->insert_sub name,code

Inserts the code for the subroutine Package::$name.

Note that the insert only happens in the database, so the change will only take place on the next roundtrip / code refresh.

This can also be used to override methods / subroutines that are defined elsewhere in the Package:: namespace.

Package->redefine_sub name,code

Inserts or updates the code for the subroutine Package::$name.

Note that the change only happens in the database, so the change will only take place on the next roundtrip / code refresh.

This can be used to override methods / subroutines that are defined in the database, elsewhere in the Package:: namespace or not at all.

Package->delete_sub name,code

Deletes the code for the subroutine Package::$name.

Note that the update only happens in the database, so the change will only take place on the next roundtrip / code refresh.

If you delete the row of a subroutine that overrides a subroutine declared elsewhere (for example in Perl code), the non-database Perl code will not become visible to the Perl interpreter until the next call to Package->init_code, that is, likely until the next process restart. This will lead to very weird behaviour, so don't do that.

Package->startup(DBIargs)

Shorthand method to initialize a package from a database connection.

If Package->dbh already returns a true value, no new connection is made.

This method is equivalent to:

    if (! Package->dbh) {
        Package->connect(@_);
    };
    Package->setup;
    Package->init_code;

BEST PRACTICES ^

The most bare-bones hosting package looks like the following (see also eg/lib/My/App.pm in the distribution):

    package My::App;
    use strict;
    use base 'DBIx::VersionedSubs';

Global variables are best declared within the BEGIN block. You will find typos or use of undeclared variables reported to STDERR as the subroutines get compiled.

TODO ^

AUTHOR ^

Max Maischein, <corion@cpan.org>

CREDITS ^

Tye McQueen for suggesting the module name

SEE ALSO ^

The Everything Engine, http://everydevel.com/

LICENSE ^

This module is licensed under the same terms as Perl itself.

ALTERNATIVE NAMES ^

DBIx::Seven::Days, Nothing::Driver, Corion's::Code::From::Outer::Space

syntax highlighting: