Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decouple Command from Relation #613

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,9 @@ if ENV["USE_DRY_INITIALIZER_MASTER"].eql?("true")
gem "dry-initializer", github: "dry-rb/dry-initializer", branch: "master"
end

if ENV["USE_ROM_SQL_MASTER"].eql?("true")
gem "rom-sql", github: "rom-rb/rom-sql", branch: "master"
else
gem "rom-sql", "~> 3.3", ">= 3.3.1"
end

group :sql do
gem "rom-sql", github: "rom-rb/rom-sql", branch: "decouple-commands-from-relations"
# TODO: >= 5.32.0 breaks mysql schema inference in some cases
gem "dry-monitor"
gem "jdbc-postgres", platforms: :jruby
gem "jdbc-sqlite3", platforms: :jruby
Expand Down
61 changes: 24 additions & 37 deletions lib/rom/command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -194,18 +194,22 @@ class Command

# @!attribute [r] relation
# @return [Relation] Command's relation
param :relation
param :dataset

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

# @!attribute [r] schema
# @return [Schema] Relation's schema
option :schema, optional: true

# @!attribute [r] type
# @return [Symbol] The command type, one of :create, :update or :delete
option :type, type: CommandType, optional: true

# @!attribute [r] source
# @return [Relation] The source relation
option :source, default: -> { relation }
# @return [Dataset] The source dataset
option :source, default: -> { dataset }

# @!attribute [r] result
# @return [Symbol] Result type, either :one or :many
Expand All @@ -227,26 +231,18 @@ class Command
# @return [Array<Hash>] An array with after hooks configuration
option :after, Types::Coercible::Array, reader: false, default: -> { self.class.after }

input Hash
result :many

# Return name of this command's relation
#
# @return [ROM::Relation::Name]
#
# !@attribute :name
# @return [ROM::Relation::Name] Return name of this command's relation
# @api public
def name
relation.name
end
option :name, optional: true

# Return gateway of this command's relation
#
# @return [Symbol]
#
# !@attribute :gateway
# @return [Symbol] Return gateway of this command's relation
# @api public
def gateway
relation.gateway
end
option :gateway, optional: true

input Hash
result :many

# Execute the command
#
Expand Down Expand Up @@ -314,7 +310,7 @@ 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)
self.class.build(dataset, **options, curry_args: args)
end
end

Expand Down Expand Up @@ -346,7 +342,7 @@ def curried?
#
# @api public
def before(*hooks)
self.class.new(relation, **options, before: before_hooks + hooks)
self.class.new(dataset, **options, before: before_hooks + hooks)
end

# Return a new command with appended after hooks
Expand All @@ -357,7 +353,7 @@ def before(*hooks)
#
# @api public
def after(*hooks)
self.class.new(relation, **options, after: after_hooks + hooks)
self.class.new(dataset, **options, after: after_hooks + hooks)
end

# List of before hooks
Expand All @@ -378,15 +374,15 @@ def after_hooks
options[:after]
end

# Return a new command with other source relation
# Return a new command with other source dataset
#
# This can be used to restrict command with a specific relation
# This can be used to restrict command with a specific dataset
#
# @return [Command]
#
# @api public
def new(new_relation)
self.class.build(new_relation, **options, source: relation)
def new(new_dataset)
self.class.build(new_dataset, **options, source: dataset)
end

# Check if this command has any hooks
Expand Down Expand Up @@ -432,22 +428,13 @@ def many?
result.equal?(:many)
end

# Check if this command is restrictible through relation
#
# @return [TrueClass,FalseClass]
#
# @api private
def restrictible?
self.class.restrictable.equal?(true)
end

# Yields tuples for insertion or return an enumerator
#
# @api private
def map_input_tuples(tuples, &mapper)
return enum_for(:with_input_tuples, tuples) unless mapper

if tuples.respond_to? :merge
if tuples.respond_to?(:merge)
mapper[tuples]
else
tuples.map(&mapper)
Expand Down
4 changes: 2 additions & 2 deletions lib/rom/command_compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -217,9 +217,9 @@ def register_command(rel_name, type, rel_meta, parent_relation = nil)
command: klass, gateway: gateway, dataset: relation.dataset, adapter: adapter
)

klass.extend_for_relation(relation) if klass.restrictable
command_input = meta[:input] || relation.input_schema

