New projects that use rom-db interact with existing db schemas quite often, especially with schemas that are built on top of Rails applications. And you can probably came across to a serialized YAML data here. ActiveRecord provides API to store unstructured key-value data into single database column with serialize method:
# Serialize preferences as Hash using YAML coder.
class User < ActiveRecord::Base
serialize :preferences, Hash
end
With this model definition if you write data as:
User.create(preferences: { locale: 'RU', timezone: 'MSK' }
it produces the following data into database:
id | preferences |
---|---|
1 | ---\n:locale: RU\n:timezone: MSK\n |
Then if you read this data with rom-sql you should use suitable type for the schema attribute. For the first time you'd probably choose a wrong type, because all that you have is a database schema definition:
CREATE TABLE IF NOT EXISTS "users" (
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
"preferences" varchar
);
Column preferences
has type varchar
which in general corresponds to ROM::SQL::Types::String
type. But if you use this type it wouldn't be so useful:
class Users < ROM::Relation[:sql]
schema do
attribute :id, ROM::SQL::Types::Serial
attribute :preferences, ROM::SQL::Types::String
end
end
users.first[:preferences]
# => "---\n:locale: RU\n:timezone: MSK\n"
Of course, ROM knows nothing about YAML and perceives data as a plain text. To deal with this data as a key-value structure we have to define custom type for this attribute:
module Types
include Dry::Types.module
module SQL
YAML = Types::Array | Types::Hash
YAMLRead = YAML.constructor(&::YAML.method(:load))
YAMLAttr = YAML.constructor(&:to_yaml).meta(read: YAMLRead)
end
end
class Users < ROM::Relation[:sql]
schema do
attribute :id, ROM::SQL::Types::Serial
attribute :preferences, ::Types::SQL::YAMLAttr
end
end
users.first[:preferences]
# => { locale: 'RU', timezone: 'MSK' }
There is a way to deal with serialized YAML data with ROM. However, it is much more important to avoid store YAML data into database. YAML is a pretty human-readable format. But it is not intended to be used with a database. Consider using JSON for the same goal. The most popular modern databases such as PostgreSQL, MySQL, MariaDB and others have quiet good enough JSON support.