File Coverage

blib/lib/DBIx/VersionedSubs.pm
Criterion Covered Total %
statement 87 111 78.3
branch 17 34 50.0
condition 3 7 42.8
subroutine 18 23 78.2
pod 14 14 100.0
total 139 189 73.5


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2             package DBIx::VersionedSubs;
3 15     15   93 use strict;
  15         29  
  15         478  
4 15     15   42953 use DBI;
  15         428377  
  15         1231  
5 15     15   17387 use POSIX qw(strftime);
  15         142013  
  15         118  
6 15     15   20923 use base 'Class::Data::Inheritable';
  15         36  
  15         20500  
7              
8             =head1 NAME
9              
10             DBIx::VersionedSubs - all your code are belong into the DB
11              
12             =head1 SYNOPSIS
13              
14             package My::App;
15             use strict;
16             use base 'DBIx::VersionedSubs';
17              
18             package main;
19             use strict;
20              
21             My::App->startup($dsn);
22             while (my $request = Some::Server->get_request) {
23             My::App->update_code; # update code from the DB
24             My::App->handle_request($request);
25             }
26              
27             And C might look like the following in the DB:
28              
29             sub handle_request {
30             my ($request) = @_;
31             my %args = split /[=;]/, $request;
32             my $method = delete $args{method};
33             no strict 'refs';
34             &{$method}( %args );
35             }
36              
37             See C for a sample HTTP implementation of a framework based
38             on this concept.
39              
40             =head1 ABSTRACT
41              
42             This module implements a minimal driver to load
43             your application code from a database into a namespace
44             and to update that code whenever the database changes.
45              
46             =head1 TABLES USED
47              
48             This module uses two tables in the database, C and C.
49             The C table stores the current version of the code and is used to
50             initialize the namespace. The C table stores all modifications
51             to the C table, that is, insertions, deletions and modifications
52             of rows in it. It is used to determine if the code has changed and what
53             changes to apply to the namespace to bring it up to par with the
54             database version.
55              
56             The two tables are presumed to have a layout like the following:
57              
58             create table code_live (
59             name varchar(256) not null primary key,
60             code varchar(65536) not null
61             );
62              
63             create table code_history (
64             version integer primary key not null,
65             timestamp varchar(15) not null,
66             name varchar(256) not null,
67             action varchar(1) not null, -- IUD, redundant with old_* and new_*
68             old_code varchar(65536) not null,
69             new_code varchar(65536) not null
70             );
71              
72             Additional columns are ignored by this code. It is likely prudent
73             to create an index on C as that will be used
74             for (descending) ordering of rows.
75              
76             =cut
77              
78             __PACKAGE__->mk_classdata($_)
79             for qw(dbh code_version code_live code_history code_source verbose);
80              
81 15     15   6638 use vars qw'%default_values $VERSION';
  15         33  
  15         5416  
82              
83             $VERSION = '0.07';
84              
85             %default_values = (
86             dbh => undef,
87             code_source => {},
88             code_live => 'code_live',
89             code_history => 'code_history',
90             code_version => 0,
91             verbose => 0,
92             );
93              
94             =head1 CLASS METHODS
95              
96             =head2 C<< Package->setup >>
97              
98             Sets up the class data defaults:
99              
100             code_source => {}
101             code_live => 'code_live',
102             code_history => 'code_history',
103             code_version => 0,
104             verbose => 0,
105              
106             C contains the Perl source code for all loaded functions.
107             C and C are the names of the two tables
108             in which the live code and the history of changes to the live code
109             are stored. C is the version of the code when it
110             was last loaded from the database.
111              
112             The C setting determines if progress gets output to
113             C.
114             Likely, this package variable will get dropped in favour of
115             a method to output (or discard) the progress.
116              
117             =cut
118              
119             sub setup {
120 15     15 1 289 my $package = shift;
121 15 50       179 warn "Setting up $package defaults"
122             if $package->verbose;
123 15         308 my %defaults = (%default_values,@_);
124 15         74 for my $def (keys %defaults) {
125 91 100       2514 if (! defined $package->$def) {
126 90         850 $package->$def($defaults{$def});
127             };
128             }
129 15         390 $package;
130             };
131              
132             =head2 C<< Package->connect DSN,User,Pass,Options >>
133              
134             Connects to the database with the credentials given.
135              
136             If called in void context, stores the DBI handle in the
137             C accessor, otherwise returns the DBI handle.
138              
139             If you already have an existing database handle, just
140             set the C accessor with it instead.
141              
142             =cut
143              
144             sub connect {
145 12     12 1 239 my ($package,$dsn,$user,$pass,$options) = @_;
146 12 50       61 if (defined wantarray) {
147 0 0       0 DBI->connect($dsn,$user,$pass,$options)
148             or die "Couldn't connect to $dsn/$user/$pass/$options";
149             } else {
150 12         127 $package->dbh(DBI->connect($dsn,$user,$pass,$options));
151             }
152             };
153              
154             =head2 C<< Package->create_sub NAME, CODE >>
155              
156             Creates a subroutine in the Package namespace.
157              
158             If you want a code block to be run automatically
159             when loaded from the database, you can name it C.
160             The loader code basically uses
161              
162             package $package;
163             *{"$package\::$name"} = eval "sub { $code }"
164              
165             so you cannot stuff attributes and other whatnot
166             into the name of your subroutine, not that you should.
167              
168             One name is special cased - C will be immediately
169             executed instead of installed. This is most likely what you expect.
170             As the code elements are loaded by C in alphabetical
171             order on the name, your C and C subroutines
172             will still be loaded before your C block runs.
173              
174             The C block will be called with the package name in C<@_>.
175              
176             Also, names like C or C are possible
177             but get stuffed below C<$package>. The practice doesn't get saner there.
178              
179             =cut
180              
181             sub create_sub {
182 18     18 1 45 my ($package,$name,$code) = @_;
183 18   33     112 my $package_name = ref $package || $package;
184              
185 18         109 my $ref = $package->eval_sub($package_name,$name,$code);
186 18 100       97 if ($ref) {
187 14 100       49 if ($name eq 'BEGIN') {
188 3         88 $ref->($package);
189             return undef
190 3         50 } else {
191 15     15   86 no strict 'refs';
  15         30  
  15         615  
192 15     15   95 no warnings 'redefine';
  15         28  
  15         17400  
193 11         104 *{"$package\::$name"} = $ref;
  11         82  
194 11         57 $package->code_source->{$name} = $code;
195             #warn "Set $package\::$name to " . $package->code_source->{$name};
196 11         172 return $ref
197             };
198             };
199             }
200              
201             =head2 C<< Package->eval_sub PACKAGE, NAME, CODE >>
202              
203             Helper method to take a piece of code and to return
204             a code reference with the correct file/line information.
205              
206             Raises a warning if code doesn't compile. Returns
207             the reference to the code or C if there was an error.
208              
209             =cut
210              
211             sub eval_sub {
212 20     20 1 49 my ($self,$package,$name,$code) = @_;
213 20         85 my $perl_code = <
214             package $package;
215             #line $package/$name#1
216             sub {$code}
217             CODE
218              
219 20     9   2052 my $ref = eval $perl_code;
  9     1   11492  
  1         8  
  1         3  
  1         45  
220 20 100       135 if (my $err = $@) {
221 4         32 warn $perl_code . "\n$package\::$name>> $err";
222             return undef
223 4         31 } else {
224 16         65 return $ref
225             };
226             };
227              
228             =head2 C<< Package->destroy_sub $name >>
229              
230             Destroy the subroutine named C<$name>. For the default
231             implementation, this replaces the subroutine with a
232             dummy subroutine that Cs.
233              
234             =cut
235              
236             sub destroy_sub {
237 0     0 1 0 my ($package,$name) = @_;
238 0         0 $package->create_sub($name,<
239             use Carp qw(croak);
240             croak "Undefined subroutine '$name' called"
241             ERROR_SUB
242 0         0 delete $package->code_source->{$name};
243             };
244              
245             =head2 C<< Package->live_code_version >>
246              
247             Returns the version number of the live code
248             in the database.
249              
250             This is done with a C< SELECT max(version) FROM ... > query,
251             so this might scale badly on MySQL which (I hear) is bad
252             with queries even against indexed tables. If this becomes
253             a problem, changing the layout to a single-row table which
254             stores the live version number is the best approach.
255              
256             =cut
257              
258             sub live_code_version {
259 17     17 1 1271 my ($package) = @_;
260 17         69 my $sth = $package->dbh->prepare_cached(sprintf <<'SQL', $package->code_history);
261             SELECT max(version) FROM %s
262             SQL
263 17         1617 $sth->execute();
264 17         182 my ($result) = $sth->fetchall_arrayref();
265 17 100       191 $result->[0]->[0] || 0
266             }
267              
268             =head2 C<< Package->init_code >>
269              
270             Adds / overwrites subroutines/methods in the Package namespace
271             from the database.
272              
273             =cut
274              
275             sub init_code {
276 9     9 1 105424 my ($package) = @_;
277 9         79 my $table = $package->code_live;
278             #warn "Loading code for $package from $table";
279 9         109 my $sql = sprintf <<'SQL', $table;
280             SELECT name,code FROM %s
281             ORDER BY name
282             SQL
283              
284 9         45 my $sth = $package->dbh->prepare_cached($sql);
285 9         6111 $sth->execute();
286 9         895 while (my ($name,$code) = $sth->fetchrow()) {
287 16         643 $package->create_sub($name,$code);
288             }
289              
290 9         86 $package->code_version($package->live_code_version);
291             };
292              
293             =head2 C<< Package->update_code >>
294              
295             Updates the namespace from the database by loading
296             all changes.
297              
298             Note that if you have/use closures or iterators,
299             these will behave weird if you redefine a subroutine
300             that was previously closed over.
301              
302             =cut
303              
304             sub update_code {
305 1     1 1 556 my ($package) = @_;
306 1   50     5 my $version = $package->code_version || 0;
307             #warn "Checking against $version";
308 1         16 my $sth = $package->dbh->prepare_cached(sprintf <<'SQL', $package->code_history);
309             SELECT distinct name,action,new_code,version FROM %s
310             WHERE version > ?
311             ORDER BY version DESC
312             SQL
313              
314 1         162 $sth->execute($version);
315              
316 1         2 my %seen;
317              
318 1   50     8 my $current_version = $version || 0;
319 1         18 while (my ($name,$action,$code,$new_version) = $sth->fetchrow()) {
320 1 50       4 next if $seen{$name}++;
321            
322 1 50       7 warn "Reloading $name"
323             if $package->verbose;
324 1 50       13 $current_version = $current_version < $new_version
325             ? $new_version
326             : $current_version;
327              
328 1 50       5 if ($action eq 'I') {
    50          
    0          
329 0         0 $package->create_sub($name,$code);
330             } elsif ($action eq 'U') {
331 1         5 $package->create_sub($name,$code);
332             } elsif ($action eq 'D') {
333 0         0 $package->destroy_sub($name);
334             };
335             }
336 1         5 $package->code_version($current_version);
337             };
338              
339             =head2 C<< Package->add_code_history Name,Old,New,Action >>
340              
341             Inserts a new row in the code history table.
342              
343             This
344             would be done with triggers on a real database,
345             but my development target includes MySQL 3 and 4.
346              
347             =cut
348              
349             sub add_code_history {
350 2     2 1 35 my ($package,$name,$old_code,$new_code,$action) = @_;
351 2         623 my $ts = strftime('%Y%m%d-%H%M%S',gmtime());
352 2         18 my $sth = $package->dbh->prepare_cached(sprintf <<'SQL',$package->code_history);
353             INSERT INTO %s (name,old_code,new_code,action,timestamp) VALUES (?,?,?,?,?)
354             SQL
355 2         366 $sth->execute($name,$old_code,$new_code,$action,$ts);
356             }
357              
358             =head2 C<< Package->update_sub name,code >>
359              
360             Updates the code for the subroutine C
361             with the code given.
362              
363             Note that the update only happens in the database, so the change
364             will only take place on the next roundtrip / code refresh.
365              
366             This cannot override subroutines that don't exist in the database.
367              
368             =cut
369              
370             sub update_sub {
371 2     2 1 8 my ($package,$name,$new_code) = @_;
372 2         11 $package->add_code_history($name,$package->code_source->{$name},$new_code,'U');
373 2         12 my $sth = $package->dbh->prepare_cached(sprintf <<'SQL',$package->code_live);
374             UPDATE %s SET code=?
375             WHERE name=?
376             SQL
377 2         288 $sth->execute($new_code,$name);
378             };
379              
380              
381             =head2 C<< Package->insert_sub name,code >>
382              
383             Inserts the code for the subroutine C.
384              
385             Note that the insert only happens in the database, so the change
386             will only take place on the next roundtrip / code refresh.
387              
388             This can also be used to override methods / subroutines that
389             are defined elsewhere in the Package:: namespace.
390              
391             =cut
392              
393             sub insert_sub {
394 0     0 1 0 my ($package,$name,$new_code) = @_;
395 0         0 $package->add_code_history($name,'',$new_code,'I');
396 0         0 my $sth = $package->dbh->prepare_cached(sprintf <<'SQL',$package->code_live);
397             INSERT INTO %s (name,code) VALUES (?,?)
398             SQL
399 0         0 $sth->execute($name,$new_code);
400             };
401              
402             =head2 C<< Package->redefine_sub name,code >>
403              
404             Inserts or updates the code for the subroutine C.
405              
406             Note that the change only happens in the database, so the change
407             will only take place on the next roundtrip / code refresh.
408              
409             This can be used to override methods / subroutines that
410             are defined in the database, elsewhere in the Package::
411             namespace or not at all.
412              
413             =cut
414              
415             sub redefine_sub {
416 0     0 1 0 my ($package,$name,$new_code) = @_;
417            
418 0 0       0 if (! eval { $package->update_sub($name,$new_code) }) {
  0         0  
419 0 0       0 warn "Inserting $name"
420             if $package->verbose;
421 0         0 $package->insert_sub($name,$new_code)
422             }
423             };
424              
425             =head2 C<< Package->delete_sub name,code >>
426              
427             Deletes the code for the subroutine C.
428              
429             Note that the update only happens in the database, so the change
430             will only take place on the next roundtrip / code refresh.
431              
432             If you delete the row of a subroutine that overrides a subroutine
433             declared elsewhere (for example in Perl code), the non-database Perl code
434             will not become
435             visible to the Perl interpreter until the next call to
436             C<< Package->init_code >>,
437             that is, likely until the next process restart. This will lead to very
438             weird behaviour, so don't do that.
439              
440             =cut
441              
442             sub delete_sub {
443 0     0 1 0 my ($package,$name,$new_code) = @_;
444 0         0 $package->add_code_history($name,$package->code_source->{$name},'','D');
445 0         0 my $sth = $package->dbh->prepare_cached(sprintf <<'SQL',$package->code_live);
446             -- here's a small race condition
447             -- - delete trumps insert/update
448             DELETE FROM %s WHERE name = ?
449             SQL
450 0         0 $sth->execute($name);
451             };
452              
453             =head2 C<< Package->startup(DBIargs) >>
454              
455             Shorthand method to initialize a package
456             from a database connection.
457              
458             If C<< Package->dbh >> already returns a true
459             value, no new connection is made.
460              
461             This method is equivalent to:
462              
463             if (! Package->dbh) {
464             Package->connect(@_);
465             };
466             Package->setup;
467             Package->init_code;
468              
469             =cut
470              
471             sub startup {
472 0     0 1 0 my $package = shift;
473 0 0       0 if (! $package->dbh) {
474 0         0 $package->connect(@_);
475             };
476 0         0 $package->setup;
477 0         0 $package->init_code;
478             }
479              
480             =head1 BEST PRACTICES
481              
482             The most bare-bones hosting package looks like the following (see also
483             C in the distribution):
484              
485             package My::App;
486             use strict;
487             use base 'DBIx::VersionedSubs';
488              
489             Global variables are best declared within the C block. You will find
490             typos or use of undeclared variables reported to C as the
491             subroutines get compiled.
492              
493             =head1 TODO
494              
495             =over 4
496              
497             =item * Implement closures (marked via a bare block)
498              
499             =item * Find a saner way instead of C<< ->setup >> and C<%default_values>
500             for configuring the initial class values while still preventing hashref
501             usage across packages. The "classic" approach of using Class::Data::Inheritable
502             means that there is the risk of sharing the C reference across
503             namespaces which is wrong. Maybe the accessor should simply be smart
504             and depend on the namespace it was called with instead of a stock accessor
505              
506             =item * Discuss whether it's sane
507             to store all your code with your data in the database.
508             It works well for L and the
509             Everything Engine.
510              
511             =back
512              
513             =head1 AUTHOR
514              
515             Max Maischein, Ecorion@cpan.orgE
516              
517             =head1 CREDITS
518              
519             Tye McQueen for suggesting the module name
520              
521             =head1 SEE ALSO
522              
523             The Everything Engine, L
524              
525             =head1 LICENSE
526              
527             This module is licensed under the same terms as Perl itself.
528              
529             =head1 ALTERNATIVE NAMES
530              
531             DBIx::Seven::Days, Nothing::Driver, Corion's::Code::From::Outer::Space
532              
533             =cut
534              
535             1;