How to serialize/deserialize String to JSON?


#1

I try to have a table with users and meta column which will be a hash serialized to JSON string:

require 'rom-repository'
require 'rom-sql'
require 'dry-struct'

module Relations
  class Users < ROM::Relation[:sql]
    schema :users do
      attribute :meta, Dry::Types['json.hash']
    end

    def by_id(id)
      where(id: id)
    end
  end
end

module Repositories
  class Users < ROM::Repository[:users]
    def [](id)
      users.by_id(id).as(User).one!
    end
  end
end

class User < Dry::Struct
  attribute :meta, Dry::Types['hash'] # Dry::Types['json.hash']
end

container = ROM.container(:sql, 'sqlite:memory') do |config|
  config.register_relation Relations::Users
end

container.gateways[:default].tap do |gateway|
  migration = gateway.migration do
    change do
      create_table :users do
        primary_key :id
        string :name, null: false
        string :meta, null: false, default: '{}'
      end
    end
  end

  migration.apply gateway.connection, :up
end

connection = container.gateways[:default].connection
connection.execute "INSERT INTO users (name, meta) VALUES ('dave', '{admin: true}')"

repo = Repositories::Users.new(container)
p repo.users.as(User).first.meta # returns "{admin: true}", not a Hash

I am not sure which type to use to make it works.


#2

You could use something like this in the schema:

JSONString = Types::String.constructor(&JSON.method(:dump))

And then in your struct something like this:

JSON = Types::Hash.constructor(&:JSON.method(:load))

You could also define a hash schema for your json and use symbolized hash schema ie:

JSON = Types::Hash
  .symbolized(foo: Types::String, bar: Types::Int)
  .constructor(&:JSON.method(:load))