fixed minor docs error
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Row.pm
CommitLineData
7624b19f 1package DBIx::Class::Row;
2
3use strict;
4use warnings;
5
1edd1722 6use base qw/DBIx::Class/;
701da8c4 7use Carp::Clan qw/^DBIx::Class/;
33dd4e80 8use Scalar::Util ();
9c6d6d93 9use Scope::Guard;
1edd1722 10
aec3eff1 11__PACKAGE__->mk_group_accessors('simple' => qw/_source_handle/);
8c49f629 12
75d07914 13=head1 NAME
7624b19f 14
15DBIx::Class::Row - Basic row methods
16
17=head1 SYNOPSIS
18
19=head1 DESCRIPTION
20
21This class is responsible for defining and doing basic operations on rows
1ea77c14 22derived from L<DBIx::Class::ResultSource> objects.
7624b19f 23
24=head1 METHODS
25
8091aa91 26=head2 new
7624b19f 27
28 my $obj = My::Class->new($attrs);
29
30Creates a new row object from column => value mappings passed as a hash ref
31
33dd4e80 32Passing an object, or an arrayref of objects as a value will call
33L<DBIx::Class::Relationship::Base/set_from_related> for you. When
34passed a hashref or an arrayref of hashrefs as the value, these will
35be turned into objects via new_related, and treated as if you had
36passed objects.
37
7624b19f 38=cut
39
33dd4e80 40## It needs to store the new objects somewhere, and call insert on that list later when insert is called on this object. We may need an accessor for these so the user can retrieve them, if just doing ->new().
41## This only works because DBIC doesnt yet care to check whether the new_related objects have been passed all their mandatory columns
42## When doing the later insert, we need to make sure the PKs are set.
43## using _relationship_data in new and funky ways..
44## check Relationship::CascadeActions and Relationship::Accessor for compat
45## tests!
46
7624b19f 47sub new {
448f820f 48 my ($class, $attrs) = @_;
7624b19f 49 $class = ref $class if ref $class;
04786a4c 50
51 my $new = { _column_data => {} };
52 bless $new, $class;
53
448f820f 54 if (my $handle = delete $attrs->{-source_handle}) {
55 $new->_source_handle($handle);
56 }
e9fe476b 57 if (my $source = delete $attrs->{-result_source}) {
58 $new->result_source($source);
59 }
a6a280b9 60
7624b19f 61 if ($attrs) {
27f01d1f 62 $new->throw_exception("attrs must be a hashref")
63 unless ref($attrs) eq 'HASH';
61a622ee 64
65 my ($related,$inflated);
de7c7c53 66 ## Pretend all the rels are actual objects, unset below if not, for insert() to fix
67 $new->{_rel_in_storage} = 1;
8222f722 68
61a622ee 69 foreach my $key (keys %$attrs) {
70 if (ref $attrs->{$key}) {
af2d42c0 71 ## Can we extract this lot to use with update(_or .. ) ?
61a622ee 72 my $info = $class->relationship_info($key);
73 if ($info && $info->{attrs}{accessor}
c4a30d56 74 && $info->{attrs}{accessor} eq 'single')
61a622ee 75 {
de7c7c53 76 my $rel_obj = delete $attrs->{$key};
33dd4e80 77 if(!Scalar::Util::blessed($rel_obj)) {
2ec8e594 78 $rel_obj = $new->find_or_new_related($key, $rel_obj);
79 $new->{_rel_in_storage} = 0 unless ($rel_obj->in_storage);
33dd4e80 80 }
de7c7c53 81 $new->set_from_related($key, $rel_obj);
82 $related->{$key} = $rel_obj;
61a622ee 83 next;
33dd4e80 84 } elsif ($info && $info->{attrs}{accessor}
85 && $info->{attrs}{accessor} eq 'multi'
86 && ref $attrs->{$key} eq 'ARRAY') {
2ec8e594 87 my $others = delete $attrs->{$key};
88 foreach my $rel_obj (@$others) {
89 if(!Scalar::Util::blessed($rel_obj)) {
90 $rel_obj = $new->new_related($key, $rel_obj);
91 $new->{_rel_in_storage} = 0;
33dd4e80 92 }
2ec8e594 93 }
94 $related->{$key} = $others;
95 next;
96 } elsif ($info && $info->{attrs}{accessor}
97 && $info->{attrs}{accessor} eq 'filter')
61a622ee 98 {
33dd4e80 99 ## 'filter' should disappear and get merged in with 'single' above!
2ec8e594 100 my $rel_obj = delete $attrs->{$key};
33dd4e80 101 if(!Scalar::Util::blessed($rel_obj)) {
df78aeb1 102 $rel_obj = $new->find_or_new_related($key, $rel_obj);
103 $new->{_rel_in_storage} = 0 unless ($rel_obj->in_storage);
33dd4e80 104 }
105 $inflated->{$key} = $rel_obj;
61a622ee 106 next;
2ec8e594 107 } elsif ($class->has_column($key)
108 && $class->column_info($key)->{_inflate_info}) {
61a622ee 109 $inflated->{$key} = $attrs->{$key};
110 next;
111 }
112 }
de7c7c53 113 use Data::Dumper;
61a622ee 114 $new->throw_exception("No such column $key on $class")
115 unless $class->has_column($key);
116 $new->store_column($key => $attrs->{$key});
7624b19f 117 }
f90375dd 118
61a622ee 119 $new->{_relationship_data} = $related if $related;
120 $new->{_inflated_column} = $inflated if $inflated;
7624b19f 121 }
04786a4c 122
7624b19f 123 return $new;
124}
125
8091aa91 126=head2 insert
7624b19f 127
128 $obj->insert;
129
b8810cc5 130Inserts an object into the database if it isn't already in
131there. Returns the object itself. Requires the object's result source to
132be set, or the class to have a result_source_instance method. To insert
133an entirely new object into the database, use C<create> (see
134L<DBIx::Class::ResultSet/create>).
7624b19f 135
136=cut
137
138sub insert {
139 my ($self) = @_;
140 return $self if $self->in_storage;
6aba697f 141 my $source = $self->result_source;
142 $source ||= $self->result_source($self->result_source_instance)
097d3227 143 if $self->can('result_source_instance');
aeb1bf75 144 $self->throw_exception("No result_source set on this object; can't insert")
145 unless $source;
6e399b4f 146
9c6d6d93 147 my $rollback_guard;
148
33dd4e80 149 # Check if we stored uninserted relobjs here in new()
33dd4e80 150 my %related_stuff = (%{$self->{_relationship_data} || {}},
151 %{$self->{_inflated_column} || {}});
9c6d6d93 152
ae66ef47 153 if(!$self->{_rel_in_storage}) {
8222f722 154 $source->storage->txn_begin;
155
9c6d6d93 156 # The guard will save us if we blow out of this scope via die
157
158 $rollback_guard = Scope::Guard->new(sub { $source->storage->txn_rollback });
159
8222f722 160 ## Should all be in relationship_data, but we need to get rid of the
161 ## 'filter' reltype..
162 ## These are the FK rels, need their IDs for the insert.
9c6d6d93 163
164 my @pri = $self->primary_columns;
165
166 REL: foreach my $relname (keys %related_stuff) {
a8c98174 167
168 my $rel_obj = $related_stuff{$relname};
169
170 next REL unless (Scalar::Util::blessed($rel_obj)
171 && $rel_obj->isa('DBIx::Class::Row'));
172
173 my $cond = $source->relationship_info($relname)->{cond};
174
175 next REL unless ref($cond) eq 'HASH';
176
177 # map { foreign.foo => 'self.bar' } to { bar => 'foo' }
178
179 my $keyhash = { map { my $x = $_; $x =~ s/.*\.//; $x; } reverse %$cond };
9c6d6d93 180
181 # assume anything that references our PK probably is dependent on us
a8c98174 182 # rather than vice versa, unless the far side is (a) defined or (b)
183 # auto-increment
9c6d6d93 184
185 foreach my $p (@pri) {
a8c98174 186 if (exists $keyhash->{$p}) {
187 warn $keyhash->{$p};
188 unless (defined($rel_obj->get_column($keyhash->{$p}))
189 || $rel_obj->column_info($keyhash->{$p})
190 ->{is_auto_increment}) {
191 next REL;
192 }
193 }
9c6d6d93 194 }
195
a8c98174 196 $rel_obj->insert();
197 $self->set_from_related($relname, $rel_obj);
198 delete $related_stuff{$relname};
33dd4e80 199 }
200 }
6e399b4f 201
7af8b477 202 $source->storage->insert($source, { $self->get_columns });
ac8e89d7 203
204 ## PK::Auto
3fda409f 205 my @auto_pri = grep {
206 !defined $self->get_column($_) ||
207 ref($self->get_column($_)) eq 'SCALAR'
208 } $self->primary_columns;
209
210 if (@auto_pri) {
211 #$self->throw_exception( "More than one possible key found for auto-inc on ".ref $self )
212 # if defined $too_many;
ac8e89d7 213
214 my $storage = $self->result_source->storage;
215 $self->throw_exception( "Missing primary key but Storage doesn't support last_insert_id" )
216 unless $storage->can('last_insert_id');
3fda409f 217 my @ids = $storage->last_insert_id($self->result_source,@auto_pri);
218 $self->throw_exception( "Can't get last insert id" )
219 unless (@ids == @auto_pri);
220 $self->store_column($auto_pri[$_] => $ids[$_]) for 0 .. $#ids;
ac8e89d7 221 }
33dd4e80 222
ae66ef47 223 if(!$self->{_rel_in_storage}) {
8222f722 224 ## Now do the has_many rels, that need $selfs ID.
225 foreach my $relname (keys %related_stuff) {
9c6d6d93 226 my $rel_obj = $related_stuff{$relname};
227 my @cands;
228 if (Scalar::Util::blessed($rel_obj)
229 && $rel_obj->isa('DBIx::Class::Row')) {
230 @cands = ($rel_obj);
231 } elsif (ref $rel_obj eq 'ARRAY') {
232 @cands = @$rel_obj;
233 }
234 if (@cands) {
235 my $reverse = $source->reverse_relationship_info($relname);
236 foreach my $obj (@cands) {
237 $obj->set_from_related($_, $self) for keys %$reverse;
8222f722 238 $obj->insert() if(!$obj->in_storage);
239 }
33dd4e80 240 }
241 }
8222f722 242 $source->storage->txn_commit;
9c6d6d93 243 $rollback_guard->dismiss;
33dd4e80 244 }
33dd4e80 245
7624b19f 246 $self->in_storage(1);
247 $self->{_dirty_columns} = {};
64acc2bc 248 $self->{related_resultsets} = {};
729b29ae 249 undef $self->{_orig_ident};
7624b19f 250 return $self;
251}
252
8091aa91 253=head2 in_storage
7624b19f 254
255 $obj->in_storage; # Get value
256 $obj->in_storage(1); # Set value
257
258Indicated whether the object exists as a row in the database or not
259
260=cut
261
262sub in_storage {
263 my ($self, $val) = @_;
264 $self->{_in_storage} = $val if @_ > 1;
265 return $self->{_in_storage};
266}
267
8091aa91 268=head2 update
7624b19f 269
d5d833d9 270 $obj->update \%columns?;
7624b19f 271
272Must be run on an object that is already in the database; issues an SQL
d3b0e369 273UPDATE query to commit any changes to the object to the database if
274required.
7624b19f 275
d5d833d9 276Also takes an options hashref of C<< column_name => value> pairs >> to update
277first. But be aware that this hashref might be edited in place, so dont rely on
8b621a87 278it being the same after a call to C<update>. If you need to preserve the hashref,
279it is sufficient to pass a shallow copy to C<update>, e.g. ( { %{ $href } } )
d5d833d9 280
7624b19f 281=cut
282
283sub update {
284 my ($self, $upd) = @_;
701da8c4 285 $self->throw_exception( "Not in database" ) unless $self->in_storage;
4b12b3c2 286 my $ident_cond = $self->ident_condition;
287 $self->throw_exception("Cannot safely update a row in a PK-less table")
288 if ! keys %$ident_cond;
6e399b4f 289
61a622ee 290 if ($upd) {
291 foreach my $key (keys %$upd) {
292 if (ref $upd->{$key}) {
293 my $info = $self->relationship_info($key);
294 if ($info && $info->{attrs}{accessor}
295 && $info->{attrs}{accessor} eq 'single')
296 {
297 my $rel = delete $upd->{$key};
298 $self->set_from_related($key => $rel);
299 $self->{_relationship_data}{$key} = $rel;
af2d42c0 300 } elsif ($info && $info->{attrs}{accessor}
301 && $info->{attrs}{accessor} eq 'multi'
302 && ref $upd->{$key} eq 'ARRAY') {
303 my $others = delete $upd->{$key};
304 foreach my $rel_obj (@$others) {
305 if(!Scalar::Util::blessed($rel_obj)) {
306 $rel_obj = $self->create_related($key, $rel_obj);
307 }
308 }
309 $self->{_relationship_data}{$key} = $others;
310# $related->{$key} = $others;
311 next;
312 }
61a622ee 313 elsif ($self->has_column($key)
314 && exists $self->column_info($key)->{_inflate_info})
315 {
316 $self->set_inflated_column($key, delete $upd->{$key});
317 }
318 }
319 }
320 $self->set_columns($upd);
321 }
5a9e0e60 322 my %to_update = $self->get_dirty_columns;
323 return $self unless keys %to_update;
88cb6a1d 324 my $rows = $self->result_source->storage->update(
f4afcd5d 325 $self->result_source, \%to_update,
326 $self->{_orig_ident} || $ident_cond
327 );
7624b19f 328 if ($rows == 0) {
701da8c4 329 $self->throw_exception( "Can't update ${self}: row not found" );
7624b19f 330 } elsif ($rows > 1) {
701da8c4 331 $self->throw_exception("Can't update ${self}: updated more than one row");
7624b19f 332 }
333 $self->{_dirty_columns} = {};
64acc2bc 334 $self->{related_resultsets} = {};
729b29ae 335 undef $self->{_orig_ident};
7624b19f 336 return $self;
337}
338
8091aa91 339=head2 delete
7624b19f 340
341 $obj->delete
342
b8810cc5 343Deletes the object from the database. The object is still perfectly
61a622ee 344usable, but C<< ->in_storage() >> will now return 0 and the object must
345reinserted using C<< ->insert() >> before C<< ->update() >> can be used
b8810cc5 346on it. If you delete an object in a class with a C<has_many>
347relationship, all the related objects will be deleted as well. To turn
348this behavior off, pass C<cascade_delete => 0> in the C<$attr>
349hashref. Any database-level cascade or restrict will take precedence
350over a DBIx-Class-based cascading delete. See also L<DBIx::Class::ResultSet/delete>.
7624b19f 351
352=cut
353
354sub delete {
355 my $self = shift;
356 if (ref $self) {
701da8c4 357 $self->throw_exception( "Not in database" ) unless $self->in_storage;
4b12b3c2 358 my $ident_cond = $self->ident_condition;
359 $self->throw_exception("Cannot safely delete a row in a PK-less table")
360 if ! keys %$ident_cond;
e0f56292 361 foreach my $column (keys %$ident_cond) {
75d07914 362 $self->throw_exception("Can't delete the object unless it has loaded the primary keys")
363 unless exists $self->{_column_data}{$column};
e0f56292 364 }
88cb6a1d 365 $self->result_source->storage->delete(
7af8b477 366 $self->result_source, $ident_cond);
7624b19f 367 $self->in_storage(undef);
7624b19f 368 } else {
701da8c4 369 $self->throw_exception("Can't do class delete without a ResultSource instance")
097d3227 370 unless $self->can('result_source_instance');
aeb1bf75 371 my $attrs = @_ > 1 && ref $_[$#_] eq 'HASH' ? { %{pop(@_)} } : {};
372 my $query = ref $_[0] eq 'HASH' ? $_[0] : {@_};
097d3227 373 $self->result_source_instance->resultset->search(@_)->delete;
7624b19f 374 }
375 return $self;
376}
377
8091aa91 378=head2 get_column
7624b19f 379
380 my $val = $obj->get_column($col);
381
61a622ee 382Gets a column value from a row object. Does not do any queries; the column
383must have already been fetched from the database and stored in the object. If
384there is an inflated value stored that has not yet been deflated, it is deflated
385when the method is invoked.
7624b19f 386
387=cut
388
389sub get_column {
390 my ($self, $column) = @_;
701da8c4 391 $self->throw_exception( "Can't fetch data as class method" ) unless ref $self;
aeb1bf75 392 return $self->{_column_data}{$column} if exists $self->{_column_data}{$column};
61a622ee 393 if (exists $self->{_inflated_column}{$column}) {
394 return $self->store_column($column,
395 $self->_deflated_column($column, $self->{_inflated_column}{$column}));
396 }
701da8c4 397 $self->throw_exception( "No such column '${column}'" ) unless $self->has_column($column);
7624b19f 398 return undef;
399}
400
9b83fccd 401=head2 has_column_loaded
402
403 if ( $obj->has_column_loaded($col) ) {
404 print "$col has been loaded from db";
405 }
406
407Returns a true value if the column value has been loaded from the
408database (or set locally).
409
410=cut
411
def81720 412sub has_column_loaded {
413 my ($self, $column) = @_;
414 $self->throw_exception( "Can't call has_column data as class method" ) unless ref $self;
61a622ee 415 return 1 if exists $self->{_inflated_column}{$column};
aeb1bf75 416 return exists $self->{_column_data}{$column};
def81720 417}
418
8091aa91 419=head2 get_columns
076a6864 420
421 my %data = $obj->get_columns;
422
8091aa91 423Does C<get_column>, for all column values at once.
076a6864 424
425=cut
426
427sub get_columns {
428 my $self = shift;
61a622ee 429 if (exists $self->{_inflated_column}) {
430 foreach my $col (keys %{$self->{_inflated_column}}) {
431 $self->store_column($col, $self->_deflated_column($col, $self->{_inflated_column}{$col}))
c4a30d56 432 unless exists $self->{_column_data}{$col};
61a622ee 433 }
434 }
cb5f2eea 435 return %{$self->{_column_data}};
d7156e50 436}
437
438=head2 get_dirty_columns
439
440 my %data = $obj->get_dirty_columns;
441
442Identical to get_columns but only returns those that have been changed.
443
444=cut
445
446sub get_dirty_columns {
447 my $self = shift;
448 return map { $_ => $self->{_column_data}{$_} }
449 keys %{$self->{_dirty_columns}};
076a6864 450}
451
ba4a6453 452=head2 get_inflated_columns
453
454 my $inflated_data = $obj->get_inflated_columns;
455
456Similar to get_columns but objects are returned for inflated columns instead of their raw non-inflated values.
457
458=cut
459
460sub get_inflated_columns {
461 my $self = shift;
462 return map {
463 my $accessor = $self->column_info($_)->{'accessor'} || $_;
464 ($_ => $self->$accessor);
465 } $self->columns;
466}
467
8091aa91 468=head2 set_column
7624b19f 469
470 $obj->set_column($col => $val);
471
8091aa91 472Sets a column value. If the new value is different from the old one,
473the column is marked as dirty for when you next call $obj->update.
7624b19f 474
475=cut
476
477sub set_column {
478 my $self = shift;
479 my ($column) = @_;
729b29ae 480 $self->{_orig_ident} ||= $self->ident_condition;
7624b19f 481 my $old = $self->get_column($column);
482 my $ret = $self->store_column(@_);
87772e46 483 $self->{_dirty_columns}{$column} = 1
484 if (defined $old ^ defined $ret) || (defined $old && $old ne $ret);
7624b19f 485 return $ret;
486}
487
8091aa91 488=head2 set_columns
076a6864 489
dc818523 490 my $copy = $orig->set_columns({ $col => $val, ... });
076a6864 491
8091aa91 492Sets more than one column value at once.
076a6864 493
494=cut
495
496sub set_columns {
497 my ($self,$data) = @_;
a2ca474b 498 foreach my $col (keys %$data) {
499 $self->set_column($col,$data->{$col});
076a6864 500 }
c01ab172 501 return $self;
076a6864 502}
503
8091aa91 504=head2 copy
076a6864 505
506 my $copy = $orig->copy({ change => $to, ... });
507
8091aa91 508Inserts a new row with the specified changes.
076a6864 509
510=cut
511
c01ab172 512sub copy {
513 my ($self, $changes) = @_;
333cce60 514 $changes ||= {};
fde6e28e 515 my $col_data = { %{$self->{_column_data}} };
516 foreach my $col (keys %$col_data) {
517 delete $col_data->{$col}
518 if $self->result_source->column_info($col)->{is_auto_increment};
519 }
04786a4c 520
521 my $new = { _column_data => $col_data };
522 bless $new, ref $self;
523
83419ec6 524 $new->result_source($self->result_source);
ecd1f408 525 $new->set_columns($changes);
333cce60 526 $new->insert;
527 foreach my $rel ($self->result_source->relationships) {
528 my $rel_info = $self->result_source->relationship_info($rel);
529 if ($rel_info->{attrs}{cascade_copy}) {
530 my $resolved = $self->result_source->resolve_condition(
531 $rel_info->{cond}, $rel, $new);
532 foreach my $related ($self->search_related($rel)) {
533 $related->copy($resolved);
534 }
535 }
536 }
2c4c67b6 537 return $new;
c01ab172 538}
539
8091aa91 540=head2 store_column
7624b19f 541
542 $obj->store_column($col => $val);
543
8091aa91 544Sets a column value without marking it as dirty.
7624b19f 545
546=cut
547
548sub store_column {
549 my ($self, $column, $value) = @_;
75d07914 550 $self->throw_exception( "No such column '${column}'" )
d7156e50 551 unless exists $self->{_column_data}{$column} || $self->has_column($column);
75d07914 552 $self->throw_exception( "set_column called for ${column} without value" )
7624b19f 553 if @_ < 3;
554 return $self->{_column_data}{$column} = $value;
555}
556
b52e9bf8 557=head2 inflate_result
558
c01ab172 559 Class->inflate_result($result_source, \%me, \%prefetch?)
b52e9bf8 560
561Called by ResultSet to inflate a result from storage
562
563=cut
564
565sub inflate_result {
c01ab172 566 my ($class, $source, $me, $prefetch) = @_;
aec3eff1 567
568 my ($source_handle) = $source;
569
570 if ($source->isa('DBIx::Class::ResultSourceHandle')) {
571 $source = $source_handle->resolve
572 } else {
573 $source_handle = $source->handle
574 }
575
04786a4c 576 my $new = {
aec3eff1 577 _source_handle => $source_handle,
04786a4c 578 _column_data => $me,
579 _in_storage => 1
580 };
581 bless $new, (ref $class || $class);
582
7fb16f1a 583 my $schema;
64acc2bc 584 foreach my $pre (keys %{$prefetch||{}}) {
585 my $pre_val = $prefetch->{$pre};
f9cc31dd 586 my $pre_source = $source->related_source($pre);
a86b1efe 587 $class->throw_exception("Can't prefetch non-existent relationship ${pre}")
588 unless $pre_source;
0f66a01b 589 if (ref($pre_val->[0]) eq 'ARRAY') { # multi
a86b1efe 590 my @pre_objects;
591 foreach my $pre_rec (@$pre_val) {
75d07914 592 unless ($pre_source->primary_columns == grep { exists $pre_rec->[0]{$_}
5a5bec6c 593 and defined $pre_rec->[0]{$_} } $pre_source->primary_columns) {
a86b1efe 594 next;
595 }
596 push(@pre_objects, $pre_source->result_class->inflate_result(
597 $pre_source, @{$pre_rec}));
598 }
599 $new->related_resultset($pre)->set_cache(\@pre_objects);
62e87ea8 600 } elsif (defined $pre_val->[0]) {
a86b1efe 601 my $fetched;
75d07914 602 unless ($pre_source->primary_columns == grep { exists $pre_val->[0]{$_}
a86b1efe 603 and !defined $pre_val->[0]{$_} } $pre_source->primary_columns)
604 {
605 $fetched = $pre_source->result_class->inflate_result(
75d07914 606 $pre_source, @{$pre_val});
a86b1efe 607 }
9809a6df 608 $new->related_resultset($pre)->set_cache([ $fetched ]);
a86b1efe 609 my $accessor = $source->relationship_info($pre)->{attrs}{accessor};
610 $class->throw_exception("No accessor for prefetched $pre")
611 unless defined $accessor;
612 if ($accessor eq 'single') {
613 $new->{_relationship_data}{$pre} = $fetched;
614 } elsif ($accessor eq 'filter') {
615 $new->{_inflated_column}{$pre} = $fetched;
616 } else {
617 $class->throw_exception("Prefetch not supported with accessor '$accessor'");
618 }
b52e9bf8 619 }
620 }
7624b19f 621 return $new;
622}
623
9b465d00 624=head2 update_or_insert
7624b19f 625
9b465d00 626 $obj->update_or_insert
7624b19f 627
8091aa91 628Updates the object if it's already in the db, else inserts it.
7624b19f 629
9b83fccd 630=head2 insert_or_update
631
632 $obj->insert_or_update
633
634Alias for L</update_or_insert>
635
7624b19f 636=cut
637
9b465d00 638*insert_or_update = \&update_or_insert;
639sub update_or_insert {
7624b19f 640 my $self = shift;
641 return ($self->in_storage ? $self->update : $self->insert);
642}
643
8091aa91 644=head2 is_changed
7624b19f 645
228dbcb4 646 my @changed_col_names = $obj->is_changed();
647 if ($obj->is_changed()) { ... }
7624b19f 648
9b83fccd 649In array context returns a list of columns with uncommited changes, or
650in scalar context returns a true value if there are uncommitted
651changes.
652
7624b19f 653=cut
654
655sub is_changed {
656 return keys %{shift->{_dirty_columns} || {}};
657}
228dbcb4 658
659=head2 is_column_changed
660
661 if ($obj->is_column_changed('col')) { ... }
662
9b83fccd 663Returns a true value if the column has uncommitted changes.
664
228dbcb4 665=cut
666
667sub is_column_changed {
668 my( $self, $col ) = @_;
669 return exists $self->{_dirty_columns}->{$col};
670}
7624b19f 671
097d3227 672=head2 result_source
673
9b83fccd 674 my $resultsource = $object->result_source;
097d3227 675
9b83fccd 676Accessor to the ResultSource this object was created from
87c4e602 677
aec3eff1 678=cut
679
680sub result_source {
681 my $self = shift;
682
683 if (@_) {
684 $self->_source_handle($_[0]->handle);
685 } else {
686 $self->_source_handle->resolve;
687 }
688}
689
9b83fccd 690=head2 register_column
27f01d1f 691
9b83fccd 692 $column_info = { .... };
693 $class->register_column($column_name, $column_info);
27f01d1f 694
9b83fccd 695Registers a column on the class. If the column_info has an 'accessor'
696key, creates an accessor named after the value if defined; if there is
697no such key, creates an accessor with the same name as the column
1f23a877 698
9b83fccd 699The column_info attributes are described in
700L<DBIx::Class::ResultSource/add_columns>
1f23a877 701
097d3227 702=cut
703
1f23a877 704sub register_column {
705 my ($class, $col, $info) = @_;
91b0fbd7 706 my $acc = $col;
707 if (exists $info->{accessor}) {
708 return unless defined $info->{accessor};
709 $acc = [ $info->{accessor}, $col ];
710 }
711 $class->mk_group_accessors('column' => $acc);
1f23a877 712}
713
701da8c4 714
5160b401 715=head2 throw_exception
701da8c4 716
717See Schema's throw_exception.
718
719=cut
720
721sub throw_exception {
722 my $self=shift;
66cab05c 723 if (ref $self && ref $self->result_source && $self->result_source->schema) {
701da8c4 724 $self->result_source->schema->throw_exception(@_);
725 } else {
726 croak(@_);
727 }
728}
729
7624b19f 7301;
731
7624b19f 732=head1 AUTHORS
733
daec44b8 734Matt S. Trout <mst@shadowcatsystems.co.uk>
7624b19f 735
736=head1 LICENSE
737
738You may distribute this code under the same terms as Perl itself.
739
740=cut