Reuse recursive ref-transformers#1250
Conversation
8568dfe to
bed14af
Compare
|
Hi @opqdonut, this seems to be ready to merge, what's the process to make that happen? |
This is a temporary fix until metosin/malli#1250 gets merged into Malli.
This is a temporary fix until metosin/malli#1250 gets merged into Malli.
This is a temporary fix until metosin/malli#1250 gets merged into Malli.
This is a temporary fix until metosin/malli#1250 gets merged into Malli.
…67742) This is a temporary fix until metosin/malli#1250 gets merged into Malli. Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
…67743) This is a temporary fix until metosin/malli#1250 gets merged into Malli.
|
I'll try to have time to review this this friday. Feedback from @frenchy64 would be welcome as well, since he's thought a lot about this topic. |
frenchy64
left a comment
There was a problem hiding this comment.
This looks good, and should work with lazy and eager refs.
There might be further optimization opportunities for eager refs. For those, I think we wouldn't need -memoize or extra thunks, we can just create the transformer eagerly. If you want to investigate that, we should be able to contain the difference to a single branch like the if lazy test in the validator.
| (let [key [(-identify-ref-schema this) method]] | ||
| (or (some-> (get-in options [::ref-transformer-cache key]) clojure.core/deref) | ||
| (let [knot (atom nil) | ||
| this-transformer (-value-transformer transformer this method options) |
There was a problem hiding this comment.
This looks like a testing point. Could you add a unit test that counts how many times -value-transformer is called for a custom transformer that records this info? Then call the transformer and ensure the number is constant no matter the depth of the input?
There was a problem hiding this comment.
I've just shamelessly stolen your test case from #1254 for this, it is accurate down to comments 😄. Hope it's OK.
| (let [this-transformer (-value-transformer transformer this method options) | ||
| deref-transformer (-memoize (fn [] (-transformer (rf) transformer method options)))] | ||
| (-intercepting this-transformer (fn [x] (if-some [t (deref-transformer)] (t x) x))))) | ||
| (let [key [(-identify-ref-schema this) method]] |
There was a problem hiding this comment.
Here we don't include transformer (I assume) because it's constant as we recur. Is that also true of method?
There was a problem hiding this comment.
Good point. I'm not sure if the transformer can be changed mid-flight in the call chain. If it can, then it is possible to include transformer into the cache key too – it won't be expensive because most (all) of the time the transformers will be pointer-equal.
bed14af to
a9599e3
Compare
|
Added the test you've requested. I'm not sure if this is still relevant after the discussions on Slack and in:
However, this approach seems complexity-cheap and still brings decent benefit in the absence of a more holistic solution. |
|
@frenchy64 Do you think it makes sense to merge this or are you working on something that will have the same effect? |
|
This PR is still relevant, I'll take a final look over and leave a review. Maybe there's a better approach but this seems like a great starting point, especially with a test. |
…7733) This is a temporary fix until metosin/malli#1250 gets merged into Malli.
This addresses a similar problem to #1245 but this time for transformers, not validators. The issue was discovered very recently in Metabase, where a decoder for a recursive schema definiton would grow infinitely, depending on the provided data (and from the look of it, the growth is quadratic). Here's a simplified reproducer:
The solution is similar and inspired by @frenchy64's #1245, however, here I had the luxury of
optionsmap and so could avoid dynvar shenanigans. However, I would still need feedback on whether this approach is valid. Anyway, after the patch: