Skip to content

Commit 7293955

Browse files
committed
Promote resolve_relationship_condition to a 1st-class API method
The encapsulated logic is just too complex to try to replicate externally, especially now that everything within DBIC itself uses this method underneath. Patches to the only widely known user (::Resultset::RecursiveUpdate) will follow shortly
1 parent e5c6382 commit 7293955

File tree

7 files changed

+101
-52
lines changed

7 files changed

+101
-52
lines changed

lib/DBIx/Class/Relationship/Accessor.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ sub add_relationship_accessor {
5454
5555
and
5656
57-
$jfc = ( $rsrc->_resolve_relationship_condition(
57+
$jfc = ( $rsrc->resolve_relationship_condition(
5858
rel_name => %1$s,
5959
foreign_alias => %1$s,
6060
self_alias => 'me',

lib/DBIx/Class/Relationship/Base.pm

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -562,9 +562,9 @@ sub related_resultset {
562562
# ->in_storage() is orders of magnitude faster than the Try::Tiny-like
563563
# construct below ( perl's low level tooling is truly shit :/ )
564564
( $self->in_storage or DBIx::Class::_Util::in_internal_try )
565-
? $rsrc->_resolve_relationship_condition($rrc_args)->{join_free_condition}
565+
? $rsrc->resolve_relationship_condition($rrc_args)->{join_free_condition}
566566
: dbic_internal_try {
567-
$rsrc->_resolve_relationship_condition($rrc_args)->{join_free_condition}
567+
$rsrc->resolve_relationship_condition($rrc_args)->{join_free_condition}
568568
}
569569
dbic_internal_catch {
570570
$unique_carper->(
@@ -729,7 +729,7 @@ sub new_related {
729729
### context-specific call-site it made no sense to expose it to end users.
730730
###
731731

732-
my $rel_resolution = $rsrc->_resolve_relationship_condition (
732+
my $rel_resolution = $rsrc->resolve_relationship_condition (
733733
rel_name => $rel,
734734
self_result_object => $self,
735735

@@ -947,7 +947,7 @@ L<update|DBIx::Class::Row/update> to update them in the storage.
947947
sub set_from_related {
948948
my ($self, $rel, $f_obj) = @_;
949949

950-
$self->set_columns( $self->result_source->_resolve_relationship_condition (
950+
$self->set_columns( $self->result_source->resolve_relationship_condition (
951951
require_join_free_values => 1,
952952
rel_name => $rel,
953953
foreign_values => (

lib/DBIx/Class/ResultSet.pm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,7 @@ sub find {
835835
$call_cond = {
836836
%$call_cond,
837837

838-
%{ $rsrc->_resolve_relationship_condition(
838+
%{ $rsrc->resolve_relationship_condition(
839839
require_join_free_values => 1,
840840
rel_name => $key,
841841
foreign_values => (
@@ -2531,7 +2531,7 @@ sub populate {
25312531

25322532
$colinfo->{$rel}{rs} = $rsrc->related_source($rel)->resultset;
25332533

2534-
$colinfo->{$rel}{fk_map} = { reverse %{ $rsrc->_resolve_relationship_condition(
2534+
$colinfo->{$rel}{fk_map} = { reverse %{ $rsrc->resolve_relationship_condition(
25352535
rel_name => $rel,
25362536

25372537
# an API where these are optional would be too cumbersome,

lib/DBIx/Class/ResultSource.pm

Lines changed: 90 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,7 +1832,7 @@ sub reverse_relationship_info {
18321832
# Some custom rels may not resolve without a $schema
18331833
#
18341834
my $our_resolved_relcond = dbic_internal_try {
1835-
$self->_resolve_relationship_condition(
1835+
$self->resolve_relationship_condition(
18361836
rel_name => $rel,
18371837

18381838
# an API where these are optional would be too cumbersome,
@@ -1898,7 +1898,7 @@ sub reverse_relationship_info {
18981898
and
18991899

19001900
my $their_resolved_relcond = dbic_internal_try {
1901-
$other_rsrc->_resolve_relationship_condition(
1901+
$other_rsrc->resolve_relationship_condition(
19021902
rel_name => $other_rel,
19031903

19041904
# an API where these are optional would be too cumbersome,
@@ -2096,7 +2096,7 @@ sub _resolve_join {
20962096
-alias => $as,
20972097
-relation_chain_depth => ( $seen->{-relation_chain_depth} || 0 ) + 1,
20982098
},
2099-
$self->_resolve_relationship_condition(
2099+
$self->resolve_relationship_condition(
21002100
rel_name => $join,
21012101
self_alias => $alias,
21022102
foreign_alias => $as,
@@ -2169,18 +2169,29 @@ sub _compare_relationship_keys :DBIC_method_is_indirect_sugar {
21692169
bag_eq( $_[1], $_[2] );
21702170
}
21712171

2172-
sub resolve_condition {
2173-
carp 'resolve_condition is a private method, stop calling it';
2172+
sub _resolve_relationship_condition :DBIC_method_is_indirect_sugar {
2173+
DBIx::Class::_ENV_::ASSERT_NO_INTERNAL_INDIRECT_CALLS and fail_on_internal_call;
2174+
2175+
# carp() - has been on CPAN for less than 2 years
2176+
carp '_resolve_relationship_condition() is deprecated - see resolve_relationship_condition() instead';
2177+
2178+
shift->resolve_relationship_condition(@_);
2179+
}
2180+
2181+
sub resolve_condition :DBIC_method_is_indirect_sugar {
2182+
DBIx::Class::_ENV_::ASSERT_NO_INTERNAL_INDIRECT_CALLS and fail_on_internal_call;
2183+
2184+
# carp() - has been discouraged forever
2185+
carp 'resolve_condition() is deprecated - see resolve_relationship_condition() instead';
2186+
21742187
shift->_resolve_condition (@_);
21752188
}
21762189

2177-
sub _resolve_condition {
2178-
# carp_unique sprintf
2179-
# '_resolve_condition is a private method, and moreover is about to go '
2180-
# . 'away. Please contact the development team at %s if you believe you '
2181-
# . 'have a genuine use for this method, in order to discuss alternatives.',
2182-
# DBIx::Class::_ENV_::HELP_URL,
2183-
# ;
2190+
sub _resolve_condition :DBIC_method_is_indirect_sugar {
2191+
DBIx::Class::_ENV_::ASSERT_NO_INTERNAL_INDIRECT_CALLS and fail_on_internal_call;
2192+
2193+
# carp_unique() - the interface replacing it only became reality in Sep 2016
2194+
carp_unique '_resolve_condition() is deprecated - see resolve_relationship_condition() instead';
21842195

21852196
#######################
21862197
### API Design? What's that...? (a backwards compatible shim, kill me now)
@@ -2232,21 +2243,21 @@ sub _resolve_condition {
22322243
};
22332244

22342245
# Allowing passing relconds different than the relationshup itself is cute,
2235-
# but likely dangerous. Remove that from the (still unofficial) API of
2236-
# _resolve_relationship_condition, and instead make it "hard on purpose"
2246+
# but likely dangerous. Remove that from the API of resolve_relationship_condition,
2247+
# and instead make it "hard on purpose"
22372248
local $self->relationship_info( $args->{rel_name} )->{cond} = $cond if defined $cond;
22382249

22392250
#######################
22402251

22412252
# now it's fucking easy isn't it?!
2242-
my $rc = $self->_resolve_relationship_condition( $args );
2253+
my $rc = $self->resolve_relationship_condition( $args );
22432254

22442255
my @res = (
22452256
( $rc->{join_free_condition} || $rc->{condition} ),
22462257
! $rc->{join_free_condition},
22472258
);
22482259

2249-
# _resolve_relationship_condition always returns qualified cols even in the
2260+
# resolve_relationship_condition always returns qualified cols even in the
22502261
# case of join_free_condition, but nothing downstream expects this
22512262
if ($rc->{join_free_condition} and ref $res[0] eq 'HASH') {
22522263
$res[0] = { map
@@ -2268,34 +2279,73 @@ our $UNRESOLVABLE_CONDITION = UNRESOLVABLE_CONDITION;
22682279
# we are moving to a constant
22692280
Internals::SvREADONLY($UNRESOLVABLE_CONDITION => 1);
22702281

2271-
# Resolves the passed condition to a concrete query fragment and extra
2272-
# metadata
2273-
#
2274-
## self-explanatory API, modeled on the custom cond coderef:
2275-
# rel_name => (scalar)
2276-
# foreign_alias => (scalar)
2277-
# foreign_values => (either not supplied or a hashref )
2278-
# self_alias => (scalar)
2279-
# self_result_object => (either not supplied or a result object)
2280-
# require_join_free_condition => (boolean, throws on failure to construct a JF-cond)
2281-
# require_join_free_values => (boolean, throws on failure to return an equality-only JF-cond, implies require_join_free_condition)
2282-
#
2283-
## returns a hash
2284-
# condition => (a valid *likely fully qualified* sqla cond structure)
2285-
# identity_map => (a hashref of foreign-to-self *unqualified* column equality names)
2286-
# identity_map_matches_condition => (boolean, indicates whether the entire condition is expressed in the identity-map)
2287-
# join_free_condition => (a valid *fully qualified* sqla cond structure, maybe unset)
2288-
# join_free_values => (IFF the returned join_free_condition contains only exact values (no expressions)
2289-
# this would be a hashref of identical join_free_condition, except with all column
2290-
# names *unqualified* )
2291-
#
2292-
sub _resolve_relationship_condition {
2282+
=head2 resolve_relationship_condition
2283+
2284+
NOTE: You generally B<SHOULD NOT> need to use this functionality... until you
2285+
do. The API description is terse on purpose. If the text below doesn't make
2286+
sense right away (based on the context which prompted you to look here) it is
2287+
almost certain you are reaching for the wrong tool. Please consider asking for
2288+
advice in any of the support channels before proceeding.
2289+
2290+
=over 4
2291+
2292+
=item Arguments: C<\%args> as shown below (C<B<*>> denotes mandatory args):
2293+
2294+
* rel_name => $string
2295+
2296+
* foreign_alias => $string
2297+
2298+
* self_alias => $string
2299+
2300+
foreign_values => \%column_value_pairs
2301+
2302+
self_result_object => $ResultObject
2303+
2304+
require_join_free_condition => $bool ( results in exception on failure to construct a JF-cond )
2305+
2306+
require_join_free_values => $bool ( results in exception on failure to return an equality-only JF-cond )
2307+
2308+
=item Return Value: C<\%resolution_result> as shown below (C<B<*>> denotes always-resent parts of the result):
2309+
2310+
* condition => $sqla_condition ( always present, valid, *likely* fully qualified, SQL::Abstract-compatible structure )
2311+
2312+
identity_map => \%foreign_to_self_equailty_map ( list of declared-equal foreign/self *unqualified* column names )
2313+
2314+
identity_map_matches_condition => $bool ( indicates whether the entire condition is expressed within the identity_map )
2315+
2316+
join_free_condition => \%sqla_condition_fully_resolvable_via_foreign_table
2317+
( always a hash, all keys guaranteed to be valid *fully qualified* columns )
2318+
2319+
join_free_values => \%unqalified_version_of_join_free_condition
2320+
( IFF the returned join_free_condition contains only exact values (no expressions), this would be
2321+
a hashref identical to join_free_condition, except with all column names *unqualified* )
2322+
2323+
=back
2324+
2325+
This is the low-level method used to convert a declared relationship into
2326+
various parameters consumed by higher level functions. It is provided as a
2327+
stable official API, as the logic it encapsulates grew incredibly complex with
2328+
time. While calling this method directly B<is generally discouraged>, you
2329+
absolutely B<should be using it> in codepaths containing the moral equivalent
2330+
of:
2331+
2332+
...
2333+
if( ref $some_rsrc->relationship_info($somerel)->{cond} eq 'HASH' ) {
2334+
...
2335+
}
2336+
...
2337+
2338+
=cut
2339+
2340+
# TODO - expand the documentation above, too terse
2341+
2342+
sub resolve_relationship_condition {
22932343
my $self = shift;
22942344

22952345
my $args = { ref $_[0] eq 'HASH' ? %{ $_[0] } : @_ };
22962346

22972347
for ( qw( rel_name self_alias foreign_alias ) ) {
2298-
$self->throw_exception("Mandatory argument '$_' to _resolve_relationship_condition() is not a plain string")
2348+
$self->throw_exception("Mandatory argument '$_' to resolve_relationship_condition() is not a plain string")
22992349
if !defined $args->{$_} or length ref $args->{$_};
23002350
}
23012351

@@ -2560,7 +2610,7 @@ sub _resolve_relationship_condition {
25602610
else {
25612611
my @subconds = map {
25622612
local $rel_info->{cond} = $_;
2563-
$self->_resolve_relationship_condition( $args );
2613+
$self->resolve_relationship_condition( $args );
25642614
} @{ $rel_info->{cond} };
25652615

25662616
if( @{ $rel_info->{cond} } == 1 ) {

lib/DBIx/Class/ResultSource/RowParser.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ sub _resolve_collapse {
194194
rsrc => $self->related_source($rel),
195195
fk_map => (
196196
dbic_internal_try {
197-
$self->_resolve_relationship_condition(
197+
$self->resolve_relationship_condition(
198198
rel_name => $rel,
199199

200200
# an API where these are optional would be too cumbersome,

lib/DBIx/Class/Row.pm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1193,7 +1193,7 @@ sub copy {
11931193

11941194
$copied->{$_->ID}++ or $_->copy(
11951195

1196-
$foreign_vals ||= $rsrc->_resolve_relationship_condition(
1196+
$foreign_vals ||= $rsrc->resolve_relationship_condition(
11971197
require_join_free_values => 1,
11981198
rel_name => $rel_name,
11991199
self_result_object => $new,

t/relationship/resolve_relationship_condition.t renamed to xt/extra/diagnostics/invalid_resolve_relationship_condition_arguments.t

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@ use warnings;
66
use Test::More;
77
use Test::Exception;
88

9-
109
use DBICTest;
1110

12-
my $schema = DBICTest->init_schema();
11+
my $schema = DBICTest->init_schema( no_deploy => 1 );
1312

1413
for (
1514
{ year => [1,2] },
@@ -18,7 +17,7 @@ for (
1817
{ -and => [ year => 1, year => 2 ] },
1918
) {
2019
throws_ok {
21-
$schema->source('Track')->_resolve_relationship_condition(
20+
$schema->source('Track')->resolve_relationship_condition(
2221
rel_name => 'cd_cref_cond',
2322
self_alias => 'me',
2423
foreign_alias => 'cd',

0 commit comments

Comments
 (0)