-
Notifications
You must be signed in to change notification settings - Fork 150
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Scalar::Defer support as column name #98
Conversation
|
Hi! I need to understand your failure case before I can say anything about the patch. Please show me how exactly are you using Scalar::Defer within a search() for this to bite you. Thanks! |
|
Well I'm using it to work with joins in dbix-class, looks like this: xjoin_column_alias returns object from Scalar::Defer, so it basically boils down to: Does it make any sense? |
|
I now understand what your problem is. It's not that the thing doesn't work, but that you get defer() called too many times. For starters the proposed fix is a no-go: the codebase in general goes to great lengths to not treat The more fundamental problem is that While it is possible to get things to work in the long run (with a ton of work), a small one-off patch like what is proposed in this PR is certainly off the table. Could you describe the actual problem you are trying to solve? Perhaps there is a better way forward without using (the clearly not working OOB) |
|
Ok I understand logic behind boolean context. As for SQL::Abstract
doesn't seem like an issue, defer will return same result over and over,
"lazy" can be used too.
Main goal was to solve issues with joins. I use chained resultsets a
lot, and they often go into ResultSet classes as helpers like
"with_tag", "with_parent_tag". Eg. sub with_tag { return shift->search({
"tag.name" => "Something" }, { join => { "parent" => "tag" } }); }. If I
remember correctly second call to with_parent_tag will add "tag_2" as
table, but condition still refer to "tag". There should be a way to know
which alias to use right now, "tag" or "tag_2", just like
$me->current_source_alias for current table (is there one?).
Additionally, if after two with_parent_tag() calls I add "tag" relation
on main object like so: $rs = $rs->search({}, { join => "tag" }), all
previous table aliases will shift, "tag" becomes "tag", "parent.tag"
becomes "tag_2" (was "tag"), and "parent.tag" becomes "tag_3" (was
"tag_2"). (It was some time ago, and I tested it with previous version,
but it's probably same now). I guess they should be sticky.
|
...? I just demonstrated in that oneliner that the thing is evaluated twice, not once.
Right. The correct answer to this is proper
They can't be because the join spec is calculated lazily at the end of a callchain, ensuring proper deduplication can take place (e.g. There is however a separate technique allowing you to sidestep the problem entirely: use correlated subqueries. The concept is more or less the same but it is both less fragile (each subquery is an implicit namespace and clashes can not occur) and more efficient (most optimizers, including MySQL's, recognize that the join does not need to be reified). You can either do this by hand, or use @frioux's helper to achieve the same effect as described in the linked SYNOPSIS. If this doesn't work for you - you will have to give up chaining for the time being, and build the structure separately from DBIC, only feeding it the final monolithic where+join criteria. The tooling is just not up to the task yet. Even though I am closing this PR due to the considerations discussed higher up, feel free to add more thoughts/questions to this ticket if the above does not give you a satisfactory set of answers. Cheers! |
So then using Scalar::Defer (or any other defer module) object as column name in search(), code call ref on it, in case of Scalar::Defer ref eq "0", and if we check length it will be == 1, so condition is false and it falls to "else" condition, which treat defer object as subject for serialize. However, serialize is using Storable::freeze, which has a line "logcroak "not a reference" unless ref($self);" and for defer object that is true, so it croaks.
I also tried to re-bless it into different package, not "0", but it only fails in different place instead. This looks like best solution for me, would be better if there was any certain way of knowing if object can be stringified and use that, but I don't see it yet.