It doesn’t work because you’re using SQLite, something about that adapter is causing the type error and I’m not certain why. The example does work with PostgreSQL.
Here’s another way you might approach it:
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'sqlite3'
gem 'rom-sql'
gem 'dry-core'
gem 'dry-auto_inject'
gem 'pry'
end
require 'rom'
require 'rom/sql'
rom_config = ROM::Configuration.new(:sql, 'sqlite::memory')
gateway = rom_config.default_gateway
migration = gateway.migration do
change do
create_table :items do
primary_key :id
column :tags, 'text', null: false
end
end
end
migration.apply(gateway.connection, :up)
module Structs
class Item < ROM::Struct
def tags
@tags ||= JSON.parse(attributes[:tags])
end
end
end
class Items < ROM::Relation[:sql]
Tags = Types.define(Types::String) do
input { |tags| ::JSON.dump(Array(tags)) }
output { |json| json }
end
schema :items, infer: true do
attribute :tags, Tags
end
end
rom_config.register_relation(Items)
container = Dry::Core::Container.new
container.register("persistence.rom", ROM.container(rom_config))
Deps = Dry::AutoInject(container)
class Repository < ROM::Repository::Root
include Deps[container: "persistence.rom"]
def find(id) = root.by_pk(id).one
end
class ItemRepo < Repository[:items]
struct_namespace Structs
commands :create, update: :by_pk, delete: :by_pk
end
repo = ItemRepo.new
Pry.start(self)
[1] pry(main)> item = repo.create(tags: %w[foo bar])
=> #<Structs::Item tags="[\"foo\",\"bar\"]" id=1>
[2] pry(main)> item.tags
=> ["foo", "bar"]
[3] pry(main)> item = repo.update(item.id, tags: item.tags + ['baz'])
=> #<Structs::Item tags="[\"foo\",\"bar\",\"baz\"]" id=1>
[4] pry(main)> item.tags
=> ["foo", "bar", "baz"]