Class: ROM::Command

Inherits:
Object
  • Object
show all
Extended by:
Dry::Core::ClassAttributes, ClassInterface, Restrictable, Initializer, Plugins::ClassMethods, SettingProxy
Includes:
Commands, Pipeline::Operator
Defined in:
lib/rom/command.rb,
lib/rom/compat/command.rb,
lib/rom/commands/class_interface.rb

Overview

Base command class with factory class-level interface and setup-related logic

Defined Under Namespace

Modules: ClassInterface, Restrictable

Constant Summary collapse

CommandType =
Types::Strict::Symbol.enum(:create, :update, :delete)
Result =
Types::Strict::Symbol.enum(:one, :many)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#after(*hooks) ⇒ Command (readonly)

Return a new command with appended after hooks

Parameters:

  • hooks (Array<Hash>)

    A list of after hooks configurations

Returns:



83
# File 'lib/rom/command.rb', line 83

option :after, Types::Coercible::Array, reader: false, default: -> { self.class.after }

#before(*hooks) ⇒ Command (readonly)

Return a new command with appended before hooks

Parameters:

  • hooks (Array<Hash>)

    A list of before hooks configurations

Returns:



79
# File 'lib/rom/command.rb', line 79

option :before, Types::Coercible::Array, reader: false, default: -> { self.class.before }

#configROM::Configurable::Config (readonly)



59
# File 'lib/rom/command.rb', line 59

option :config, default: -> { self.class.config }

#curry_argsArray (readonly)

Returns Curried args.

Returns:

  • (Array)

    Curried args



75
# File 'lib/rom/command.rb', line 75

option :curry_args, default: -> { EMPTY_ARRAY }

#inputProc, #call (readonly)

Returns Tuple processing function, typically uses Relation#input_schema.

Returns:

  • (Proc, #call)

    Tuple processing function, typically uses Relation#input_schema



71
# File 'lib/rom/command.rb', line 71

option :input, default: -> { config.input }

#relationRelation (readonly)

Returns Command's relation.

Returns:



48
# File 'lib/rom/command.rb', line 48

param :relation

#resultSymbol (readonly)

Returns Result type, either :one or :many.

Returns:

  • (Symbol)

    Result type, either :one or :many



67
# File 'lib/rom/command.rb', line 67

option :result, type: Result, default: -> { config.result }

#sourceRelation (readonly)

Returns The source relation.

Returns:



63
# File 'lib/rom/command.rb', line 63

option :source, default: -> { relation }

#typeSymbol (readonly)

Returns The command type, one of :create, :update or :delete.

Returns:

  • (Symbol)

    The command type, one of :create, :update or :delete



55
# File 'lib/rom/command.rb', line 55

option :type, type: CommandType, optional: true

Class Method Details

.[](adapter) ⇒ Class Originally defined in module ClassInterface

Return adapter specific sub-class based on the adapter identifier

This is a syntax sugar to make things consistent

Examples:

ROM::Commands::Create[:memory]
# => ROM::Memory::Commands::Create

Parameters:

  • adapter (Symbol)

    identifier

Returns:

  • (Class)

.adapterSymbol Originally defined in module ClassInterface

Return configured adapter identifier

Returns:

  • (Symbol)

.adapter_namespace(adapter) ⇒ Module Originally defined in module ClassInterface

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Return namespaces that contains command subclasses of a specific adapter

Parameters:

  • adapter (Symbol)

    identifier

Returns:

  • (Module)

#after(hook) ⇒ Array<Hash, Symbol> #after(hook_opts) ⇒ Array<Hash, Symbol> Originally defined in module ClassInterface

Set after-execute hooks

Overloads:

  • #after(hook) ⇒ Array<Hash, Symbol>

    Set an after hook as a method name

    Examples:

    class CreateUser < ROM::Commands::Create[:sql]
      relation :users
      register_as :create
    
      after :my_hook
    
      def my_hook(tuple, *)
        puts "hook called#
      end
    end
  • #after(hook_opts) ⇒ Array<Hash, Symbol>

    Set an after hook as a method name with arguments

    Examples:

    class CreateUser < ROM::Commands::Create[:sql]
      relation :users
      register_as :create
    
      after my_hook: { arg1: 1, arg1: 2 }
    
      def my_hook(tuple, arg1:, arg2:)
        puts "hook called with args: #{arg1} and #{arg2}"
      end
    end

    Parameters:

    • hook (Hash<Symbol=>Hash>)

      Options with method name and pre-set args

Returns:

  • (Array<Hash, Symbol>)

    A list of all configured after hooks

#before(hook) ⇒ Array<Hash, Symbol> #before(hook_opts) ⇒ Array<Hash, Symbol> Originally defined in module ClassInterface

Set before-execute hooks

Overloads:

  • #before(hook) ⇒ Array<Hash, Symbol>

    Set an before hook as a method name

    Examples:

    class CreateUser < ROM::Commands::Create[:sql]
      relation :users
      register_as :create
    
      before :my_hook
    
      def my_hook(tuple, *)
        puts "hook called#
      end
    end
  • #before(hook_opts) ⇒ Array<Hash, Symbol>

    Set an before hook as a method name with arguments

    Examples:

    class CreateUser < ROM::Commands::Create[:sql]
      relation :users
      register_as :create
    
      before my_hook: { arg1: 1, arg2: 2 }
    
      def my_hook(tuple, arg1:, arg2:)
        puts "hook called with args: #{arg1} and #{arg2}"
      end
    end

    Parameters:

    • hook (Hash<Symbol=>Hash>)

      Options with method name and pre-set args

Returns:

  • (Array<Hash, Symbol>)

    A list of all configured before hooks

.build(relation, **options) ⇒ Command Originally defined in module ClassInterface

Build a command class for a specific relation with options

Examples:

class CreateUser < ROM::Commands::Create[:memory]
end

command = CreateUser.build(rom.relations[:users])

Parameters:

Returns:

.create_class(type: self, meta: {}, rel_meta: {}, plugins: {}) {|Class| ... } ⇒ Class, Object Originally defined in module ClassInterface

Create a command class with a specific type

Parameters:

  • name (Symbol)

    Command name

  • type (Class) (defaults to: self)

    Command class

Yields:

  • (Class)

Returns:

  • (Class, Object)

.default_nameSymbol Originally defined in module ClassInterface

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Return default name of the command class based on its name

During setup phase this is used by defalut as register_as option

Returns:

  • (Symbol)

.extend_for_relation(relation) ⇒ Class

Deprecated.

Extend a command class with relation view methods

Parameters:

Returns:

  • (Class)


51
52
53
# File 'lib/rom/compat/command.rb', line 51

def self.extend_for_relation(relation)
  include(relation_methods_mod(relation.class))
end

.inherited(klass) ⇒ Object Originally defined in module ClassInterface

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This hook sets up default class state

.pluginsObject Originally defined in module Plugins::ClassMethods

Return all available plugins for the component type

.relation_methods_mod(relation_class) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/rom/compat/command.rb', line 56

def self.relation_methods_mod(relation_class)
  Module.new do
    relation_class.view_methods.each do |meth|
      module_eval <<-RUBY, __FILE__, __LINE__ + 1
        def #{meth}(*args)
          response = relation.public_send(:#{meth}, *args)

          if response.is_a?(relation.class)
            new(response)
          else
            response
          end
        end
      RUBY
    end
  end
end

.set_hooks(type, hooks) ⇒ Object Originally defined in module ClassInterface

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Set new or more hooks

.setting_mappingObject



31
32
33
34
35
36
37
38
39
40
# File 'lib/rom/compat/command.rb', line 31

def setting_mapping
  @setting_mapper ||= {
    adapter: [:component, :adapter],
    relation: [:component, %i[relation namespace]],
    register_as: [:component, :id],
    restrictable: [],
    result: [],
    input: []
  }.freeze
end

.use(name, **options) ⇒ Object Originally defined in module Plugins::ClassMethods

Include a registered plugin in this relation class

Parameters:

  • plugin (Symbol)
  • options (Hash)

Options Hash (**options):

  • :adapter (Symbol) — default: :default

    first adapter to check for plugin

Instance Method Details

#>>(other) ⇒ Relation::Composite Originally defined in module Pipeline::Operator

Compose two relation with a left-to-right composition

Examples:

users.by_name('Jane') >> tasks.for_users

Parameters:

  • other (Relation)

    The right relation

Returns:

#after_hooksArray

List of after hooks

Returns:

  • (Array)


229
230
231
# File 'lib/rom/command.rb', line 229

def after_hooks
  options[:after]
end

#before_hooksArray

List of before hooks

Returns:

  • (Array)


220
221
222
# File 'lib/rom/command.rb', line 220

def before_hooks
  options[:before]
end

#call(*args, &block) ⇒ Object Also known as: []

Call the command and return one or many tuples

This method will apply before/after hooks automatically



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/rom/command.rb', line 122

def call(*args, &block)
  tuples =
    if hooks?
      prepared =
        if curried?
          apply_hooks(before_hooks, *(curry_args + args))
        else
          apply_hooks(before_hooks, *args)
        end

      result = prepared ? execute(prepared, &block) : execute(&block)

      if curried?
        if !args.empty?
          apply_hooks(after_hooks, result, *args)
        elsif curry_args.size > 1
          apply_hooks(after_hooks, result, curry_args[1])
        else
          apply_hooks(after_hooks, result)
        end
      else
        apply_hooks(after_hooks, result, *args[1..args.size - 1])
      end
    else
      execute(*(curry_args + args), &block)
    end

  if one?
    tuples.first
  else
    tuples
  end
end

#combine(*others) ⇒ Command::Graph

Compose this command with other commands

Composed commands can handle nested input

Returns:



180
181
182
# File 'lib/rom/command.rb', line 180

def combine(*others)
  Graph.new(self, others)
end

#curried?TrueClass, FalseClass

Check if this command is curried

Returns:

  • (TrueClass, FalseClass)


189
190
191
# File 'lib/rom/command.rb', line 189

def curried?
  !curry_args.empty?
end

#curry(*args) ⇒ Command, Lazy

Curry this command with provided args

Curried command can be called without args. If argument is a graph input processor, lazy command will be returned, which is used for handling nested input hashes.

Returns:



165
166
167
168
169
170
171
# File 'lib/rom/command.rb', line 165

def curry(*args)
  if curry_args.empty? && args.first.is_a?(Graph::InputEvaluator)
    Lazy[self].new(self, *args)
  else
    self.class.build(relation, **options, curry_args: args)
  end
end

#executeArray

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method is abstract.

Execute the command

Returns:

  • (Array)

    an array with inserted tuples

Raises:

  • (NotImplementedError)


110
111
112
113
114
115
# File 'lib/rom/command.rb', line 110

def execute(*)
  raise(
    NotImplementedError,
    "#{self.class}##{__method__} must be implemented"
  )
end

#gatewaySymbol

Return gateway of this command's relation

Returns:

  • (Symbol)


99
100
101
# File 'lib/rom/command.rb', line 99

def gateway
  relation.gateway
end

#graph?false

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if this command is a graph

Returns:

  • (false)


265
266
267
# File 'lib/rom/command.rb', line 265

def graph?
  false
end

#hooks?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if this command has any hooks

Returns:

  • (Boolean)


247
248
249
# File 'lib/rom/command.rb', line 247

def hooks?
  !before_hooks.empty? || !after_hooks.empty?
end

#lazy?false

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if this command is lazy

Returns:

  • (false)


256
257
258
# File 'lib/rom/command.rb', line 256

def lazy?
  false
end

#many?TrueClass, FalseClass

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if this command returns many tuples

Returns:

  • (TrueClass, FalseClass)


283
284
285
# File 'lib/rom/command.rb', line 283

def many?
  result.equal?(:many)
end

#map_input_tuples(tuples, &mapper) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Yields tuples for insertion or return an enumerator



299
300
301
302
303
304
305
306
307
# File 'lib/rom/command.rb', line 299

def map_input_tuples(tuples, &mapper)
  return enum_for(:with_input_tuples, tuples) unless mapper

  if tuples.respond_to? :merge
    mapper[tuples]
  else
    tuples.map(&mapper)
  end
end

#nameROM::Relation::Name

Return name of this command's relation

Returns:



90
91
92
# File 'lib/rom/command.rb', line 90

def name
  relation.name
end

#new(new_relation) ⇒ Command

Return a new command with other source relation

This can be used to restrict command with a specific relation

Returns:



240
241
242
# File 'lib/rom/command.rb', line 240

def new(new_relation)
  self.class.build(new_relation, **options, source: relation)
end

#one?TrueClass, FalseClass

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if this command returns a single tuple

Returns:

  • (TrueClass, FalseClass)


274
275
276
# File 'lib/rom/command.rb', line 274

def one?
  result.equal?(:one)
end

#restrictible?TrueClass, FalseClass

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if this command is restrictible through relation

Returns:

  • (TrueClass, FalseClass)


292
293
294
# File 'lib/rom/command.rb', line 292

def restrictible?
  config.restrictable.equal?(true)
end