Closed solnic closed 8 years ago
We can tweak commands in a way that if there's an input handler configured which is not the default proc, then we'll compose it with the schema handler. Would that work?
From @flash-gordon on November 4, 2016 18:57
This is possible to override Command.build
method in this way
class Commands::CreateCaseFromModel < ROM::Command::Create[:sql]
relation :hoi_cases
register_as :create_from_model
def self.build(relation, options = {})
# pass any input you want, you can access schema's input via relation.schema_hash
super(relation, options.merge(input: ...))
end
end
This will do the trick for now ^ But I agree we need to make it more user-friendly :) See sources: https://github.com/rom-rb/rom/blob/master/lib/rom/plugins/command/schema.rb#L16
@Kukunin this has been fixed in rom 2.0.2, this illustrates how it works now:
require 'rom'
require 'securerandom'
config = ROM::Configuration.new(:sql, 'sqlite::memory')
config.default.create_table :posts do
primary_key :id
column :title, String, null: false
column :uuid, String
end
config.relation(:posts) do
schema(infer: true)
end
class CreatePost < ROM::Command::Create[:sql]
relation :posts
register_as :create
input -> tuple { tuple.key?(:uuid) ? tuple : tuple.merge(uuid: SecureRandom.uuid) }
end
config.register_command(CreatePost)
rom = ROM.container(config)
puts rom.commands[:posts][:create].call(title: "Hello World").inspect
# [{:id=>1, :title=>"Hello World", :uuid=>"fd2eafb6-30c1-46aa-9a9d-770a90a30a2a"}]
Now, schema hash is used as the second processing step, this means that your input handler is used first, and its result is passed to schema hash.
In example here we configure our schema with a constrained type for :uuid
attribute:
require 'rom'
require 'securerandom'
config = ROM::Configuration.new(:sql, 'sqlite::memory')
config.default.create_table :posts do
primary_key :id
column :title, String, null: false
column :uuid, String
end
config.relation(:posts) do
schema do
attribute :id, ROM::SQL::Types::Serial
attribute :title, ROM::SQL::Types::Strict::String
attribute :uuid, ROM::SQL::Types::Strict::String.constrained(format: /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i)
end
end
class CreatePost < ROM::Command::Create[:sql]
relation :posts
register_as :create
input -> tuple { tuple.key?(:uuid) ? tuple : tuple.merge(uuid: SecureRandom.uuid) }
end
config.register_command(CreatePost)
rom = ROM.container(config)
rom.commands[:posts][:create].call(title: "Hello World", uuid: 'not-uuid').inspect
# "not-uuid" (String) has invalid type for :uuid (Dry::Types::SchemaError)
Thanks a lot!
From @Kukunin on November 4, 2016 17:56
In my application, I have different attributes format between schema (legacy tables) and my domain models. So I need to use mappers to both save and restore an entity.
While it's easy to use mappers for Relation, I haven't found a way to use for Command. So, I use command's
input
for this purpose.It works great, until I want to set association for my relation.
schema(infer: true)
breaks everything.After some investigation, I've found that inferred schema overrides my custom input for any commands.
So, without
schema(infer: true)
, I get custom mapper asinput
But with
schema(infer: true)
, it is:So, because It doesn't map my domain entity, it crashes.
P.S. If you know a better way to map entity to underlying schema in 2-directions more easily - tell me, please.
Thanks!