require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'dry-types'
gem 'rom'
gem 'rom-sql'
gem 'sqlite3'
end
module Marv
module Girt
module Entities
Types = Dry.Types() # Note sure how to use ROM::Struct here?
module Enums
ALERT_TYPE = Types::Symbol.enum(
SMS: 1,
EMAIL: 2,
)
end
end
end
end
module Marv
module Girt
module Entities
class Base < ROM::Struct
include Enums
transform_keys(&:to_sym)
schema(schema.strict)
end
end
end
end
module Marv
module Girt
module Entities
# It is instantiating this User object, but not using these attributes for validation
class User < Base
attribute(:id, Types::Integer)
attribute(:name, Types::String)
attribute(:email, Types::String.optional)
# Not sure how to get this to validate?
attribute(:alert_type, ALERT_TYPE)
end
end
end
end
rom = ROM.container(:sql, 'sqlite::memory') do |conf|
conf.default.create_table(:users) do
primary_key :id
column :name, String, null: false
column :email, String
column :alert_type, String
end
class Users < ROM::Relation[:sql]
schema(:users, infer: true)
auto_struct true
end
conf.register_relation(Users)
end
class UserRepo < ROM::Repository[:users]
struct_namespace Marv::Girt::Entities
commands :create, update: :by_pk, delete: :by_pk
end
user_repo = UserRepo.new(rom)
# get auto-generated User struct
model = user_repo.users.mapper.model
puts "model: #{model}"
# => Marv::Girt::Entities::User
puts model.schema.key(:id)
# => #<Dry::Types[id: Nominal<Integer meta={primary_key: true, alias: nil, source: :users}>]>
# Allows create with no "alert_type" specified
puts user = user_repo.create(name: "Jane", email: "jane@doe.org")
# => #<Marv::Girt::Entities::User:0x000000015aa2bce0>
puts user.name
# => Jane
puts user.alert_type
# =>
# Allows update with invalid "alert_type" specified
puts updated_user = user_repo.update(user.id, name: "Jane Doe", alert_type: "FISH")
# => #<Marv::Girt::Entities::User:0x000000015aa0a6a8>
puts updated_user.name
# => Jane Doe
puts updated_user.alert_type
# => FISH
puts count = user_repo.relations[:users].count
# => 1
puts user2 = user_repo.create(name: "Wayne", email: "wayne@doe.org")
# => #<Marv::Girt::Entities::User:0x000000015aa00270>
puts user2.name
# => Wayne
puts count2 = user_repo.relations[:users].count
# => 2
My Types are not used at all for validation. It’s using the class name, but otherwise, having no effect. Also, I am not sure how to use ROM::Types at all, in the manner I have been using Dry::Types, and I can’t find any relevant documentation.
The reason I want to do this is to be able to share my core set of entities across repositories that are backed by rom-http
, rom-sql
, and rom-json
.