registry[rel_name][type] = klass.build(relation)
registry[rel_name][type] = klass.build(relation.dataset, input: command_input)
end
end

Expand Down
4 changes: 2 additions & 2 deletions lib/rom/commands/class_interface.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ def adapter_namespace(adapter)
# @return [Command]
#
# @api public
def build(relation, **options)
new(relation, **self.options, **options)
def build(dataset, **options)
new(dataset, **self.options, **options)
end

# Create a command class with a specific type
Expand Down
4 changes: 1 addition & 3 deletions lib/rom/core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
# container factory
require "rom/create_container"

# register known plugin types
require "rom/schema_plugin"

# register known plugin types
ROM::Plugins.register(:command)
ROM::Plugins.register(:mapper)
ROM::Plugins.register(:relation)
Expand All @@ -37,7 +37,6 @@
# register core plugins
require "rom/plugins/relation/registry_reader"
require "rom/plugins/relation/instrumentation"
require "rom/plugins/command/schema"
require "rom/plugins/command/timestamps"
require "rom/plugins/schema/timestamps"

Expand All @@ -48,7 +47,6 @@ module ROM
register :timestamps, ROM::Plugins::Schema::Timestamps, type: :schema
register :registry_reader, ROM::Plugins::Relation::RegistryReader, type: :relation
register :instrumentation, ROM::Plugins::Relation::Instrumentation, type: :relation
register :schema, ROM::Plugins::Command::Schema, type: :command
register :timestamps, ROM::Plugins::Command::Timestamps, type: :command
end
end
8 changes: 3 additions & 5 deletions lib/rom/memory/commands.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@ module Commands
# @api public
class Create < ROM::Commands::Create
adapter :memory
use :schema

# @see ROM::Commands::Create#execute
def execute(tuples)
Array([tuples]).flatten.map { |tuple|
attributes = input[tuple]
relation.insert(attributes.to_h)
dataset.insert(attributes.to_h)
attributes
}.to_a
end
Expand All @@ -30,12 +29,11 @@ def execute(tuples)
# @api public
class Update < ROM::Commands::Update
adapter :memory
use :schema

# @see ROM::Commands::Update#execute
def execute(params)
attributes = input[params]
relation.map { |tuple| tuple.update(attributes.to_h) }
dataset.map { |tuple| tuple.update(attributes.to_h) }
end
end

Expand All @@ -47,7 +45,7 @@ class Delete < ROM::Commands::Delete

# @see ROM::Commands::Delete#execute
def execute
relation.to_a.map do |tuple|
dataset.to_a.map do |tuple|
source.delete(tuple)
tuple
end
Expand Down
45 changes: 0 additions & 45 deletions lib/rom/plugins/command/schema.rb

This file was deleted.

6 changes: 1 addition & 5 deletions lib/rom/relation/commands.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,7 @@ def command(type, mapper: nil, use: EMPTY_ARRAY, plugins_options: EMPTY_HASH, **
base_command
end

if command.restrictible?
command.new(self)
else
command
end
command.new(dataset)
end
end
end
Expand Down
11 changes: 7 additions & 4 deletions lib/rom/setup/finalize/finalize_commands.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,12 @@ def run!
command: klass, gateway: gateway, dataset: relation.dataset, adapter: relation.adapter
)

klass.extend_for_relation(relation) if klass.restrictable

klass.build(relation)
klass.build(
relation.dataset,
input: relation.input_schema,
name: relation.name,
gateway: relation.gateway
)
end

registry = Registry.new
Expand All @@ -54,7 +57,7 @@ def run!
)

@relations.each do |(name, relation)|
rel_commands = commands.select { |c| c.relation.name == relation.name }
rel_commands = commands.select { |c| c.dataset.eql?(relation.dataset) }

rel_commands.each do |command|
identifier = command.class.register_as || command.class.default_name
Expand Down
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

require "rom/core"
require "rom-changeset"
require "byebug"

Dir[root.join("support/**/*.rb").to_s].each do |f|
require f unless f.include?("coverage")
Expand Down
2 changes: 1 addition & 1 deletion spec/unit/rom/commands/lazy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ def associate(tuple, user)
ROM::Commands::Lazy[update_task].new(
update_task,
evaluator,
-> cmd, user, task { cmd.by_user(user[:name]).by_title(task[:title]) }
-> cmd, user, task { relation.by_user(user[:name]).by_title(task[:title]).command(:update) }
)
end

Expand Down
Loading