Advanced Topics » Standalone Commands
Writing records to a persistence solution is done through Commands. Commands are objects that encapsulate datastore-specific modification operations. They receive a relation and execute their operation using that relation.
ROM adapters can provide three basic Command types:
ROM::Commands::Create
ROM::Commands::Update
ROM::Commands::Delete
Some adapters provide more for special operations - see your adapter’s documentation for details.
Defining Commands
In your setup, define available commands with the commands
statement, passing
it a symbol of the relation's name:
require 'rom-repository'
# Assumes a database with a users table
ROM.container(:sql, 'sqlite::memory') do |config|
# Remember that many adapters can infer relations, so we can often skip defining it.
# Otherwise, add something like:
#
# config.relation(:users)
config.commands(:users) do
# declares that we can create, update, and delete users.
define(:create)
define(:update)
define(:delete)
end
end
Single Results vs Many Results
Ordinarily, a command will return an Array
of Hash
objects. You can
customize this to return a single result by supplying result :one
to the
command definition.
ROM.container(:sql, 'sqlite::memory') do |config|
config.commands(:users) do
define(:create) do
result :one
end
# ... etc
end
end
Executing Commands
Every registered command is accessible through the environment container:
rom_container = ROM.container(:sql, 'sqlite::memory') do |config|
config.relation(:users) do
def by_id(id)
where(id: id)
end
def by_first_name(name)
where(first_name: name)
end
end
config.commands(:users) do
define(:create)
end
end
# fetch the command object by type
create_user = rom_container.commands[:users][:create]
# a command object won’t do anything until it’s called with input tuples:
new_users = [
{ name: 'Jane' },
{ name: 'Joe' }
]
create_user.call(new_users) # saves the user tuples
Commands are backed by a relation, which you can use to specify which records to Update or Delete.
# operate on a single result
delete_user = rom_container.commands[:users][:delete]
delete_user.by_id(2).call
# or many
delete_users = rom_container.commands[:users][:delete]
delete_users.by_first_name('Lawrence').call
# update is the same, and takes the new data as a parameter to #call
update_user = rom_container.command[:users][:update]
update_user.by_id(7).call(first_name: 'Kaylee', last_name: 'Frye')
Full Example
This short example demonstrates defining and using the three basic commands.
# app.rb
class MyApp
def self.run(rom_container)
user_commands = rom_container.commands[:users]
# Create...
user = user_commands[:create].call(first_name: 'Natalia', last_name: 'Romanova')
puts rom_container.relation(:users).to_a.inspect
# => [{:first_name=>"Natalia", :last_name=>"Romanova"}]
# Update...
user_commands[:update].by_id(user[:id]).call(first_name: 'Natasha', last_name: 'Romanoff')
puts rom_container.relation(:users).to_a.inspect
# => [{:first_name=>"Natasha", :last_name=>"Romanoff"}]
# And Delete!
user_commands[:delete].by_id(user[:id]).call
puts rom_container.relation(:users).to_a.inspect
# => []
end
end
# command_demo.rb
require 'rom-sql'
# Assumes a database with a users table
rom_container = ROM.container(:sql, 'sqlite::memory') do |config|
config.use :macros
config.relation(:users) do
def by_id(id)
restrict(id: id)
end
end
config.commands(:users) do
define(:create) do
result :one
end
define(:update)
define(:delete)
end
end
MyApp.run(rom_container)
Run it and see the three states print out.
ruby command_demo.rb