sub search_rs {
my $self = shift;
- # Special-case handling for (undef, undef).
- if ( @_ == 2 && !defined $_[1] && !defined $_[0] ) {
- @_ = ();
- }
+ my $rsrc = $self->result_source;
+ my ($call_cond, $call_attrs);
- my $call_attrs = {};
- if (@_ > 1) {
- if (ref $_[-1] eq 'HASH') {
- # copy for _normalize_selection
- $call_attrs = { %{ pop @_ } };
- }
- elsif (! defined $_[-1] ) {
- pop @_; # search({}, undef)
+ # Special-case handling for (undef, undef) or (undef)
+ # Note that (foo => undef) is valid deprecated syntax
+ @_ = () if not scalar grep { defined $_ } @_;
+
+ # just a cond
+ if (@_ == 1) {
+ $call_cond = shift;
+ }
+ # fish out attrs in the ($condref, $attr) case
+ elsif (@_ == 2 and ( ! defined $_[0] or (ref $_[0]) ne '') ) {
+ ($call_cond, $call_attrs) = @_;
+ }
+ elsif (@_ % 2) {
+ $self->throw_exception('Odd number of arguments to search')
+ }
+ # legacy search
+ elsif (@_) {
+ carp_unique 'search( %condition ) is deprecated, use search( \%condition ) instead'
+ unless $rsrc->result_class->isa('DBIx::Class::CDBICompat');
+
+ for my $i (0 .. $#_) {
+ next if $i % 2;
+ $self->throw_exception ('All keys in condition key/value pairs must be plain scalars')
+ if (! defined $_[$i] or ref $_[$i] ne '');
}
+
+ $call_cond = { @_ };
}
# see if we can keep the cache (no $rs changes)
$cache = $self->get_cache;
}
- my $rsrc = $self->result_source;
-
my $old_attrs = { %{$self->{attrs}} };
my $old_having = delete $old_attrs->{having};
my $old_where = delete $old_attrs->{where};
my $new_attrs = { %$old_attrs };
# take care of call attrs (only if anything is changing)
- if (keys %$call_attrs) {
+ if ($call_attrs and keys %$call_attrs) {
+
+ # copy for _normalize_selection
+ $call_attrs = { %$call_attrs };
my @selector_attrs = qw/select as columns cols +select +as +columns include_columns/;
}
- # rip apart the rest of @_, parse a condition
- my $call_cond = do {
-
- if (ref $_[0] eq 'HASH') {
- (keys %{$_[0]}) ? $_[0] : undef
- }
- elsif (@_ == 1) {
- $_[0]
- }
- elsif (@_ % 2) {
- $self->throw_exception('Odd number of arguments to search')
- }
- else {
- +{ @_ }
- }
-
- } if @_;
-
- if( @_ > 1 and ! $rsrc->result_class->isa('DBIx::Class::CDBICompat') ) {
- carp_unique 'search( %condition ) is deprecated, use search( \%condition ) instead';
- }
-
for ($old_where, $call_cond) {
if (defined $_) {
$new_attrs->{where} = $self->_stack_cond (
=cut
sub cursor {
- my ($self) = @_;
-
- my $attrs = $self->_resolved_attrs_copy;
+ my $self = shift;
- return $self->{cursor}
- ||= $self->result_source->storage->select($attrs->{from}, $attrs->{select},
- $attrs->{where},$attrs);
+ return $self->{cursor} ||= do {
+ my $attrs = { %{$self->_resolved_attrs } };
+ $self->result_source->storage->select(
+ $attrs->{from}, $attrs->{select}, $attrs->{where}, $attrs
+ );
+ };
}
=head2 single
$self->throw_exception('single() only takes search conditions, no attributes. You want ->search( $cond, $attrs )->single()');
}
- my $attrs = $self->_resolved_attrs_copy;
+ my $attrs = { %{$self->_resolved_attrs} };
if (keys %{$attrs->{collapse}}) {
$self->throw_exception(
return $self->search(@_)->count if @_ and defined $_[0];
return scalar @{ $self->get_cache } if $self->get_cache;
- my $attrs = $self->_resolved_attrs_copy;
+ my $attrs = { %{ $self->_resolved_attrs } };
# this is a little optimization - it is faster to do the limit
# adjustments in software, instead of a subquery
sub reset {
my ($self) = @_;
- delete $self->{_attrs} if exists $self->{_attrs};
$self->{all_cache_position} = 0;
$self->cursor->reset;
return $self;
);
}
elsif ($storage->_use_multicolumn_in) {
- # This is hideously ugly, but SQLA does not understand multicol IN expressions
- my $sql_maker = $storage->sql_maker;
- my ($sql, @bind) = @${$subrs->as_query};
- $sql = sprintf ('(%s) IN %s', # the as_query already comes with a set of parenthesis
- join (', ', map { $sql_maker->_quote ($_) } @$idcols),
- $sql,
- );
-
return $storage->$op (
$rsrc,
$op eq 'update' ? $values : (),
- \[$sql, @bind],
+ # no syntax for calling this properly yet
+ # !!! EXPERIMENTAL API !!! WILL CHANGE !!!
+ $storage->sql_maker->_where_op_multicolumn_in (
+ $idcols, # how do I convey a list of idents...? can binds reside on lhs?
+ $subrs->as_query
+ ),
);
}
else {
=over 4
-=item Arguments: \@data;
+=item Arguments: [ \@column_list, \@row_values+ ] | [ \%col_data+ ]
+
+=item Return Value: L<\@result_objects|DBIx::Class::Manual::ResultClass> (scalar context) | L<@result_objects|DBIx::Class::Manual::ResultClass> (list context)
=back
-Accepts either an arrayref of hashrefs or alternatively an arrayref of arrayrefs.
-For the arrayref of hashrefs style each hashref should be a structure suitable
-for submitting to a $resultset->create(...) method.
+Accepts either an arrayref of hashrefs or alternatively an arrayref of
+arrayrefs.
+
+=over
+
+=item NOTE
+
+The context of this method call has an important effect on what is
+submitted to storage. In void context data is fed directly to fastpath
+insertion routines provided by the underlying storage (most often
+L<DBI/execute_for_fetch>), bypassing the L<new|DBIx::Class::Row/new> and
+L<insert|DBIx::Class::Row/insert> calls on the
+L<Result|DBIx::Class::Manual::ResultClass> class, including any
+augmentation of these methods provided by components. For example if you
+are using something like L<DBIx::Class::UUIDColumns> to create primary
+keys for you, you will find that your PKs are empty. In this case you
+will have to explicitly force scalar or list context in order to create
+those values.
-In void context, C<insert_bulk> in L<DBIx::Class::Storage::DBI> is used
-to insert the data, as this is a faster method.
+=back
-Otherwise, each set of data is inserted into the database using
-L<DBIx::Class::ResultSet/create>, and the resulting objects are
-accumulated into an array. The array itself, or an array reference
-is returned depending on scalar or list context.
+In non-void (scalar or list) context, this method is simply a wrapper
+for L</create>. Depending on list or scalar context either a list of
+L<Result|DBIx::Class::Manual::ResultClass> objects or an arrayref
+containing these objects is returned.
-Example: Assuming an Artist Class that has many CDs Classes relating:
+When supplying data in "arrayref of arrayrefs" invocation style, the
+first element should be a list of column names and each subsequent
+element should be a data value in the earlier specified column order.
+For example:
- my $Artist_rs = $schema->resultset("Artist");
+ $Arstist_rs->populate([
+ [ qw( artistid name ) ],
+ [ 100, 'A Formally Unknown Singer' ],
+ [ 101, 'A singer that jumped the shark two albums ago' ],
+ [ 102, 'An actually cool singer' ],
+ ]);
- ## Void Context Example
- $Artist_rs->populate([
+For the arrayref of hashrefs style each hashref should be a structure
+suitable for passing to L</create>. Multi-create is also permitted with
+this syntax.
+
+ $schema->resultset("Artist")->populate([
{ artistid => 4, name => 'Manufactured Crap', cds => [
{ title => 'My First CD', year => 2006 },
{ title => 'Yet More Tweeny-Pop crap', year => 2007 },
},
]);
- ## Array Context Example
- my ($ArtistOne, $ArtistTwo, $ArtistThree) = $Artist_rs->populate([
- { name => "Artist One"},
- { name => "Artist Two"},
- { name => "Artist Three", cds=> [
- { title => "First CD", year => 2007},
- { title => "Second CD", year => 2008},
- ]}
- ]);
-
- print $ArtistOne->name; ## response is 'Artist One'
- print $ArtistThree->cds->count ## reponse is '2'
-
-For the arrayref of arrayrefs style, the first element should be a list of the
-fieldsnames to which the remaining elements are rows being inserted. For
-example:
-
- $Arstist_rs->populate([
- [qw/artistid name/],
- [100, 'A Formally Unknown Singer'],
- [101, 'A singer that jumped the shark two albums ago'],
- [102, 'An actually cool singer'],
- ]);
-
-Please note an important effect on your data when choosing between void and
-wantarray context. Since void context goes straight to C<insert_bulk> in
-L<DBIx::Class::Storage::DBI> this will skip any component that is overriding
-C<insert>. So if you are using something like L<DBIx-Class-UUIDColumns> to
-create primary keys for you, you will find that your PKs are empty. In this
-case you will have to use the wantarray context in order to create those
-values.
+If you attempt a void-context multi-create as in the example above (each
+Artist also has the related list of CDs), and B<do not> supply the
+necessary autoinc foreign key information, this method will proxy to the
+less efficient L</create>, and then throw the Result objects away. In this
+case there are obviously no benefits to using this method over L</create>.
=cut
return unless @$data;
if(defined wantarray) {
- my @created;
- foreach my $item (@$data) {
- push(@created, $self->create($item));
- }
+ my @created = map { $self->create($_) } @$data;
return wantarray ? @created : \@created;
}
else {
## inherit the data locked in the conditions of the resultset
my ($rs_data) = $self->_merge_with_rscond({});
delete @{$rs_data}{@columns};
- my @inherit_cols = keys %$rs_data;
- my @inherit_data = values %$rs_data;
## do bulk insert on current row
$rsrc->storage->insert_bulk(
$rsrc,
- [@columns, @inherit_cols],
- [ map { [ @$_{@columns}, @inherit_data ] } @$data ],
+ [@columns, keys %$rs_data],
+ [ map { [ @$_{@columns}, values %$rs_data ] } @$data ],
);
## do the has_many relationships
sub as_query {
my $self = shift;
- my $attrs = $self->_resolved_attrs_copy;
+ my $attrs = { %{ $self->_resolved_attrs } };
# For future use:
#
=cut
sub current_source_alias {
- my ($self) = @_;
-
- return ($self->{attrs} || {})->{alias} || 'me';
+ return (shift->{attrs} || {})->{alias} || 'me';
}
=head2 as_subselect_rs
return {%$attrs, from => $from, seen_join => $seen};
}
-# too many times we have to do $attrs = { %{$self->_resolved_attrs} }
-sub _resolved_attrs_copy {
- my $self = shift;
- return { %{$self->_resolved_attrs (@_)} };
-}
-
sub _resolved_attrs {
my $self = shift;
return $self->{_attrs} if $self->{_attrs};