Skip Menu |

This queue is for tickets about the Rose-DB-Object CPAN distribution.

Report information
The Basics
Id: 98730
Status: open
Priority: 0/
Queue: Rose-DB-Object

People
Owner: Nobody in particular
Requestors: cpan [...] punch.net
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: (no value)
Fixed in: (no value)



Subject: passing custom params to save to foreign keys
I have a need to pass custom params during a save to foreign keys. Attached is a patch with some documentation on how to use it and a new test file.
Subject: custom-params-to-fk-on-save.diff
Index: lib/Rose/DB/Object.pm =================================================================== --- lib/Rose/DB/Object.pm (revision 2313) +++ lib/Rose/DB/Object.pm (working copy) @@ -20,6 +20,8 @@ our $Debug = 0; +our @valid_save_params = (qw(changes_only prepare_cached cascade)); + # # Object data # @@ -537,7 +539,7 @@ my %code_args = map { ($_ => $args{$_}) } grep { exists $args{$_} } - qw(changes_only prepare_cached cascade); + @valid_save_params; # # Do pre-save stuff @@ -2431,6 +2433,15 @@ If an insert was performed and the primary key is a single column that supports auto-generated values, then the object accessor for the primary key column will contain the auto-generated value. See the L<Serial and Auto-Incremented Columns|/"Serial and Auto-Incremented Columns"> section for more information. +It is possible to set custom params that are passed to foreign keys on save if those params are added to @valid_save_params. + +Example: + + push @Rose::DB::Object::valid_save_params, 'my_custom_param'; + + # now able to call ->save(my_custom_param => 'my value'); + + =item B<update [PARAMS]> Update the current object in the database table. This method should only be used when you're absolutely sure that you want to B<force> the current object to be updated, rather than inserted. It is recommended that you use the L<save|/save> method instead of this one in most circumstances. The L<save|/save> method will "do the right thing," executing an insert or update as appropriate for the current situation.
Subject: db-object-relationship-custom-params.t
#!/usr/bin/perl -w use strict; use Test::More 'no_plan'; #tests => 1604; BEGIN { require 't/test-lib.pl'; use_ok('Rose::DB::Object'); use_ok('Rose::DB::Object::Manager'); } our($HAVE_SQLITE); use FindBin qw($Bin); # # SQLite # SKIP: foreach my $db_type ('sqlite') { skip("SQLite tests", 466) unless($HAVE_SQLITE); Rose::DB->default_type($db_type); my $o = MySQLiteObject->new(name => 'John', id => 1); ok(ref $o && $o->isa('MySQLiteObject'), "new() 1 - $db_type"); ok($o->other_obj({k1 => 1}), "set a foreign key"); push @Rose::DB::Object::valid_save_params, 'custom_valid'; ok($o->save(custom => 1, custom_valid => 1), "save with a custom variables"); } BEGIN { # # SQLite # my $dbh; eval { $dbh = Rose::DB->new('sqlite_admin')->retain_dbh() or die Rose::DB->error; }; if(!$@ && $dbh) { our $HAVE_SQLITE = 1; # Drop existing table and create schema, ignoring errors { local $dbh->{'RaiseError'} = 0; local $dbh->{'PrintError'} = 0; $dbh->do('DROP TABLE rose_db_object_test'); $dbh->do('DROP TABLE rose_db_object_other'); } $dbh->do(<<"EOF"); CREATE TABLE rose_db_object_other ( k1 INT NOT NULL, name VARCHAR(32), UNIQUE(k1) ) EOF $dbh->do(<<"EOF"); CREATE TABLE rose_db_object_test ( id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(32) NOT NULL, fk1 INT, FOREIGN KEY (fk1) REFERENCES rose_db_object_other (k1) ) EOF $dbh->disconnect; # Create test subclasses package MySQLCustomBaseObject; our @ISA = qw(Rose::DB::Object); sub save { my ($self, %args) = @_; if (ref($self) eq "MySQLiteObject") { # main class, does it have the custom variable? Test::More::ok(exists $args{custom}, "custom property exists in main class"); } if (ref($self) eq "MySQLiteOtherObject") { Test::More::ok(!exists $args{custom}, "custom property does not exist in foreign class"); } Test::More::ok(exists $args{custom_valid}, "defined custom property exists in every class"); return $self->SUPER::save(%args); } package MySQLiteOtherObject; our @ISA = qw(MySQLCustomBaseObject); sub init_db { Rose::DB->new('sqlite') } MySQLiteOtherObject->meta->table('rose_db_object_other'); MySQLiteOtherObject->meta->columns ( name => { type => 'varchar'}, k1 => { type => 'int' }, ); MySQLiteOtherObject->meta->primary_key_columns(qw(k1)); MySQLiteOtherObject->meta->initialize; package MySQLiteObject; use Rose::DB::Object::Helpers qw(has_loaded_related); our @ISA = qw(MySQLCustomBaseObject); sub init_db { Rose::DB->new('sqlite') } MySQLiteObject->meta->table('rose_db_object_test'); MySQLiteObject->meta->columns ( 'name', id => { primary_key => 1 }, fk1 => { type => 'int' }, ); MySQLiteObject->meta->add_foreign_keys ( other_obj => { class => 'MySQLiteOtherObject', rel_type => 'one to one', key_columns => { fk1 => 'k1', }, }, ); MySQLiteObject->meta->initialize; } }; END { # Delete test table if($HAVE_SQLITE) { # SQLite my $dbh = Rose::DB->new('sqlite_admin')->retain_dbh() or die Rose::DB->error; $dbh->do('DROP TABLE rose_db_object_test'); $dbh->do('DROP TABLE rose_db_object_other'); $dbh->disconnect; } }
I'll take a look at this when I get a chance (probably not until after October), but the use of @Rose::DB::Object::valid_save_params as an interface to add valid save parameters will likely not be preserved.
Thanks. Attached is an updated patch, there was a place in Rose::DB::Object::MakeMethods::Generic where the parameters were not being passed for map records. I totally understand not liking the interface. If you can give me some idea what you would rather see, I can rework it.
Subject: custom-params-to-fk-on-save-2..diff
Index: lib/Rose/DB/Object/MakeMethods/Generic.pm =================================================================== --- lib/Rose/DB/Object/MakeMethods/Generic.pm (revision 2313) +++ lib/Rose/DB/Object/MakeMethods/Generic.pm (working copy) @@ -5503,7 +5503,7 @@ # Save the map record, if necessary unless($in_db) { - $map_record->save or die $map_record->error; + $map_record->save(%$args) or die $map_record->error; } } Index: lib/Rose/DB/Object.pm =================================================================== --- lib/Rose/DB/Object.pm (revision 2313) +++ lib/Rose/DB/Object.pm (working copy) @@ -20,6 +20,8 @@ our $Debug = 0; +our @valid_save_params = (qw(changes_only prepare_cached cascade)); + # # Object data # @@ -537,7 +539,7 @@ my %code_args = map { ($_ => $args{$_}) } grep { exists $args{$_} } - qw(changes_only prepare_cached cascade); + @valid_save_params; # # Do pre-save stuff @@ -2431,6 +2433,15 @@ If an insert was performed and the primary key is a single column that supports auto-generated values, then the object accessor for the primary key column will contain the auto-generated value. See the L<Serial and Auto-Incremented Columns|/"Serial and Auto-Incremented Columns"> section for more information. +It is possible to set custom params that are passed to foreign keys on save if those params are added to @valid_save_params. + +Example: + + push @Rose::DB::Object::valid_save_params, 'my_custom_param'; + + # now able to call ->save(my_custom_param => 'my value'); + + =item B<update [PARAMS]> Update the current object in the database table. This method should only be used when you're absolutely sure that you want to B<force> the current object to be updated, rather than inserted. It is recommended that you use the L<save|/save> method instead of this one in most circumstances. The L<save|/save> method will "do the right thing," executing an insert or update as appropriate for the current situation.