Use recursive: true for encoding ActiveRecord objects#14
Conversation
recursive: true for encoding ActiveRecord objects
9ff2617 to
2a96004
Compare
|
|
||
| codec = Paquito::CodecFactory.build([ActiveRecord::Base]) | ||
| codec = Paquito::CodecFactory.build([ | ||
| ActiveRecord::Base, Symbol, Time, DateTime, Date, BigDecimal, ActiveSupport::TimeWithZone, |
There was a problem hiding this comment.
This is easy to miss: previously ActiveRecordPacker contained all the necessary types to encode a record, but now since the codec is recursively applying itself it needs to have those types itself.
I think this makes sense but the failure mode here (silent failure?) seems bad.
There was a problem hiding this comment.
I think in "recursive mode" .build([ActiveRecord::Base]) should append the other necessary types.
The problem is that it then allows you to use these types even outside of a record.
There was a problem hiding this comment.
The problem is that it then allows you to use these types even outside of a record.
Yeah exactly.
There was a problem hiding this comment.
Ok so I was wrong and you were indeed correct, the payload does not change, but the change here (requiring all types in the parent codec) is an API change if nothing else. Not sure what we should do about this one.
There was a problem hiding this comment.
We could have something like "dependent types" , so if you try to call Paquito::Types.register with ActiveRecordCoder but without the other types it needs, it would raise or at least warn that it needs those types.
There was a problem hiding this comment.
Alternatively we could keep the "manual nesting". It's unclear what we gain by using recursive here.
There was a problem hiding this comment.
It's unclear what we gain by using
recursivehere.
We get rid of all of ActiveRecordPacker, that seems significant no?
There was a problem hiding this comment.
It's not that much code, and it allow for better error messages. I'm not 100% against, but just saying the win isn't that clear to me.
There was a problem hiding this comment.
I quite like that it leverages a feature (recursive) that suits the use case very closely. The only downside I see is that the type here has implicit dependencies, but cutting 50 lines of code seems like a win. Agree about error messages but maybe we can find another way to do that 🤔
There was a problem hiding this comment.
Ok I tried adding a simple implementation of dependent types. I'm not sure if I like it. There are many cases where you don't actually need all the types, but are required to declare them anyway.
|
The Ruby head failures don't seem related to this PR. |
Are you sure it's not? The format should be the same. It would be worth trying at least. #7 was backward compatible for instance. But if somehow we can't preserve backward compatibility, then we can't delete the old coder. |
Hmm, I can easily check this with a test with a hard-coded payload. Let me try that. |
|
Confirmed, doesn't work. There's a difference because in the recursive case, there is no messagepack "wrapper", whereas in the case with a separate coder there is. I forget the exact difference of bytes but it's small but important (I looked into this way back when...) Cherry-pick that last commit onto master to confirm it works with the current coded + |
|
Maybe I should make a separate PR with the hard-coded payload test so we can first merge that. Then we're sure what's changing here and we'll have a trace (and also avoid any backwards-incompatible changes in the future). |
Yes, absolutely. |
| assert_equal(shop, codec.load(reencoded_value)) | ||
| end | ||
|
|
||
| test "preserves previous encoding scheme" do |
There was a problem hiding this comment.
You also want to test dumping the value produce the same payload.
662f07c to
ad1e557
Compare
ad1e557 to
59ef6d1
Compare
7f4618c to
31e2d14
Compare
55062d6 to
c8d61a2
Compare
|
|
a9427c7 to
7d173ef
Compare
|
Ok, seems I was wrong! I just hadn't passed all the necessary types to the codec in the new test, which I've now done. This now passes with the same payload. I've removed |
|
I just realized we never merged this, I probably missed a notification and never did the last round of review :/ |
2632a22 to
bb7d1a2
Compare
| packer: ->(value, packer) { packer.write(ActiveRecordCoder.dump(value)) }, | ||
| unpacker: ->(unpacker) { ActiveRecordCoder.load(unpacker.read) }, | ||
| recursive: true, | ||
| dependent_types: ["Symbol", "Time", "DateTime", "Date", "BigDecimal", "ActiveSupport::TimeWithZone"], |
There was a problem hiding this comment.
I feel like this is may be overkill.
cab95a3 to
9bd62a7
Compare
|
@byroot @shioyama are either of y'all still interested in this? I noticed that I think a "simpler" solution could be to have the factory always call |
I don't have short term interest in Paquito. Perhaps in the future, dunno.
The MessagePack pool is designed so that if all pooled factories are in use, it fallback to use an ephemeral one. So even a pool of size 1 help if you use multiple threads. Also not all thread always use msgpack at the same time. That being said, IIRC the pool adds overhead too, so it's not always a win on small payloads, kinda depends. |
|
@hmcguire-shopify I'm not working in anything related to pacquito now, probably not in the near-term future. This seemed like a sensible thing at the time, but as I recall it wasn't really a win. Happy to close if we're not going to merge it. |
When we originally created
ActiveRecordCoder, msgpack had norecursiveoption so we created another coder (ActiveRecordPacker) to pack the record data returned fromActiveRecordCoder(and vice versa).Now that there is a recursive option, it seems we shouldn't need to do this and just set
recursive: true.|Obviously this is not backwards compatible.~ (Never mind!)
For cached data we'd just need to clear the cache, for persisted data this would be problematic, but then nobody's serializing records to the database anyway so that should be fineAlso, as noted in a comment, previously
ActiveRecordPackercontained all types necessary to pack a record, whereas now the codec uses itself, therefore if it doesn't have the required types then things go wrong. This is also not backward-compatible, and we might want to issue a warning of some kind in case those types are missing (though I'm not sure where that would go).