[Jifty-commit] r2888 - in Jifty-DBI/trunk: lib/Jifty lib/Jifty/DBI
lib/Jifty/DBI/Class lib/Jifty/DBI/Record t
jifty-commit at lists.jifty.org
jifty-commit at lists.jifty.org
Sat Mar 3 11:41:09 EST 2007
Author: jesse
Date: Sat Mar 3 11:41:08 2007
New Revision: 2888
Added:
Jifty-DBI/trunk/lib/Jifty/DBI/Class/
Jifty-DBI/trunk/lib/Jifty/DBI/Class/Trigger.pm
Jifty-DBI/trunk/lib/Jifty/DBI/Record/Plugin.pm
Jifty-DBI/trunk/t/15types.t
Jifty-DBI/trunk/t/16inheritance.t
Modified:
Jifty-DBI/trunk/ (props changed)
Jifty-DBI/trunk/Changes
Jifty-DBI/trunk/MANIFEST
Jifty-DBI/trunk/META.yml
Jifty-DBI/trunk/Makefile.PL
Jifty-DBI/trunk/SIGNATURE
Jifty-DBI/trunk/lib/Jifty/DBI.pm
Jifty-DBI/trunk/lib/Jifty/DBI/Collection.pm
Jifty-DBI/trunk/lib/Jifty/DBI/Column.pm
Jifty-DBI/trunk/lib/Jifty/DBI/Record.pm
Jifty-DBI/trunk/lib/Jifty/DBI/Schema.pm
Jifty-DBI/trunk/t/01records.t
Jifty-DBI/trunk/t/02records_object.t
Jifty-DBI/trunk/t/11schema_records.t
Jifty-DBI/trunk/t/12prefetch.t
Jifty-DBI/trunk/t/testmodels.pl
Log:
* Merge down from the Object::Declare branch
r47396 at pinglin (orig r2567): clkao | 2007-01-26 07:43:23 +0000
branch for OD-ify jifty::dbi.
r47399 at pinglin (orig r2570): audreyt | 2007-01-26 11:27:28 +0000
* Completely finish porting Jifty::DBI::Schema to use Object::Declare.
Visible differences are:
- "refers App::Class" is now an alias for "refers_to App::Class".
- In refers/refers_to it is no longer neccessary to load App::Class
beforehand; therefore circular references can now be expressed.
- "length is 30" is now invalid; a compile-time exception will be
raised that tells the user to use "maxlength id 40" instead.
r47424 at pinglin (orig r2595): audreyt | 2007-01-26 13:32:46 +0000
* This be 0.39_999.
- Improved error message for "length is 42":
Due to an incompatible API change, the "length" field in
Jifty::DBI columns has been renamed to "max_length":
column foo =>
length is 10; # NOT VALID
Please write this instead:
column foo =>
max_length is 10 # VALID
- Calling 'column' within a schema class is an error:
package TestApp::Address::Schema;
column address => ...; # NOT VALID
Please write this instead:
package TestApp::Address;
use Jifty::DBI::Schema;
use Jifty::DBI::Record schema {
column address => ...; # VALID
};
r47425 at pinglin (orig r2596): audreyt | 2007-01-26 13:36:12 +0000
* Remove wrong use of SimpleTrace
r47426 at pinglin (orig r2597): audreyt | 2007-01-26 13:42:47 +0000
* Fix warning in die sighandler
r47427 at pinglin (orig r2598): audreyt | 2007-01-26 13:44:36 +0000
* try again...
r47428 at pinglin (orig r2599): audreyt | 2007-01-26 13:52:53 +0000
* Another try at warning avoidance.
r47430 at pinglin (orig r2601): audreyt | 2007-01-26 14:11:44 +0000
* render_as
r47443 at pinglin (orig r2614): clkao | 2007-01-27 00:35:04 +0000
First draft of bundled type support.
r47447 at pinglin (orig r2618): jesse | 2007-01-27 02:44:52 +0000
* Add back support for 'since' and 'until'
r47448 at pinglin (orig r2619): audreyt | 2007-01-27 03:06:13 +0000
* Jifty::DBI::Schema - Proper support for since/until
r47451 at pinglin (orig r2622): audreyt | 2007-01-27 03:32:29 +0000
* Remove the "until '123'" support that was never working anyway. It's now
spelled as "till '123'".
r47455 at pinglin (orig r2626): audreyt | 2007-01-27 04:09:12 +0000
* Jifty::DBI::Column - Remove ->until in OD branch
r47460 at pinglin (orig r2631): audreyt | 2007-01-27 04:41:14 +0000
* Fix "refers_to" bug when cloning virtual columns with column name matching /_id$/.
r47461 at pinglin (orig r2632): audreyt | 2007-01-27 04:41:32 +0000
* Fix mismerge.
r47465 at pinglin (orig r2636): audreyt | 2007-01-27 05:11:26 +0000
* Jifty::DBI::Schema - refers_to handling assumes UNIVERSAL::require(),
so while it should be largely okay to rely on it being supplied by an
earlier use of ::Record, still it's better to use() it first.
r47468 at pinglin (orig r2639): clkao | 2007-01-27 05:39:08 +0000
tests for inherited models.
r47495 at pinglin (orig r2666): audreyt | 2007-01-27 13:07:41 +0000
* Jifty::DBI::Schema - Rescind "refers Foo::Bar" support as it's not English.
r47496 at pinglin (orig r2667): audreyt | 2007-01-27 13:17:04 +0000
* Add new synonym "references" for "refers_to" as it has no underscores.
r48581 at pinglin (orig r2853): jesse | 2007-02-27 20:35:24 +0000
r48579 at 123: jesse | 2007-02-27 15:31:36 -0500
* Fix 'literal' support in the Object::Declare branch of Jifty
r48587 at pinglin (orig r2858): jesse | 2007-02-28 02:58:04 +0000
r48582 at pinglin: jesse | 2007-02-27 21:57:40 -0500
* Initial stab at a mixin-based Jifty::DBI::Record plugin system.
r48590 at pinglin (orig r2860): jesse | 2007-02-28 03:28:56 +0000
r48588 at pinglin: jesse | 2007-02-27 22:28:37 -0500
* Blow the methods into the _right_ class
r48619 at pinglin (orig r2872): jesse | 2007-02-28 20:18:49 +0000
r48599 at pinglin: jesse | 2007-02-28 14:24:49 -0500
* plugins can now export subs
r50704 at pinglin (orig r2880): jesse | 2007-03-02 00:45:20 +0000
r50701 at pinglin: jesse | 2007-03-01 19:44:22 -0500
* Initial refactoring to introduce callbacks for plugins
r52914 at pinglin (orig r2883): falcone | 2007-03-03 05:19:37 +0000
r17051 at ketch: falcone | 2007-03-03 00:18:35 -0500
* add missing Class::Trigger dependancy
r52915 at pinglin (orig r2884): falcone | 2007-03-03 05:20:08 +0000
r17052 at ketch: falcone | 2007-03-03 00:18:49 -0500
* fix table name so test pass on PG
r52948 at pinglin (orig r2886): jesse | 2007-03-03 16:29:38 +0000
r52891 at pinglin: jesse | 2007-03-02 18:51:05 +0000
* extracting methods for calling validation and Class::Trigger support
r52950 at pinglin (orig r2887): jesse | 2007-03-03 16:38:15 +0000
r52944 at pinglin: jesse | 2007-03-03 12:26:36 +0000
* Added intial support for plugins to register triggers
r52945 at pinglin: jesse | 2007-03-03 12:29:38 +0000
* can not call a method name as the method. "oops"
r52947 at pinglin: jesse | 2007-03-03 16:21:49 +0000
* canonicalizers work
Modified: Jifty-DBI/trunk/Changes
==============================================================================
--- Jifty-DBI/trunk/Changes (original)
+++ Jifty-DBI/trunk/Changes Sat Mar 3 11:41:08 2007
@@ -1,5 +1,44 @@
Revision history for Perl extension Jifty::DBI.
+0.39_9999 Fri Jan 26 21:30:48 CST 2007
+
+- Removed unneccessary use of Devel::SimpleTrace.
+
+0.39_999 Fri Jan 26 21:30:48 CST 2007
+
+- Improved error message for "length is 42":
+
+ Due to an incompatible API change, the "length" field in
+ Jifty::DBI columns has been renamed to "max_length":
+
+ column foo =>
+ length is 10; # NOT VALID
+
+ Please write this instead:
+
+ column foo =>
+ max_length is 10 # VALID
+
+- Calling 'column' within a schema class is an error:
+
+ package TestApp::Address::Schema;
+ column address => ...; # NOT VALID
+
+ Please write this instead:
+
+ package TestApp::Address;
+ use Jifty::DBI::Schema;
+ use Jifty::DBI::Record schema {
+ column address => ...; # VALID
+ };
+
+
+0.39_99 Fri Jan 26 19:57:48 CST 2007
+
+- INCOMPATIBLE API CHANGE: "length is 42" must be written as "max_length is 42" instead.
+- Switch to Object::Declare for schema declaration, fixing many annoyances such as the inability for two modules to refer to each other in their columns.
+- "refers Foo::Bar", a new alias to "refers_to Foo::Bar".
+
0.34 Sun Jan 28 21:28:00 CST 2007
- Added a method to the schema generator to output the SQL for a single column
Modified: Jifty-DBI/trunk/MANIFEST
==============================================================================
--- Jifty-DBI/trunk/MANIFEST (original)
+++ Jifty-DBI/trunk/MANIFEST Sat Mar 3 11:41:08 2007
@@ -74,6 +74,8 @@
t/12prefetch.t
t/13collection.t
t/14handle-pg.t
+t/15types.t
+t/16inheritance.t
t/pod.t
t/testmodels.pl
t/utils.pl
Modified: Jifty-DBI/trunk/META.yml
==============================================================================
--- Jifty-DBI/trunk/META.yml (original)
+++ Jifty-DBI/trunk/META.yml Sat Mar 3 11:41:08 2007
@@ -29,6 +29,7 @@
Encode: 2.1
Exporter::Lite: 0
Lingua::EN::Inflect: 0
+ Object::Declare: 0.22
UNIVERSAL::require: 0
perl: 5.8.3
-version: 0.32
+version: 0.39_9999
Modified: Jifty-DBI/trunk/Makefile.PL
==============================================================================
--- Jifty-DBI/trunk/Makefile.PL (original)
+++ Jifty-DBI/trunk/Makefile.PL Sat Mar 3 11:41:08 2007
@@ -17,8 +17,10 @@
requires('Encode' => 2.10);
requires('Exporter::Lite');
requires('Lingua::EN::Inflect');
+requires('Object::Declare' => 0.22);
requires('UNIVERSAL::require');
requires('version');
+#requires('Class::Trigger');
build_requires('Test::More' => 0.52);
build_requires('DBD::SQLite');
no_index directory => 'ex';
Modified: Jifty-DBI/trunk/SIGNATURE
==============================================================================
--- Jifty-DBI/trunk/SIGNATURE (original)
+++ Jifty-DBI/trunk/SIGNATURE Sat Mar 3 11:41:08 2007
@@ -14,10 +14,10 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
-SHA1 691871afc059ed0de2321403a2caffa4e51edafd Changes
+SHA1 6cdd320e5387932cd7b6305d5b5068ac31cef0cb Changes
SHA1 3bf592c9da2a5718e9be45c822f200bea821746b MANIFEST
-SHA1 9552c4f2bb3380b27b092c527a7bce6dc22288e8 META.yml
-SHA1 38715641f85f55e5597415ab4d53e6c28ef8193f Makefile.PL
+SHA1 59ce3857a0aa37277227ea09964d213bbb3bfd29 META.yml
+SHA1 45d5f1856267d73c7a4a21f8f584b15cfd1bae9b Makefile.PL
SHA1 d0943ab047f543c92405564ab77ba008052544e6 README
SHA1 82d6ac3f6def48558d09f8b6e3b53ed4194d8c81 ROADMAP
SHA1 9d304f35438f847863969f6a069598379f5a9db2 debian/README
@@ -29,22 +29,22 @@
SHA1 584c0f6cdebcbf760dfca8413c94783586120214 ex/Example/Model/Address.pm
SHA1 7cea1a5289f79c2a87837924a83feb583f6e8890 ex/Example/Model/Employee.pm
SHA1 a9d62e4f5b43b2f78066172a4771238ee7df6339 ex/create_tables.pl
-SHA1 0bb5ddbe64424d40536acdee2f09e853ab39087d inc/Module/AutoInstall.pm
-SHA1 e7688055bf405375921ea837273d8bdc68803efb inc/Module/Install.pm
-SHA1 4fad9a959426996f62d0e4e972cf09e3a0cf8c0c inc/Module/Install/AutoInstall.pm
-SHA1 e5b3215acb96829f2142dcfce736c1b6484fbc08 inc/Module/Install/Base.pm
-SHA1 07c44e137098675ea35a5d537df1e4af098382d9 inc/Module/Install/Can.pm
-SHA1 8f691f8e451ba687551fa836e8d75c4d514241e5 inc/Module/Install/Fetch.pm
-SHA1 0db6efc5925b96e1ea3b8bc46c3ecdb14660ae82 inc/Module/Install/Include.pm
-SHA1 81b798c6ca71d1b665a470fb49d32105084ac389 inc/Module/Install/Makefile.pm
-SHA1 c8c9737da19baa15ffa7d9d5037913f64b592189 inc/Module/Install/Metadata.pm
-SHA1 b97304e2a5c405d950eeaa4afd09c6b5507571c3 inc/Module/Install/Win32.pm
-SHA1 73a588d58f7ad0a6a9ed0ea80c48fa12f234a02c inc/Module/Install/WriteAll.pm
-SHA1 69d5c825abea1a2b8f7f3e60d0eb1b75fcdd8a9f lib/Jifty/DBI.pm
-SHA1 8c257d0dfcd1f5e033a96cc51413150a72456b91 lib/Jifty/DBI/Collection.pm
+SHA1 603bb9de29fb8cba7f13409c546750972eff645d inc/Module/AutoInstall.pm
+SHA1 9b2f9d83bcf77860f53a0c07c90a4a59ad9f5df1 inc/Module/Install.pm
+SHA1 ad955f51ad2c40d4ba35395c27f5ed899a80bf7a inc/Module/Install/AutoInstall.pm
+SHA1 abe32855d75ab13747cf65765af9947b7a8c3057 inc/Module/Install/Base.pm
+SHA1 95b81d1e91bd634467bf633571eff4420e9c04eb inc/Module/Install/Can.pm
+SHA1 1fe98c63cf9d7271c8cb4183ba230f152df69e26 inc/Module/Install/Fetch.pm
+SHA1 0606a8b02a420600bc3e2b65ab82f70266784926 inc/Module/Install/Include.pm
+SHA1 aa4a3d87cedc972e3dc0d5d156809624e6db9416 inc/Module/Install/Makefile.pm
+SHA1 f1d4e1bbcb40bb269f36e6dc011b3ca25d3829b7 inc/Module/Install/Metadata.pm
+SHA1 0c2118868ef82ac517eb6d9c3bd93e6eb9bbf83e inc/Module/Install/Win32.pm
+SHA1 e827d6d43771032fa3df35c0ad5e5698d0e54cda inc/Module/Install/WriteAll.pm
+SHA1 83f0a75d698ab7ab174f42bb19e346b23fb4ba5e lib/Jifty/DBI.pm
+SHA1 b9ad69976fe3438c0528057fe972bb5741824af6 lib/Jifty/DBI/Collection.pm
SHA1 ecfae7430da875a856113e0c233daa0e31073000 lib/Jifty/DBI/Collection/Union.pm
SHA1 07115934091da72e0025c9c754714fc0ceedbef5 lib/Jifty/DBI/Collection/Unique.pm
-SHA1 1d4155a6de62daf7b1f962383ba46ee0ca80d472 lib/Jifty/DBI/Column.pm
+SHA1 ef9a50bac5f2dfa90936c5d155d1be82b7f4dced lib/Jifty/DBI/Column.pm
SHA1 a2c16702f3467a220e9ba96ac5e086cc2e7779d1 lib/Jifty/DBI/Filter.pm
SHA1 87192bf64a224cbea78770f4209ecae9981f3f5c lib/Jifty/DBI/Filter/Date.pm
SHA1 e7d1ddfa3a55f69680d8637071b53d516ad0fc7d lib/Jifty/DBI/Filter/DateTime.pm
@@ -65,15 +65,15 @@
SHA1 e6041a34c3044ed8b9691a5629ecf146fed95257 lib/Jifty/DBI/Handle/mysql.pm
SHA1 f2cc4fcce79c9a88a023d4e6bd96c2089eef1ced lib/Jifty/DBI/Handle/mysqlPP.pm
SHA1 0e975f9ec5480ca09025c592c06d484058e637df lib/Jifty/DBI/HasFilters.pm
-SHA1 9d7334483b81d1d1141dea136f80be1b873d4fbe lib/Jifty/DBI/Record.pm
+SHA1 da3d76a58bdb72d26fff9717b4e29a3e058d4641 lib/Jifty/DBI/Record.pm
SHA1 eb7085a11cc38f6a1e4b0256b43e590730666b29 lib/Jifty/DBI/Record/Cachable.pm
SHA1 91bf502236779f5e3aa04f6c7cabdcffc413ab81 lib/Jifty/DBI/Record/Memcached.pm
-SHA1 16f7dd62bb43ba4a04474bc925ef029a55b69c63 lib/Jifty/DBI/Schema.pm
-SHA1 48e330236bad9a33e1b054570584b8deaa43e4c1 lib/Jifty/DBI/SchemaGenerator.pm
+SHA1 6bdf9f32e1555c08d47e06782428b151b37b28ad lib/Jifty/DBI/Schema.pm
+SHA1 3a967c8385ad5e8ecb76b0c6374cfa2a092dffe3 lib/Jifty/DBI/SchemaGenerator.pm
SHA1 32834b7c4cf5a8d131382fccc8db341be8768291 t/00.load.t
SHA1 9aa7fed2b2409faa4c71d2a45db210721f47403e t/01-version_checks.t
SHA1 13c9fe3eeec0d000a7c86ea2474e30186cbc37e2 t/01basics.t
-SHA1 a9e9d590df1042ed21f8ab18fe720f1ef3d4f9cd t/01records.t
+SHA1 5acefb1e751c4a21e38ceb9fa37063c07d2d37dc t/01records.t
SHA1 b1d9bb663d106e6874c0c454d64819e6b67d56d2 t/01searches.t
SHA1 933ebc7f0cfcaf03a2092a7c8271f98b2385f785 t/02-column_constraints.t
SHA1 70fbf72948bdd7cabcfcf128d8f51365abb33e9c t/02records_cachable.t
@@ -85,8 +85,8 @@
SHA1 f0f6ce9d48f419de6ac6154684f9065f32e30ddd t/06filter_truncate.t
SHA1 2e9777a47e3a920d063bfbf9d56375c67c5b89c5 t/06filter_utf8.t
SHA1 824e48c66d2e18120b377934177745680785525b t/10schema.t
-SHA1 44291153e6f73ecd6d3f465c06bd0477943ae025 t/11schema_records.t
-SHA1 c071b919b08fd107eb86eecc511f61d7c9cbb61a t/12prefetch.t
+SHA1 423461800861653032758627a82465426968da8e t/11schema_records.t
+SHA1 7356c3470a6b493e061df45bd75dd23bf574dd5a t/12prefetch.t
SHA1 a93e0ee622b2291f797887f663f33c30fc7339f6 t/13collection.t
SHA1 f057b643275b0370ae18d47b3a1b394791c850d6 t/14handle-pg.t
SHA1 e9c6a5881fc60173fbc8d479c1afd2ce3b43bef1 t/pod.t
@@ -95,7 +95,7 @@
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.3 (GNU/Linux)
-iD8DBQFFvKUPEi9d9xCOQEYRAh+VAJ9k3HuIBC1f5B1RCEpeoHqXvnOZLwCbB4d+
-3y5B6i/kNM+jYHX5KbU6TlU=
-=xCos
+iD8DBQFFugMLtLPdNzw1AaARAke3AKCaJeRcBcCuOf5DEFLK+q9JgVaa7gCdFeH5
+zofu7nWSY/r9+A4aXHcIhfQ=
+=3gHU
-----END PGP SIGNATURE-----
Modified: Jifty-DBI/trunk/lib/Jifty/DBI.pm
==============================================================================
--- Jifty-DBI/trunk/lib/Jifty/DBI.pm (original)
+++ Jifty-DBI/trunk/lib/Jifty/DBI.pm Sat Mar 3 11:41:08 2007
@@ -2,7 +2,7 @@
use warnings;
use strict;
-$Jifty::DBI::VERSION = '0.34';
+$Jifty::DBI::VERSION = '0.39_9999';
=head1 NAME
Added: Jifty-DBI/trunk/lib/Jifty/DBI/Class/Trigger.pm
==============================================================================
--- (empty file)
+++ Jifty-DBI/trunk/lib/Jifty/DBI/Class/Trigger.pm Sat Mar 3 11:41:08 2007
@@ -0,0 +1,365 @@
+package Jifty::DBI::Class::Trigger;
+
+use strict;
+use vars qw($VERSION);
+$VERSION = "0.11_01";
+
+use Carp ();
+
+my (%Triggers, %TriggerPoints);
+
+sub import {
+ my $class = shift;
+ my $pkg = caller(0);
+
+ $TriggerPoints{$pkg} = { map { $_ => 1 } @_ } if @_;
+
+ # export mixin methods
+ no strict 'refs';
+ my @methods = qw(add_trigger call_trigger last_trigger_results);
+ *{"$pkg\::$_"} = \&{$_} for @methods;
+}
+
+sub add_trigger {
+ my $proto = shift;
+
+ my $triggers = __fetch_triggers($proto);
+
+ if (ref($_[1]) eq 'CODE') {
+
+ while (my($when, $code) = splice @_, 0, 2) {
+ __validate_triggerpoint($proto, $when);
+ Carp::croak('add_trigger() needs coderef') unless ref($code) eq 'CODE';
+ push @{$triggers->{$when}}, [$code, undef];
+ }
+ }
+ elsif (grep {'name'} @_) {
+ my %args = ( name => undef, callback => undef, abortable => undef, @_);
+ my $when= $args{'name'};
+ my $code = $args{'callback'};
+ my $abortable = $args{'abortable'};
+ __validate_triggerpoint($proto, $when);
+ Carp::croak('add_trigger() needs coderef') unless ref($code) eq 'CODE';
+ push @{$triggers->{$when}}, [$code, $abortable];
+
+
+ } else {
+ Carp::croak('add_trigger() needs coderef');
+
+ }
+ 1;
+}
+
+
+sub last_trigger_results {
+ my $self = shift;
+ my $result_store = ref($self) ? $self : ${Jifty::DBI::Class::Trigger::_trigger_results}->{$self};
+ return $result_store->{'_class_trigger_results'};
+}
+
+sub call_trigger {
+ my $self = shift;
+ my $when = shift;
+
+ my @return;
+
+ my $result_store = ref($self) ? $self : ${Jifty::DBI::Class::Trigger::_trigger_results}->{$self};
+
+ $result_store->{'_class_trigger_results'} = [];
+
+ if (my @triggers = __fetch_all_triggers($self, $when)) { # any triggers?
+ for (@triggers) {
+ my @return = $_->[0]->($self, @_);
+ push @{$result_store->{'_class_trigger_results'}}, \@return;
+ return undef if ($_->[1] and not $return[0]); # only abort on false values.
+
+ }
+ }
+ else {
+ # if validation is enabled we can only add valid trigger points
+ # so we only need to check in call_trigger() if there's no
+ # trigger with the requested name.
+ __validate_triggerpoint($self, $when);
+ }
+
+ return scalar @{$result_store->{'_class_trigger_results'}};
+}
+
+sub __fetch_all_triggers {
+ my ($obj, $when, $list, $order) = @_;
+ my $class = ref $obj || $obj;
+ my $return;
+ unless ($list) {
+ # Absence of the $list parameter conditions the creation of
+ # the unrolled list of triggers. These keep track of the unique
+ # set of triggers being collected for each class and the order
+ # in which to return them (based on hierarchy; base class
+ # triggers are returned ahead of descendant class triggers).
+ $list = {};
+ $order = [];
+ $return = 1;
+ }
+ no strict 'refs';
+ my @classes = @{$class . '::ISA'};
+ push @classes, $class;
+ foreach my $c (@classes) {
+ next if $list->{$c};
+ if (UNIVERSAL::can($c, 'call_trigger')) {
+ $list->{$c} = [];
+ __fetch_all_triggers($c, $when, $list, $order)
+ unless $c eq $class;
+ if (defined $when && $Triggers{$c}{$when}) {
+ push @$order, $c;
+ $list->{$c} = $Triggers{$c}{$when};
+ }
+ }
+ }
+ if ($return) {
+ my @triggers;
+ foreach my $class (@$order) {
+ push @triggers, @{ $list->{$class} };
+ }
+ if (ref $obj && defined $when) {
+ my $obj_triggers = $obj->{__triggers}{$when};
+ push @triggers, @$obj_triggers if $obj_triggers;
+ }
+ return @triggers;
+ }
+}
+
+sub __validate_triggerpoint {
+ return unless my $points = $TriggerPoints{ref $_[0] || $_[0]};
+ my ($self, $when) = @_;
+ Carp::croak("$when is not valid triggerpoint for ".(ref($self) ? ref($self) : $self))
+ unless $points->{$when};
+}
+
+sub __fetch_triggers {
+ my ($obj, $proto) = @_;
+ # check object based triggers first
+ return ref $obj ? $obj->{__triggers} ||= {} : $Triggers{$obj} ||= {};
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Jifty::DBI::Class::Trigger - Mixin to add / call inheritable triggers
+
+=head1 WARNING
+
+This Module is a TEMPORARY FORK of Class::Trigger. It will be replaced
+upon the release of new features in Class::Trigger that we depend on.
+
+ALL BUGS IN THIS MODULE ARE THE FAULT OF Jifty's DEVELOPERS AND NOT
+Class::Trigger's DEVELOPERS. UNDER NO CIRCUMSTANCES SHOULD BUGS
+BE REPORTED TO CLASS::TRIGGER'S DEVELOPERS.
+
+=head1 SYNOPSIS
+
+ package Foo;
+ use Jifty::DBI::Class::Trigger;
+
+ sub foo {
+ my $self = shift;
+ $self->call_trigger('before_foo');
+ # some code ...
+ $self->call_trigger('middle_of_foo');
+ # some code ...
+ $self->call_trigger('after_foo');
+ }
+
+ package main;
+ Foo->add_trigger(before_foo => \&sub1);
+ Foo->add_trigger(after_foo => \&sub2);
+
+ my $foo = Foo->new;
+ $foo->foo; # then sub1, sub2 called
+
+ # triggers are inheritable
+ package Bar;
+ use base qw(Foo);
+
+ Bar->add_trigger(before_foo => \&sub);
+
+ # triggers can be object based
+ $foo->add_trigger(after_foo => \&sub3);
+ $foo->foo; # sub3 would appply only to this object
+
+=head1 DESCRIPTION
+
+Jifty::DBI::Class::Trigger is a mixin class to add / call triggers (or hooks)
+that get called at some points you specify.
+
+=head1 METHODS
+
+By using this module, your class is capable of following methods.
+
+=over 4
+
+=item add_trigger
+
+ Foo->add_trigger($triggerpoint => $sub);
+ $foo->add_trigger($triggerpoint => $sub);
+
+
+ Foo->add_trigger( name => $triggerpoint,
+ callback => sub {return undef},
+ abortable => 1);
+
+ # no further triggers will be called. Undef will be returned.
+
+
+Adds triggers for trigger point. You can have any number of triggers
+for each point. Each coderef will be passed a reference to the calling object,
+as well as arguments passed in via L<call_trigger>. Return values will be
+captured in I<list context>.
+
+If add_trigger is called with named parameters and the C<abortable>
+parameter is passed a true value, a false return value from trigger
+code will stop processing of this trigger point and return a C<false>
+value to the calling code.
+
+If C<add_trigger> is called without the C<abortable> flag, return
+values will be captured by call_trigger, but failures will be ignored.
+
+If C<add_trigger> is called as object method, whole current trigger
+table will be copied onto the object and the new trigger added to
+that. (The object must be implemented as hash.)
+
+ my $foo = Foo->new;
+
+ # this trigger ($sub_foo) would apply only to $foo object
+ $foo->add_trigger($triggerpoint => $sub_foo);
+ $foo->foo;
+
+ # And not to another $bar object
+ my $bar = Foo->new;
+ $bar->foo;
+
+=item call_trigger
+
+ $foo->call_trigger($triggerpoint, @args);
+
+Calls triggers for trigger point, which were added via C<add_trigger>
+method. Each triggers will be passed a copy of the object as the first argument.
+Remaining arguments passed to C<call_trigger> will be passed on to each trigger.
+Triggers are invoked in the same order they were defined.
+
+If there are no C<abortable> triggers or no C<abortable> trigger point returns
+a false value, C<call_trigger> will return the number of triggers processed.
+
+
+If an C<abortable> trigger returns a false value, call trigger will stop execution
+of the trigger point and return undef.
+
+=item last_trigger_results
+
+ my @results = @{ $foo->last_trigger_results };
+
+Returns a reference to an array of the return values of all triggers called
+for the last trigger point. Results are ordered in the same order the triggers
+were run.
+
+
+=back
+
+=head1 TRIGGER POINTS
+
+By default you can make any number of trigger points, but if you want
+to declare names of trigger points explicitly, you can do it via
+C<import>.
+
+ package Foo;
+ use Jifty::DBI::Class::Trigger qw(foo bar baz);
+
+ package main;
+ Foo->add_trigger(foo => \&sub1); # okay
+ Foo->add_trigger(hoge => \&sub2); # exception
+
+=head1 FAQ
+
+B<Acknowledgement:> Thanks to everyone at POOP mailing-list
+(http://poop.sourceforge.net/).
+
+=over 4
+
+=item Q.
+
+This module lets me add subs to be run before/after a specific
+subroutine is run. Yes?
+
+=item A.
+
+You put various call_trigger() method in your class. Then your class
+users can call add_trigger() method to add subs to be run in points
+just you specify (exactly where you put call_trigger()).
+
+=item Q.
+
+Are you aware of the perl-aspects project and the Aspect module? Very
+similar to Jifty::DBI::Class::Trigger by the look of it, but its not nearly as
+explicit. Its not necessary for foo() to actually say "triggers go
+*here*", you just add them.
+
+=item A.
+
+Yep ;)
+
+But the difference with Aspect would be that Jifty::DBI::Class::Trigger is so
+simple that it's easy to learn, and doesn't require 5.6 or over.
+
+=item Q.
+
+How does this compare to Sub::Versive, or Hook::LexWrap?
+
+=item A.
+
+Very similar. But the difference with Jifty::DBI::Class::Trigger would be the
+explicitness of trigger points.
+
+In addition, you can put hooks in any point, rather than pre or post
+of a method.
+
+=item Q.
+
+It looks interesting, but I just can't think of a practical example of
+its use...
+
+=item A.
+
+(by Tony Bowden)
+
+I originally added code like this to Class::DBI to cope with one
+particular case: auto-upkeep of full-text search indices.
+
+So I added functionality in Class::DBI to be able to trigger an
+arbitary subroutine every time something happened - then it was a
+simple matter of setting up triggers on INSERT and UPDATE to reindex
+that row, and on DELETE to remove that index row.
+
+See L<Class::DBI::mysql::FullTextSearch> and its source code to see it
+in action.
+
+=back
+
+=head1 AUTHOR
+
+IMPORTANT: DO NOT REPORT BUGS TO THE AUTHORS MENTIONED BELOW. PLEASE
+REPORT THEM TO JIFTY-DEVEL at LISTS.BESTPRACTICAL.COM. PLEASE SEE THE WARNING
+ABOVE
+
+Original idea by Tony Bowden E<lt>tony at kasei.comE<gt> in Class::DBI.
+
+Code by Tatsuhiko Miyagawa E<lt>miyagawa at bulknews.netE<gt>.
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=head1 SEE ALSO
+
+L<Class::DBI>
+
+=cut
+
Modified: Jifty-DBI/trunk/lib/Jifty/DBI/Collection.pm
==============================================================================
--- Jifty-DBI/trunk/lib/Jifty/DBI/Collection.pm (original)
+++ Jifty-DBI/trunk/lib/Jifty/DBI/Collection.pm Sat Mar 3 11:41:08 2007
@@ -1754,17 +1754,6 @@
return $self->{table};
}
-=head2 refers_to
-
-Private convenience method needed for the declarative schema generation.
-
-=cut
-
-sub refers_to {
- my $class = shift;
- return ( Jifty::DBI::Schema::Trait->new( refers_to => $class ), @_ );
-}
-
=head2 clone
Returns copy of the current object with all search restrictions.
Modified: Jifty-DBI/trunk/lib/Jifty/DBI/Column.pm
==============================================================================
--- Jifty-DBI/trunk/lib/Jifty/DBI/Column.pm (original)
+++ Jifty-DBI/trunk/lib/Jifty/DBI/Column.pm Sat Mar 3 11:41:08 2007
@@ -77,17 +77,8 @@
*read = \&readable;
*write = \&writable;
-sub length {
- Carp::carp('$column->length is deprecated; use $column->max_length instead');
- my $self = shift;
- $self->max_length(@_);
-}
-
-sub until {
- Carp::carp('$column->until is deprecated; use $column->till instead');
- my $self = shift;
- $self->till(@_);
-}
+sub length { Carp::croak('$column->length is no longer supported; use $column->max_length instead') }
+sub until { Carp::croak('$column->until is no longer supported; use $column->till instead') }
=head2 active
Modified: Jifty-DBI/trunk/lib/Jifty/DBI/Record.pm
==============================================================================
--- Jifty-DBI/trunk/lib/Jifty/DBI/Record.pm (original)
+++ Jifty-DBI/trunk/lib/Jifty/DBI/Record.pm Sat Mar 3 11:41:08 2007
@@ -7,6 +7,8 @@
use Lingua::EN::Inflect ();
use Jifty::DBI::Column ();
use UNIVERSAL::require ();
+use Jifty::DBI::Class::Trigger; # exports by default
+
use base qw/
Class::Data::Inheritable
@@ -142,7 +144,6 @@
my $self = shift;
my $column_name = shift;
my $attribute = lc( shift || '' );
-
my $col = $self->column($column_name);
return undef unless ( $col and $col->can($attribute) );
return $col->$attribute();
@@ -188,6 +189,7 @@
$column->readable(1);
$column->type('serial');
$column->mandatory(1);
+
$self->_init_methods_for_column($column);
}
@@ -444,8 +446,7 @@
sub column {
my $self = shift;
my $name = lc( shift || '' );
- my $col = $self->COLUMNS;
-
+ my $col = $self->_columns_hashref;
return undef unless $col && exists $col->{$name};
return $col->{$name};
@@ -467,7 +468,7 @@
<=> ( ( $a->type || '' ) eq 'serial' ) )
or ( ($a->sort_order || 0) <=> ($b->sort_order || 0))
or ( $a->name cmp $b->name )
- } grep { $_->active } values %{ $self->COLUMNS || {} }
+ } grep { $_->active } values %{ $self->_columns_hashref }
])}
}
@@ -489,9 +490,16 @@
<=> ( ( $a->type || '' ) eq 'serial' ) )
or ( ($a->sort_order || 0) <=> ($b->sort_order || 0))
or ( $a->name cmp $b->name )
- } values %{ $self->COLUMNS || {} }
+ } values %{ $self->_columns_hashref || {} }
+}
+
+sub _columns_hashref {
+ my $self = shift;
+
+ return ($self->COLUMNS||{});
}
+
# sub {{{ readable_attributes
=head2 readable_attributes
@@ -602,8 +610,8 @@
my $column = shift;
my $value = $self->__value( $column => @_ );
- my $method = $self->can("after_$column");
- $method->( $self, \$value ) if $method;
+ $self->_run_callback( name => "after_".$column,
+ args => \$value);
return $value;
}
@@ -690,23 +698,18 @@
@_
);
- my $method = "before_set_" . $args{column};
- if ( $self->can($method) ) {
- my $before_set_ret = $self->$method( \%args );
- return $before_set_ret
- unless ($before_set_ret);
- }
- my $ok = $self->__set(%args);
+ my $ok = $self->_run_callback( name => "before_set_" . $args{column},
+ args => \%args);
+ return $ok if( not defined $ok);
- return $ok unless $ok;
+ $ok = $self->__set(%args);
+ return $ok if not $ok;
- $method = "after_set_" . $args{column};
- if( $self->can($method) ) {
# Fetch the value back to make sure we have the actual value
my $value = $self->_value($args{column});
- $self->$method({column => $args{column}, value => $value});
- }
+ my $after_set_ret = $self->_run_callback( name => "after_set_" . $args{column}, args =>
+ {column => $args{column}, value => $value});
return $ok;
}
@@ -1042,14 +1045,15 @@
- if ( $self->can('before_create') ) {
- my $before_ret = $self->before_create( \%attribs );
- return ($before_ret) unless ($before_ret);
- }
+ my $ok = $self->_run_callback( name => "before_create", args => \%attribs);
+ return $ok if ( not defined $ok);
my $ret = $self->__create(%attribs);
- $self->after_create( \$ret ) if $self->can('after_create');
+ $ok = $self->_run_callback( name => "after_create",
+ args => \$ret);
+ return $ok if (not defined $ok);
+
if ($class) {
$self->load_by_cols(id => $ret);
return ($self);
@@ -1143,12 +1147,13 @@
sub delete {
my $self = shift;
- if ( $self->can('before_delete') ) {
- my $before_ret = $self->before_delete();
- return $before_ret unless ($before_ret);
- }
+ my $before_ret = $self->_run_callback( name => 'before_delete' );
+ return $before_ret unless (defined $before_ret);
my $ret = $self->__delete;
- $self->after_delete( \$ret ) if $self->can('after_delete');
+
+ my $after_ret
+ = $self->_run_callback( name => 'after_delete', args => \$ret );
+ return $after_ret unless (defined $after_ret);
return ($ret);
}
@@ -1250,11 +1255,6 @@
=cut
-sub refers_to {
- my $class = shift;
- return ( Jifty::DBI::Schema::Trait->new(refers_to => $class), @_ );
-}
-
sub _filters {
my $self = shift;
my %args = ( direction => 'input', column => undef, @_ );
@@ -1341,6 +1341,90 @@
}
}
+
+=head2 run_canonicalization_for_column
+
+=cut
+
+sub run_canonicalization_for_column {
+ my $self = shift;
+ my %args = ( column => undef,
+ value => undef,
+ @_);
+
+ my ($ret,$value_ref) = $self->_run_callback ( name => "canonicalize_".$args{'column'}, args => $args{'value'});
+ return unless defined $ret;
+ return ( exists $value_ref->[-1]->[0] ? $value_ref->[-1]->[0] : $args{'value'});
+}
+
+sub has_canonicalizer_for_column {
+ my $self = shift;
+ my $key = shift;
+ my $method = "canonicalize_$key";
+ if( $self->can($method) ) {
+ return 1;
+ } else {
+ return undef;
+ }
+}
+
+
+=head2 run_canonicalization_for_column
+
+=cut
+
+sub run_validation_for_column {
+ my $self = shift;
+ my %args = (
+ column => undef,
+ value => undef,
+ @_
+ );
+ my $key = $args{'column'};
+ my $attr = $args{'value'};
+
+
+ my ($ret, $results) = $self->_run_callback( name => "validate_".$key, args => $attr );
+
+ if (defined $ret) {
+ return ( 1, 'Validation ok' );
+ }
+ else {
+ return @{$results->[-1]};
+ }
+
+}
+
+sub has_validator_for_column {
+ my $self = shift;
+ my $key = shift;
+ if ( $self->can( "validate_" . $key ) ) {
+ return 1;
+ } else {
+ return undef;
+ }
+}
+
+
+sub _run_callback {
+ my $self = shift;
+ my %args = (
+ name => undef,
+ args => undef,
+ @_
+ );
+
+ my $ret;
+ my $method = $args{'name'};
+ my @results;
+ if ( my $func = $self->can($method) ) {
+ @results = $func->($self, $args{args} );
+ return(wantarray ? (undef, [@results]) : undef) unless $results[0];
+ }
+ $ret = $self->call_trigger( $args{'name'} => $args{args} );
+ return (wantarray ? ($ret, [[@results],@{$self->last_trigger_results}]) : $ret);
+}
+
1;
__END__
Added: Jifty-DBI/trunk/lib/Jifty/DBI/Record/Plugin.pm
==============================================================================
--- (empty file)
+++ Jifty-DBI/trunk/lib/Jifty/DBI/Record/Plugin.pm Sat Mar 3 11:41:08 2007
@@ -0,0 +1,26 @@
+package Jifty::DBI::Record::Plugin;
+
+use warnings;
+use strict;
+
+
+use base qw/Exporter/;
+
+
+sub import {
+ my $self = shift;
+ my $caller = caller;
+ for ($self->columns) {
+ $caller->COLUMNS->{$_->name} = $_ ;
+ $caller->_init_methods_for_column($_);
+ }
+ $self->export_to_level(1,undef);
+
+ if (my $triggers = $self->can('register_triggers') ) {
+ $triggers->($caller)
+ }
+}
+
+
+
+1;
Modified: Jifty-DBI/trunk/lib/Jifty/DBI/Schema.pm
==============================================================================
--- Jifty-DBI/trunk/lib/Jifty/DBI/Schema.pm (original)
+++ Jifty-DBI/trunk/lib/Jifty/DBI/Schema.pm Sat Mar 3 11:41:08 2007
@@ -41,13 +41,128 @@
=cut
use Carp qw/croak carp/;
-use Exporter::Lite;
-our @EXPORT
- = qw(column type default literal validator autocompleted immutable unreadable max_length length distinct mandatory not_null sort_order valid_values label hints render_as render since till input_filters output_filters filters virtual is as by are on schema indexed valid order);
+use Scalar::Defer;
+use base qw(Class::Data::Inheritable);
+__PACKAGE__->mk_classdata('TYPES' => {});
+
+use Object::Declare (
+ mapping => {
+ column => sub { Jifty::DBI::Column->new({@_}) } ,
+ },
+ aliases => {
+ default_value => 'default',
+ available => 'available_values',
+ valid => 'valid_values',
+ render => 'render_as',
+ order => 'sort_order',
+ filters => 'input_filters',
+ },
+ copula => {
+ is => sub { return @_ if $#_;
+ my $typehandler = __PACKAGE__->TYPES->{$_[0]};
+ # XXX: when we have a type name
+ # convention, give a warning when it
+ # looks like a type name but not found
+ return ($_[0] => 1) unless $typehandler;
+ return $typehandler->();
+ },
+ are => '',
+ as => '',
+ ajax => 'ajax_',
+ refers_to => sub { refers_to => @_ },
+ references => sub { refers_to => @_ },
+ },
+);
+use Class::Data::Inheritable;
+use UNIVERSAL::require ();
+
+our @EXPORT = qw( defer lazy column schema by render_as since till literal);
+
+sub by ($) { @_ }
+sub render_as ($) { render as @_ }
+sub since ($) { since is @_ }
+sub till ($) { till is @_ }
+
+sub literal($) {
+ my $value = shift;
+ return \$value;
+}
our $SCHEMA;
our $SORT_ORDERS = {};
+use Exporter::Lite ();
+# TODO - This "sub import" is strictly here to catch the deprecated "length is 40".
+# Once the deprecation cycle is over we should take this away and rever to
+# "use Exporter::Lite" in the line above.
+my $old_sig_die;
+
+sub import {
+ no warnings qw( uninitialized numeric );
+ $old_sig_die ||= $SIG{__DIE__};
+ $SIG{__DIE__} = \&filter_die unless $SIG{__DIE__} and $SIG{__DIE__} == \&filter_die;
+ goto &Exporter::Lite::import;
+}
+
+sub filter_die {
+ # Calling it by hand means we restore the old sighandler.
+ $SIG{__DIE__} = $old_sig_die;
+ if ($_[0] =~ /near "is (\d+)"/) {
+ carp @_, << ".";
+
+*********************************************************
+
+ Due to an incompatible API change, the "length" field in
+ Jifty::DBI columns has been renamed to "max_length":
+
+ column foo =>
+ length is $1; # NOT VALID
+
+ Please write this instead:
+
+ column foo =>
+ max_length is $1 # VALID
+
+ Sorry for the inconvenience.
+
+**********************************************************
+
+
+.
+ exit 1;
+ }
+ elsif ($_[0] =~ /Undefined subroutine &Jifty::DBI::Schema::column|Can't locate object method "type" via package "(?:is|are)"/) {
+ my $from = (caller)[0];
+ $from =~ s/::Schema$//;
+ my $base = $INC{'Jifty/Record.pm'} ? "Jifty::Record" : "Jifty::DBI::Record";
+
+ no strict 'refs';
+ carp @_, << ".";
+*********************************************************
+
+ Calling 'column' within a schema class is an error:
+
+ package $from\::Schema;
+ column foo => ...; # NOT VALID
+
+ Please write this instead:
+
+ package $from;
+ use Jifty::DBI::Schema;
+ use @{[(${"$from\::ISA"} || [$base])->[0] || $base]} schema {
+ column foo => ...; # VALID
+ };
+
+ Sorry for the inconvenience.
+
+*********************************************************
+.
+ }
+
+ die @_;
+}
+
+
=head1 FUNCTIONS
All these functions are exported. However, if you use the C<schema> helper function,
@@ -68,38 +183,79 @@
sub schema (&) {
my $code = shift;
-
- my $from = (caller)[0];
+ my $from = caller;
my $new_code = sub {
- $code->();
-
- # Unimport all our symbols from the calling package.
- foreach my $sym (@EXPORT) {
- no strict 'refs';
- undef *{"$from\::$sym"}
- if \&{"$from\::$sym"} == \&$sym;
- }
+ no warnings 'redefine';
+ local *_ = sub { my $args = \@_; defer { _(@$args) } };
+ $from->_init_columns;
+
+ my @columns = &declare($code);
+
+ # Unimport all our symbols from the calling package.
+ foreach my $sym (@EXPORT) {
+ no strict 'refs';
+ undef *{"$from\::$sym"}
+ if \&{"$from\::$sym"} == \&$sym;
+ }
+
+ foreach my $column (@columns) {
+ next if !ref($column);
+ _init_column($column);
+ }
$from->_init_methods_for_columns;
};
- return('-base' => $new_code);
+ return ('-base' => $new_code);
}
-=head2 column
+use Hash::Merge ();
+
+no warnings 'uninitialized';
+use constant MERGE_PARAM_BEHAVIOUR => {
+ SCALAR => {
+ SCALAR => sub { CORE::length($_[1]) ? $_[1] : $_[0] },
+ ARRAY => sub { [ @{$_[1]} ] },
+ HASH => sub { $_[1] } },
+ ARRAY => {
+ SCALAR => sub { CORE::length($_[1]) ? $_[1] : $_[0] },
+ ARRAY => sub { [ @{$_[1]} ] },
+ HASH => sub { $_[1] } },
+ HASH => {
+ SCALAR => sub { CORE::length($_[1]) ? $_[1] : $_[0] },
+ ARRAY => sub { [ @{$_[1]} ] },
+ HASH => sub { Hash::Merge::_merge_hashes( $_[0], $_[1] ) } }
+};
+
+=head2 merge_params HASHREF HASHREF
+
+Takes two hashrefs. Merges them together and returns the merged hashref.
+
+ - Empty fields in subclasses don't override nonempty fields in superclass anymore.
+ - Arrays don't merge; e.g. if parent class's valid_values is [1,2,3,4], and
+ subclass's valid_values() is [1,2], they don't somehow become [1,2,3,4,1,2].
+
+BUG: This should either be a private routine or factored out into Jifty::Util
-Set forth the description of a column in the data store.
-Note: If the column uses 'refers_to' to reference another class then you
-should not name the column ending in '_id' as it has special meaning.
=cut
-sub column {
- my $name = lc(shift);
+sub merge_params {
+ my $prev_behaviour = Hash::Merge::get_behavior();
+ Hash::Merge::specify_behavior( MERGE_PARAM_BEHAVIOUR, "merge_params" );
+ my $rv = Hash::Merge::merge(@_);
+ Hash::Merge::set_behavior( $prev_behaviour );
+ return $rv;
+}
+
- my $from = (caller)[0];
+sub _init_column {
+ my $column = shift;
+ my $name = $column->name;
+
+ my $from = (caller(2))[0];
if ($from =~ s/::Schema$// && $from !~ /Script/) {
no strict 'refs';
@@ -132,23 +288,23 @@
croak "Illegal column definition for column $name in $from"
if grep {not UNIVERSAL::isa($_, "Jifty::DBI::Schema::Trait")} @_;
- $from->_init_columns;
-
+ $column->readable(!(delete $column->{unreadable}));
+ $column->writable(!(delete $column->{immutable}));
- my @args = (
- ! unreadable(),
- ! immutable(),
- ! virtual(),
- type(''),
- @_
- );
+ # XXX: deprecated
+ $column->mandatory(1) if delete $column->{not_null};
- my $column = Jifty::DBI::Column->new( { name => $name } );
$column->sort_order($SORT_ORDERS->{$from}++);
- $_->apply($column) for @args;
+ $column->input_filters($column->{input_filters} || []);
+ $column->output_filters($column->{output_filters} || []);
if ( my $refclass = $column->refers_to ) {
+ if (ref($refclass) eq 'ARRAY') {
+ $column->by($refclass->[1]);
+ $column->refers_to($refclass = $refclass->[0]);
+ }
+
$refclass->require();
$column->type('integer') unless ( $column->type );
@@ -157,15 +313,14 @@
my $aliased_as = $1;
my $virtual_column = $from->add_column($aliased_as);
- # XXX FIXME I think the next line is wrong, but things
- # explode without it -- mostly because we unique-key
- # on name instead of some conbination of name and
- # alias_for_column in a couple places
- $virtual_column->name( $name );
- $virtual_column->aliased_as($aliased_as);
- $_->apply($virtual_column) for @args;
+ # Clone ourselves into the virtual column
+ %$virtual_column = %$column;
+
$column->refers_to(undef);
+
+ $virtual_column->aliased_as($aliased_as);
$virtual_column->alias_for_column($name);
+
$from->_init_methods_for_column($virtual_column);
}
$column->by('id') unless $column->by;
@@ -188,19 +343,26 @@
# through the &schema wrapper, so we defer initialization here
# to not upset column names such as "label" and "type".
# (We may not *have* a caller(1) if the user is executing a .pm file.)
- my $caller1 = caller(1);
- return if defined $caller1 && $caller1 eq __PACKAGE__;
+}
- $from->_init_methods_for_column($column)
+sub register_types {
+ my $class = shift;
+ while (my ($type, $sub) = splice(@_, 0, 2)) {
+ $class->TYPES->{$type} = $sub;
+ }
}
-=head2 refers_to
+1;
+
+__END__
+
+=head2 references
Indicates that the column references an object or a collection of objects in another
class. You may refer to either a class that inherits from Jifty::Record by a primary
key in that class or to a class that inherits from Jifty::Collection.
-Correct usage is C<refers_to Application::Model::OtherClass by 'column_name'>, where
+Correct usage is C<references Application::Model::OtherClass by 'column_name'>, where
Application::Model::OtherClass is a valid Jifty model and C<'column_name'> is
a column containing unique values in OtherClass. You can omit C<by 'column_name'> and
the column name 'id' will be used.
@@ -213,7 +375,11 @@
For columns referring to Jifty::Records you can access the actual value of the column
instead of the object reference by appending '_id' to the column name. As a result,
-you may not end any column name which uses 'refers_to' using '_id'.
+you may not end any column name which uses 'references' using '_id'.
+
+=head2 refers_to
+
+Synonym for C<references>.
=cut
@@ -230,59 +396,28 @@
databases. For example blobs have different names between
mysql and postgres.
-=cut
-
-sub type {
- _list( type => @_ );
-}
-
=head2 default
Give a default value for the column. Correct usage is C<default is
'foo'>.
-=cut
-
-sub default {
- _list( default => @_ );
-}
-
=head2 literal
Used for default values, to connote that they should not be quoted
before being supplied as the default value for the column. Correct
usage is C<default is literal 'now()'>.
-=cut
-
-sub literal($) {
- my $value = shift;
- return \$value;
-}
-
=head2 validator
Defines a subroutine which returns a true value only for valid values
this column can have. Correct usage is C<validator is \&foo>.
-=cut
-
-sub validator {
- _list( validator => @_ );
-}
-
=head2 immutable
States that this column is not writable. This is useful for
properties that are set at creation time but not modifiable
thereafter, like 'created by'. Correct usage is C<is immutable>.
-=cut
-
-sub immutable {
- _item( writable => 0, @_ );
-}
-
=head2 unreadable
States that this column is not directly readable by the application
@@ -290,93 +425,29 @@
the like. The data is still accessible via C<< $record->_value('') >>.
Correct usage is C<is unreadable>.
-=cut
-
-sub unreadable {
- _item( readable => 0, @_ );
-}
-
=head2 max_length
-Sets a maximum length to store in the database; values longer than
+Sets a maximum max_length to store in the database; values longer than
this are truncated before being inserted into the database, using
L<Jifty::DBI::Filter::Truncate>. Note that this is in B<bytes>, not
B<characters>. Correct usage is C<max_length is 42>.
-=cut
-
-sub max_length {
- _list( max_length => @_ );
-}
-
-=head2 length
-
-DEPRECATED alias for C<max_length>. Do not use; this will go away in the
-next version.
-
-=cut
-
-sub length {
- no strict 'refs';
- carp << "." unless caller()->{_seen_length_warning}++;
-
-*********************************************************
-
- Due to an incompatible API change, the "length" field in
- Jifty::DBI columns has been renamed to "max_length":
-
- column foo =>
- length is $_[0]; # NOT VALID
-
- Please write this instead:
-
- column foo =>
- max_length is $_[0] # VALID
-
- Sorry for the inconvenience.
-
-**********************************************************
-
-
-.
- _list( max_length => @_ );
-}
-
=head2 mandatory
Mark as a required column. May be used for generating user
interfaces. Correct usage is C<is mandatory>.
-=cut
-
-sub mandatory {
- _item( mandatory => 1, @_ );
-}
-
=head2 not_null
Same as L</mandatory>. This is deprecated. Currect usage would be
C<is not_null>.
-=cut
-
-sub not_null {
- carp "'is not_null' is deprecated in favor of 'is mandatory'";
- _item( mandatory => 1, @_ );
-}
-
=head2 autocompleted
Mark as an autocompleted column. May be used for generating user
interfaces. Correct usage is C<is autocompleted>.
-=cut
-
-sub autocompleted {
- _item( autocompleted => 1, @_ );
-}
-
=head2 distinct
Declares that a column should only have distinct values. This
@@ -386,56 +457,26 @@
columns implemented in L<DBIx::DBSchema> at this time.
Correct usage is C<is distinct>.
-=cut
-
-sub distinct {
- _item( distinct => 1, @_ );
-}
-
=head2 virtual
Declares that a column is not backed by an actual column in the
database, but is instead computed on-the-fly.
-=cut
-
-sub virtual {
- _item( virtual => 1, @_ );
-}
-
-
=head2 sort_order
Declares an integer sort value for this column. By default, Jifty will sort
columns in the order they are defined.
-=cut
-
-sub sort_order {
- _item ( sort_order => (shift @_ || 0));
-}
-
=head2 order
Alias for C<sort_order>.
-=cut
-
-sub order { sort_order(@_) }
-
-
=head2 input_filters
Sets a list of input filters on the data. Correct usage is
C<input_filters are 'Jifty::DBI::Filter::DateTime'>. See
L<Jifty::DBI::Filter>.
-=cut
-
-sub input_filters {
- _list( input_filters => @_ );
-}
-
=head2 output_filters
Sets a list of output filters on the data. Correct usage is
@@ -443,12 +484,6 @@
L<Jifty::DBI::Filter>. You usually don't need to set this, as the
output filters default to the input filters in reverse order.
-=cut
-
-sub output_filters {
- _list( output_filters => @_ );
-}
-
=head2 filters
Sets a list of filters on the data. These are applied when reading
@@ -457,23 +492,11 @@
actuality, this is the exact same as L</input_filters>, since output
filters default to the input filters, reversed.
-=cut
-
-sub filters {
- _list( input_filters => @_ );
-}
-
=head2 since
What application version this column was last changed. Correct usage
is C<since '0.1.5'>.
-=cut
-
-sub since {
- _list( since => @_ );
-}
-
=head2 till
The version after this column was supported. The column is not available in
@@ -502,45 +525,21 @@
{ display => 'Blue', value => 'blue' },
{ display => 'Red', value => 'red' }
-=cut
-
-sub valid_values {
- _list( valid_values => @_ );
-}
-
=head2 valid
Alias for C<valid_values>.
-=cut
-
-sub valid {
- _list( valid_values => @_ );
-}
-
=head2 label
Designates a human-readable label for the column, for use in user
interfaces. Correct usage is C<label is 'Your foo value'>.
-=cut
-
-sub label {
- _list( label => @_ );
-}
-
=head2 hints
A sentence or two to display in long-form user interfaces about what
might go in this column. Correct usage is C<hints is 'Used by the
frobnicator to do strange things'>.
-=cut
-
-sub hints {
- _list( hints => @_ );
-}
-
=head2 render_as
Used in user interface generation to know how to render the column.
@@ -584,108 +583,15 @@
If these don't meet your needs, you can write your own subclass of
L<Jifty::Web::Form::Field>. See the documentation for that module.
-=cut
-
-sub render_as {
- _list( render_as => @_ );
-}
-
=head2 render
Alias for C<render_as>.
-=cut
-
-sub render {
- _list( render_as => @_ );
-}
-
=head2 indexed
An index will be built on this column
Correct usage is C<is indexed>
-=cut
-
-sub indexed {
- _list( indexed => 1, @_ );
-}
-
-=head2 by
-
-Helper method to improve readability.
-
-=cut
-
-sub by {
- _list( by => @_ );
-}
-
-=head2 is
-
-Helper method to improve readability.
-
-=cut
-
-sub is {
- my $thing = shift;
- ref $thing eq "ARRAY" ? ( @{$thing}, @_ ) : ($thing, @_);
-}
-
-=head2 as
-
-Helper method to improve readability.
-
-=cut
-
-sub as {
- my $thing = shift;
- ref $thing eq "ARRAY" ? ( @{$thing}, @_ ) : ($thing, @_);
-}
-
-=head2 are
-
-Helper method to improve readability.
-
-=cut
-
-sub are {
- my $ref = [];
- push @{$ref}, shift @_ while @_ and not UNIVERSAL::isa($_[0], "Jifty::DBI::Schema::Trait");
- return( $ref, @_ );
-}
-
-=head2 on
-
-Helper method to improve readability.
-
-=cut
-
-sub on {
- _list( self => shift );
-}
-
-sub _list {
- defined wantarray
- or croak("Cannot add traits in void context -- check for misspelled preceding comma as a semicolon or missing use statements for models you refer_to.");
-
- wantarray
- or croak("Cannot call list traits in scalar context -- check for unneccessary 'is'");
- _trait(@_);
-}
-
-sub _item {
- defined wantarray
- or croak("Cannot add traits in void context -- check for misspelled preceding comma as a semicolon");
-
- _trait(@_);
-}
-
-sub _trait {
- my @trait;
- push @trait, shift @_ while @_ and not UNIVERSAL::isa($_[0], "Jifty::DBI::Schema::Trait");
- return wantarray ? (Jifty::DBI::Schema::Trait->new(@trait), @_) : Jifty::DBI::Schema::Trait->new(@trait);
-}
=head1 EXAMPLE
@@ -702,32 +608,4 @@
=cut
-package Jifty::DBI::Schema::Trait;
-
-use overload "!" => \&negation;
-use Carp qw/croak/;
-
-sub new {
- my $class = shift;
- return bless [@_], $class;
-}
-
-sub apply {
- my $self = shift;
- my ($column) = @_;
-
- my ($method, $argument) = @{$self};
-
- croak("Illegal Jifty::DBI::Schema property '$method'")
- unless $column->can($method);
-
- $column->$method($argument);
-}
-
-sub negation {
- my $self = shift;
- my ($trait, @rest) = @{$self};
- return (ref $self)->new($trait, map {not $_} @rest);
-}
-
1;
Modified: Jifty-DBI/trunk/t/01records.t
==============================================================================
--- Jifty-DBI/trunk/t/01records.t (original)
+++ Jifty-DBI/trunk/t/01records.t Sat Mar 3 11:41:08 2007
@@ -38,7 +38,6 @@
is( $rec->_accessible('id' => 'write'), 0, 'id is not accessible for write' );
is( $rec->_accessible('id'), undef, "any column is not accessible in undefined mode" );
is( $rec->_accessible('unexpected_column' => 'read'), undef, "column doesn't exist and can't be accessible for read" );
-
is_deeply( [sort($rec->readable_attributes)], [sort qw(address employee_id id name phone)], 'readable attributes' );
is_deeply( [sort($rec->writable_attributes)], [sort qw(address employee_id name phone)], 'writable attributes' );
@@ -290,7 +289,7 @@
type is 'varchar(14)';
column phone =>
- type is 'varchar(18)',
+ type is 'varchar(18)';
column address =>
type is 'varchar(50)',
Modified: Jifty-DBI/trunk/t/02records_object.t
==============================================================================
--- Jifty-DBI/trunk/t/02records_object.t (original)
+++ Jifty-DBI/trunk/t/02records_object.t Sat Mar 3 11:41:08 2007
@@ -119,7 +119,7 @@
BEGIN {
use Jifty::DBI::Schema;
use Jifty::DBI::Record schema {
- column employee => refers_to TestApp::Employee;
+ column employee => references TestApp::Employee;
column phone => type is 'varchar(18)';
}
}
Modified: Jifty-DBI/trunk/t/11schema_records.t
==============================================================================
--- Jifty-DBI/trunk/t/11schema_records.t (original)
+++ Jifty-DBI/trunk/t/11schema_records.t Sat Mar 3 11:41:08 2007
@@ -266,7 +266,7 @@
use Jifty::DBI::Schema;
use Jifty::DBI::Record schema {
column name => type is 'varchar';
- column phones => refers_to TestApp::PhoneCollection by 'employee';
+ column phones => references TestApp::PhoneCollection by 'employee';
}
}
@@ -282,7 +282,7 @@
BEGIN {
use Jifty::DBI::Schema;
use Jifty::DBI::Record schema {;
- column employee => refers_to TestApp::Employee;
+ column employee => refers_to TestApp::Employee; # "refers_to" is the old synonym to "references"
column phone => type is 'varchar';
}
}
Modified: Jifty-DBI/trunk/t/12prefetch.t
==============================================================================
--- Jifty-DBI/trunk/t/12prefetch.t (original)
+++ Jifty-DBI/trunk/t/12prefetch.t Sat Mar 3 11:41:08 2007
@@ -183,8 +183,8 @@
BEGIN {
use Jifty::DBI::Schema;
use Jifty::DBI::Record schema {
- column name => type 'varchar';
- column phones => refers_to TestApp::PhoneCollection by 'employee';
+ column name => type is 'varchar';
+ column phones => references TestApp::PhoneCollection by 'employee';
}
}
@@ -194,8 +194,8 @@
BEGIN {
use Jifty::DBI::Schema;
use Jifty::DBI::Record schema {
- column employee => refers_to TestApp::Employee;
- column phone => type 'varchar';
+ column employee => references TestApp::Employee;
+ column phone => type is 'varchar';
}
}
Added: Jifty-DBI/trunk/t/15types.t
==============================================================================
--- (empty file)
+++ Jifty-DBI/trunk/t/15types.t Sat Mar 3 11:41:08 2007
@@ -0,0 +1,133 @@
+#!/usr/bin/env perl -w
+
+use strict;
+
+use Test::More;
+BEGIN { require "t/utils.pl" }
+our (@available_drivers);
+
+use constant TESTS_PER_DRIVER => 16;
+
+my $total = scalar(@available_drivers) * TESTS_PER_DRIVER;
+plan tests => $total;
+
+use DateTime ();
+
+foreach my $d ( @available_drivers ) {
+SKIP: {
+ unless( has_schema( 'TestApp::User', $d ) ) {
+ skip "No schema for '$d' driver", TESTS_PER_DRIVER;
+ }
+ unless( should_test( $d ) ) {
+ skip "ENV is not defined for driver '$d'", TESTS_PER_DRIVER;
+ }
+ diag("start testing with '$d' handle") if $ENV{TEST_VERBOSE};
+
+ my $handle = get_handle( $d );
+ connect_handle( $handle );
+ isa_ok($handle->dbh, 'DBI::db');
+
+ {my $ret = init_schema( 'TestApp::User', $handle );
+ isa_ok($ret,'DBI::st', "Inserted the schema. got a statement handle back" );}
+
+ my $rec = TestApp::User->new( handle => $handle );
+ isa_ok($rec, 'Jifty::DBI::Record');
+
+ my $now = time;
+ my $today = DateTime->from_epoch( epoch => $now )->truncate( to => 'day' )->epoch;
+ my $min_of_day = DateTime->from_epoch( epoch => $now )->truncate( to => 'minute' );
+ my $dt = DateTime->from_epoch( epoch => $now );
+ my ($id) = $rec->create( created => $dt, event_on => $dt, event_stops => $min_of_day );
+ ok($id, "Successfuly created ticket");
+ ok($rec->load($id), "Loaded the record");
+ is($rec->id, $id, "The record has its id");
+ isa_ok($rec->created, 'DateTime' );
+ is( $rec->created->epoch, $now, "Correct value");
+ isa_ok($rec->event_on, 'DateTime' );
+ is( $rec->event_on->epoch, $today, "Correct value");
+ isa_ok($rec->event_stops, 'DateTime' );
+ is( $rec->event_stops->minute, $min_of_day->minute, "Correct value");
+ is( $rec->event_stops->hour, $min_of_day->hour, "Correct value");
+
+ # undef/NULL
+ $rec->set_created;
+ is($rec->created, undef, "Set undef value" );
+
+ # from string
+ require POSIX;
+ $rec->set_created( POSIX::strftime( "%Y-%m-%d %H:%M:%S", gmtime($now) ) );
+ isa_ok($rec->created, 'DateTime' );
+ is( $rec->created->epoch, $now, "Correct value");
+
+ cleanup_schema( 'TestApp', $handle );
+ disconnect_handle( $handle );
+}
+}
+
+package TestApp::User;
+use base qw/Jifty::DBI::Record/;
+
+1;
+
+sub schema_sqlite {
+
+<<EOF;
+CREATE table users (
+ id integer primary key,
+ created datetime,
+ event_on date,
+ event_stops time
+)
+EOF
+
+}
+
+sub schema_mysql {
+
+<<EOF;
+CREATE TEMPORARY table users (
+ id integer auto_increment primary key,
+ created datetime,
+ event_on date,
+ event_stops time
+)
+EOF
+
+}
+
+sub schema_pg {
+
+<<EOF;
+CREATE TEMPORARY table users (
+ id serial primary key,
+ created timestamp,
+ event_on date,
+ event_stops time
+)
+EOF
+
+}
+
+BEGIN {
+use Jifty::DBI::Schema;
+Jifty::DBI::Schema->register_types(
+ Date =>
+ sub { type is 'date', input_filters are qw/Jifty::DBI::Filter::Date/ },
+ Time =>
+ sub { type is 'time', input_filters are qw/Jifty::DBI::Filter::Time/ },
+ DateTime => sub {
+ type is 'datetime',
+ input_filters are qw/Jifty::DBI::Filter::DateTime/
+ }
+);
+}
+
+use Jifty::DBI::Record schema {
+ column created => is DateTime;
+ column event_on => is Date;
+ column event_stops => is Time;
+};
+
+
+1;
+
Added: Jifty-DBI/trunk/t/16inheritance.t
==============================================================================
--- (empty file)
+++ Jifty-DBI/trunk/t/16inheritance.t Sat Mar 3 11:41:08 2007
@@ -0,0 +1,185 @@
+#!/usr/bin/env perl -w
+
+use strict;
+
+use Test::More;
+BEGIN { require "t/utils.pl" }
+our (@available_drivers);
+
+use constant TESTS_PER_DRIVER => 17;
+
+my $total = scalar(@available_drivers) * TESTS_PER_DRIVER;
+plan tests => $total;
+
+use DateTime ();
+
+foreach my $d ( @available_drivers ) {
+SKIP: {
+ unless( has_schema( 'TestApp::CrazyUser', $d ) ) {
+ skip "No schema for '$d' driver", TESTS_PER_DRIVER;
+ }
+ unless( should_test( $d ) ) {
+ skip "ENV is not defined for driver '$d'", TESTS_PER_DRIVER;
+ }
+ diag("start testing with '$d' handle") if $ENV{TEST_VERBOSE};
+
+ my $handle = get_handle( $d );
+ connect_handle( $handle );
+ isa_ok($handle->dbh, 'DBI::db');
+
+ {my $ret = init_schema( 'TestApp::User', $handle );
+ isa_ok($ret,'DBI::st', "Inserted the schema. got a statement handle back" );}
+ {my $ret = init_schema( 'TestApp::CrazyUser', $handle );
+ isa_ok($ret,'DBI::st', "Inserted the schema. got a statement handle back" );}
+ my $rec = TestApp::CrazyUser->new( handle => $handle );
+ isa_ok($rec, 'Jifty::DBI::Record');
+
+ my $now = time;
+ my $today = DateTime->from_epoch( epoch => $now )->truncate( to => 'day' )->epoch;
+ my $min_of_day = DateTime->from_epoch( epoch => $now )->truncate( to => 'minute' );
+ my $dt = DateTime->from_epoch( epoch => $now );
+ my ($id) = $rec->create( created => $dt, event_on => $dt, event_stops => $min_of_day );
+ ok($id, "Successfuly created ticket");
+ ok($rec->load($id), "Loaded the record");
+ is($rec->id, $id, "The record has its id");
+ isa_ok($rec->created, 'DateTime' );
+ is( $rec->created->epoch, $now, "Correct value");
+ isa_ok($rec->event_on, 'DateTime' );
+ is( $rec->event_on->epoch, $today, "Correct value");
+ isa_ok($rec->event_stops, 'DateTime' );
+ is( $rec->event_stops->minute, $min_of_day->minute, "Correct value");
+ is( $rec->event_stops->hour, $min_of_day->hour, "Correct value");
+
+ # undef/NULL
+ $rec->set_created;
+ is($rec->created, undef, "Set undef value" );
+
+ # from string
+ require POSIX;
+ $rec->set_created( POSIX::strftime( "%Y-%m-%d %H:%M:%S", gmtime($now) ) );
+ isa_ok($rec->created, 'DateTime' );
+ is( $rec->created->epoch, $now, "Correct value");
+
+ cleanup_schema( 'TestApp', $handle );
+ disconnect_handle( $handle );
+}
+}
+
+package TestApp::User;
+use base qw/Jifty::DBI::Record/;
+
+1;
+
+sub schema_sqlite {
+
+<<EOF;
+CREATE table users (
+ id integer primary key,
+ created datetime,
+ event_on date,
+ event_stops time
+)
+EOF
+
+}
+
+sub schema_mysql {
+
+<<EOF;
+CREATE TEMPORARY table users (
+ id integer auto_increment primary key,
+ created datetime,
+ event_on date,
+ event_stops time
+)
+EOF
+
+}
+
+sub schema_pg {
+
+<<EOF;
+CREATE TEMPORARY table users (
+ id serial primary key,
+ created timestamp,
+ event_on date,
+ event_stops time
+)
+EOF
+
+}
+
+BEGIN {
+use Jifty::DBI::Schema;
+Jifty::DBI::Schema->register_types(
+ Date =>
+ sub { type is 'date', input_filters are qw/Jifty::DBI::Filter::Date/ },
+ Time =>
+ sub { type is 'time', input_filters are qw/Jifty::DBI::Filter::Time/ },
+ DateTime => sub {
+ type is 'datetime',
+ input_filters are qw/Jifty::DBI::Filter::DateTime/
+ }
+);
+}
+
+use Jifty::DBI::Record schema {
+ column created => is DateTime;
+ column event_on => is Date;
+ column event_stops => is Time;
+};
+
+package TestApp::CrazyUser;
+BEGIN {
+our @ISA =qw(TestApp::User);
+}
+use Jifty::DBI::Schema;
+use Jifty::DBI::Record schema {
+ column craziness => type is 'text';
+# column event_on => is mandatory;
+};
+
+sub schema_sqlite {
+
+<<EOF;
+CREATE table crazy_users (
+ id integer primary key,
+ craziness varchar(16),
+ created datetime,
+ event_on date,
+ event_stops time
+)
+EOF
+
+}
+
+sub schema_mysql {
+
+<<EOF;
+CREATE TEMPORARY table crazy_users (
+ id integer auto_increment primary key,
+ created datetime,
+ event_on date,
+ event_stops time
+)
+EOF
+
+}
+
+sub schema_pg {
+
+<<EOF;
+CREATE TEMPORARY table crazy_users (
+ id serial primary key,
+ craziness varchar(16),
+ created timestamp,
+ event_on date,
+ event_stops time
+)
+EOF
+
+}
+
+
+1;
+
Modified: Jifty-DBI/trunk/t/testmodels.pl
==============================================================================
--- Jifty-DBI/trunk/t/testmodels.pl (original)
+++ Jifty-DBI/trunk/t/testmodels.pl Sat Mar 3 11:41:08 2007
@@ -44,7 +44,7 @@
use Jifty::DBI::Record schema {
column employee_id =>
- refers_to Sample::Employee;
+ references Sample::Employee;
column name =>
type is 'varchar',
More information about the Jifty-commit
mailing list