Skip to content
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

de-serialization support? #2

Open
jrochkind opened this issue Feb 10, 2018 · 3 comments
Open

de-serialization support? #2

jrochkind opened this issue Feb 10, 2018 · 3 comments

Comments

@jrochkind
Copy link

Is there any way to turn a serialized data structure back into it's original?

@jgaskins
Copy link
Owner

Not yet. I would absolutely love to have it, it was part of the plan from the beginning, but it requires knowledge of two things that I haven't determined how to codify:

  • how the object assigns attributes
  • if the attributes were also made serializable, how to get them back into their previous state

If we have an OrderSerializer, we may not be able to just do something like Order.new(serializable_hash). We have to have some sort of API in place to tell it to ignore, transform, and infer values for attributes. For example:

  • ignore customer_name since it represents denormalized data from another model that isn't settable on the Order
  • transform a serialized delivery_address string or hash into a first-class DeliveryAddress object, as it was before serialization
  • infer line_items from a line_item_ids attribute by fetching line-item rows from the DB

What I usually do is define a deserialize class method. It lets me specify exactly how to do all of these:

class OrderSerializer < Primalize::Single
  def self.deserialize_json(string)
    deserialize JSON.parse(string, symbolize_names: true)
  end

  def self.deserialize(customer_name:, delivery_address:, line_item_ids:, **attrs)
    Order.new(
      **attrs,
      delivery_address: DeliveryAddress.from_string(delivery_address),
      line_items: LineItem.find(line_item_ids),
    )
  end
end

(except I usually use evolve instead of deserialize as a play on the name of the gem)

@jrochkind
Copy link
Author

jrochkind commented Feb 11, 2018

Okay, thanks for response, makes sense.

I was struck by how similar the tasks here are in some ways to what I dealt with in my experimental json_attribute gem. That gem is focused on serializing models to json for the purpose of storing them in a postgres json column, and getting them back. The API ends up being similar, except I base it on ActiveModel::Type stuff, since I was trying to stay close to ActiveRecord but with attributes in JSON. (For that matter, dry-struct also has somewhat similar 'domain' and APIs, but also, I think, is "one way". Several of us seem to be approaching similar things. )

My json_attribute experiment enforces only serializing multi-value instances that have a constructor that take the serialized hash as an initializer, to get around the "how do we know how to restore this" problem. Actually beyond that, at the moment it enforces include'ing a certain module.

@jgaskins
Copy link
Owner

Funny you mention dry-struct, solnic (not @-mentioning him so I don't opt him into this thread) told me a while back that this is kinda what dry-struct does, but it looks like dry-struct is more flexible and, possibly as a result, a fair bit more verbose. This isn't a big deal, but I feel like Rails has trained the Ruby developer community to write things with as few keystrokes as possible.

It'd probably be interesting to see primalize implemented in terms of dry-struct, tbh. I bet we could translate …

attributes(
  name: optional(string),
  age: integer,
)

… into their example code …

attribute :name, Types::String.optional
attribute :age, Types::Int

json_attribute looks interesting, too. The idea of mapping attributes at the model level onto JSONB keys is pretty slick. I've had to migrate attributes from a JSONB hash to first-class columns a few times and that would've made it so much easier. :-)

(Btw, so many names are taken... what should I call this gem?)

This is hilarious. I settled on primalize because I couldn't figure out a way to talk about serialization that wasn't either taken or terrible. Fun fact: the runner-up name choice for this gem was corn_flakes because of "cerealization".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants