rom 0.9.1 → 1.0.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +30 -12
  3. data/.travis.yml +1 -1
  4. data/CHANGELOG.md +24 -0
  5. data/Gemfile +7 -3
  6. data/README.md +24 -11
  7. data/lib/rom.rb +9 -26
  8. data/lib/rom/command.rb +113 -75
  9. data/lib/rom/commands/class_interface.rb +115 -0
  10. data/lib/rom/commands/graph.rb +17 -23
  11. data/lib/rom/commands/graph/builder.rb +176 -0
  12. data/lib/rom/commands/graph/class_interface.rb +8 -2
  13. data/lib/rom/commands/graph/input_evaluator.rb +13 -9
  14. data/lib/rom/commands/lazy.rb +23 -17
  15. data/lib/rom/commands/lazy/create.rb +23 -0
  16. data/lib/rom/commands/lazy/delete.rb +27 -0
  17. data/lib/rom/commands/lazy/update.rb +34 -0
  18. data/lib/rom/commands/result.rb +14 -0
  19. data/lib/rom/commands/update.rb +0 -4
  20. data/lib/rom/configuration.rb +86 -0
  21. data/lib/rom/{setup_dsl/setup.rb → configuration_dsl.rb} +9 -7
  22. data/lib/rom/configuration_dsl/command.rb +43 -0
  23. data/lib/rom/{setup_dsl → configuration_dsl}/command_dsl.rb +5 -4
  24. data/lib/rom/configuration_dsl/mapper.rb +37 -0
  25. data/lib/rom/{setup_dsl → configuration_dsl}/mapper_dsl.rb +11 -5
  26. data/lib/rom/configuration_dsl/relation.rb +26 -0
  27. data/lib/rom/configuration_plugin.rb +17 -0
  28. data/lib/rom/constants.rb +5 -12
  29. data/lib/rom/container.rb +11 -8
  30. data/lib/rom/create_container.rb +61 -0
  31. data/lib/rom/environment.rb +27 -241
  32. data/lib/rom/gateway.rb +18 -2
  33. data/lib/rom/global.rb +24 -0
  34. data/lib/rom/global/plugin_dsl.rb +2 -0
  35. data/lib/rom/lint/spec.rb +0 -12
  36. data/lib/rom/lint/test.rb +0 -31
  37. data/lib/rom/memory/commands.rb +2 -2
  38. data/lib/rom/memory/gateway.rb +2 -0
  39. data/lib/rom/pipeline.rb +1 -1
  40. data/lib/rom/plugin_base.rb +1 -1
  41. data/lib/rom/plugin_registry.rb +12 -10
  42. data/lib/rom/plugins/configuration/configuration_dsl.rb +16 -0
  43. data/lib/rom/plugins/relation/key_inference.rb +31 -0
  44. data/lib/rom/plugins/relation/view.rb +90 -0
  45. data/lib/rom/plugins/relation/view/dsl.rb +32 -0
  46. data/lib/rom/relation.rb +1 -11
  47. data/lib/rom/relation/class_interface.rb +37 -50
  48. data/lib/rom/setup.rb +13 -104
  49. data/lib/rom/setup/auto_registration.rb +55 -0
  50. data/lib/rom/setup/finalize.rb +113 -127
  51. data/lib/rom/setup/finalize/commands.rb +67 -0
  52. data/lib/rom/setup/finalize/mappers.rb +36 -0
  53. data/lib/rom/setup/finalize/relations.rb +53 -0
  54. data/lib/rom/support/configurable.rb +21 -7
  55. data/lib/rom/version.rb +1 -1
  56. data/rakelib/mutant.rake +4 -1
  57. data/rom.gemspec +3 -4
  58. data/spec/fixtures/app/commands/create_user.rb +2 -0
  59. data/spec/fixtures/app/mappers/user_list.rb +2 -0
  60. data/spec/fixtures/app/relations/users.rb +2 -0
  61. data/spec/fixtures/lib/persistence/commands/create_user.rb +6 -0
  62. data/spec/fixtures/lib/persistence/mappers/user_list.rb +6 -0
  63. data/spec/fixtures/lib/persistence/relations/users.rb +6 -0
  64. data/spec/{unit/rom → integration}/command_registry_spec.rb +8 -9
  65. data/spec/integration/commands/create_spec.rb +17 -13
  66. data/spec/integration/commands/delete_spec.rb +12 -11
  67. data/spec/integration/commands/error_handling_spec.rb +5 -4
  68. data/spec/integration/commands/graph_builder_spec.rb +213 -0
  69. data/spec/integration/commands/graph_spec.rb +112 -49
  70. data/spec/integration/commands/update_spec.rb +14 -11
  71. data/spec/integration/commands_spec.rb +60 -0
  72. data/spec/integration/mappers/combine_spec.rb +7 -6
  73. data/spec/integration/mappers/deep_embedded_spec.rb +5 -6
  74. data/spec/integration/mappers/definition_dsl_spec.rb +19 -18
  75. data/spec/integration/mappers/embedded_spec.rb +11 -12
  76. data/spec/integration/mappers/exclude_spec.rb +5 -6
  77. data/spec/integration/mappers/fold_spec.rb +8 -7
  78. data/spec/integration/mappers/group_spec.rb +16 -15
  79. data/spec/integration/mappers/overwrite_attributes_value_spec.rb +5 -5
  80. data/spec/integration/mappers/prefix_separator_spec.rb +5 -7
  81. data/spec/integration/mappers/prefix_spec.rb +5 -7
  82. data/spec/integration/mappers/prefixing_attributes_spec.rb +7 -7
  83. data/spec/integration/mappers/registering_custom_mappers_spec.rb +4 -5
  84. data/spec/integration/mappers/renaming_attributes_spec.rb +18 -18
  85. data/spec/integration/mappers/step_spec.rb +11 -12
  86. data/spec/integration/mappers/symbolizing_attributes_spec.rb +11 -8
  87. data/spec/integration/mappers/unfold_spec.rb +9 -10
  88. data/spec/integration/mappers/ungroup_spec.rb +10 -11
  89. data/spec/integration/mappers/unwrap_spec.rb +10 -15
  90. data/spec/integration/mappers/wrap_spec.rb +16 -15
  91. data/spec/{unit/rom → integration}/memory/commands/create_spec.rb +7 -5
  92. data/spec/{unit/rom → integration}/memory/commands/delete_spec.rb +7 -5
  93. data/spec/{unit/rom → integration}/memory/commands/update_spec.rb +7 -5
  94. data/spec/integration/multi_env_spec.rb +16 -124
  95. data/spec/integration/multi_repo_spec.rb +9 -9
  96. data/spec/integration/relations/default_dataset_spec.rb +15 -0
  97. data/spec/integration/relations/inheritance_spec.rb +5 -7
  98. data/spec/integration/relations/reading_spec.rb +32 -65
  99. data/spec/integration/relations/registry_dsl_spec.rb +5 -4
  100. data/spec/integration/repositories/extending_relations_spec.rb +6 -7
  101. data/spec/integration/repositories/setting_logger_spec.rb +5 -7
  102. data/spec/integration/setup_spec.rb +49 -61
  103. data/spec/shared/command_graph.rb +50 -0
  104. data/spec/shared/container.rb +9 -0
  105. data/spec/shared/gateway_only.rb +6 -0
  106. data/spec/shared/no_container.rb +16 -0
  107. data/spec/shared/one_behavior.rb +4 -4
  108. data/spec/shared/users_and_tasks.rb +5 -17
  109. data/spec/spec_helper.rb +5 -3
  110. data/spec/test/memory_repository_lint_test.rb +1 -1
  111. data/spec/unit/rom/auto_registration_spec.rb +54 -0
  112. data/spec/unit/rom/commands/graph_spec.rb +18 -44
  113. data/spec/unit/rom/commands/lazy_spec.rb +246 -35
  114. data/spec/unit/rom/commands/result_spec.rb +56 -0
  115. data/spec/unit/rom/commands_spec.rb +9 -73
  116. data/spec/unit/rom/configurable_spec.rb +49 -0
  117. data/spec/unit/rom/configuration_spec.rb +61 -0
  118. data/spec/unit/rom/container_spec.rb +39 -33
  119. data/spec/unit/rom/create_container_spec.rb +151 -0
  120. data/spec/unit/rom/environment_spec.rb +123 -0
  121. data/spec/unit/rom/gateway_spec.rb +58 -2
  122. data/spec/unit/rom/global_spec.rb +10 -7
  123. data/spec/unit/rom/plugin_spec.rb +44 -25
  124. data/spec/unit/rom/plugins/relation/key_inference_spec.rb +27 -0
  125. data/spec/unit/rom/plugins/relation/view_spec.rb +47 -0
  126. data/spec/unit/rom/relation/composite_spec.rb +20 -20
  127. data/spec/unit/rom/relation/curried_spec.rb +10 -11
  128. data/spec/unit/rom/relation/graph_spec.rb +27 -27
  129. data/spec/unit/rom/relation/lazy/combine_spec.rb +26 -20
  130. data/spec/unit/rom/relation/lazy_spec.rb +38 -38
  131. data/spec/unit/rom/relation/loaded_spec.rb +2 -3
  132. data/spec/unit/rom/relation_spec.rb +39 -2
  133. metadata +58 -66
  134. data/lib/rom/commands/abstract.rb +0 -184
  135. data/lib/rom/environment_plugin.rb +0 -17
  136. data/lib/rom/environment_plugins/auto_registration.rb +0 -38
  137. data/lib/rom/repository.rb +0 -16
  138. data/lib/rom/setup_dsl/command.rb +0 -36
  139. data/lib/rom/setup_dsl/mapper.rb +0 -32
  140. data/lib/rom/setup_dsl/relation.rb +0 -30
  141. data/spec/integration/inline_setup_spec.rb +0 -65
  142. data/spec/unit/rom/repository_spec.rb +0 -12
  143. data/spec/unit/rom/setup_spec.rb +0 -253
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d5eaa5117425dbec0243b42bfc8e5cd2a246ee67
4
- data.tar.gz: b4d0c29e7025e62a7e8cf8660913a1a5c5c9a65a
3
+ metadata.gz: 5528fe9b5a765d4b890b736e7f1fd41756f98bb9
4
+ data.tar.gz: 98e7df71ea10901734ff91af05a42d17b345e385
5
5
  SHA512:
6
- metadata.gz: fd50b8d43492c960dffcb3782cf0068138bacfaa05791266a8d407fe8938b5cf758360372b88be8a26f98c391fa2c857502a9547574d2e635c76ccad581f8f30
7
- data.tar.gz: 45c454986d7b9aa01b06bc1210b75733b9daedb25a13208e7726bbe11e2000039ce0d057c94f11bd3f31adea46bfb08a8a92115abf998b58ffd79af98d1d5b09
6
+ metadata.gz: 3c11e54690552a3b38ec4cd59cea7c2153c40e93be50fb69de3b3b63c0c5b4645127b65ac33f61cbe785043992824e56b2cd82e0622bd7fbabda0075f300827d
7
+ data.tar.gz: 8a87fbd020626ae052732c524af292666338bff3bce12e174af9b82a40504216f29385c0026b0991bae747af9f9835ab37d0fee41d626831e24f3e8eda0f705b
data/.rubocop_todo.yml CHANGED
@@ -1,28 +1,46 @@
1
- # This configuration was generated by `rubocop --auto-gen-config`
2
- # on 2015-02-26 16:54:42 +0100 using RuboCop version 0.29.1.
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2015-09-26 16:17:55 +0200 using RuboCop version 0.34.2.
3
4
  # The point is for the user to remove these configuration records
4
5
  # one by one as the offenses are removed from the code base.
5
6
  # Note that changes in the inspected code, or installation of new
6
7
  # versions of RuboCop, may require this file to be generated again.
7
8
 
8
- # Offense count: 4
9
+ # Offense count: 3
10
+ Lint/NestedMethodDefinition:
11
+ Exclude:
12
+ - 'lib/rom/relation/class_interface.rb'
13
+ - 'spec/unit/rom/commands_spec.rb'
14
+
15
+ # Offense count: 13
9
16
  Metrics/AbcSize:
10
- Max: 22
17
+ Max: 38
11
18
 
12
- # Offense count: 1
19
+ # Offense count: 3
13
20
  Metrics/CyclomaticComplexity:
14
- Max: 7
21
+ Max: 9
15
22
 
16
- # Offense count: 40
23
+ # Offense count: 65
17
24
  # Configuration parameters: AllowURI, URISchemes.
18
25
  Metrics/LineLength:
19
- Max: 88
26
+ Max: 113
20
27
 
21
- # Offense count: 15
28
+ # Offense count: 20
22
29
  # Configuration parameters: CountComments.
23
30
  Metrics/MethodLength:
24
- Max: 21
31
+ Max: 42
25
32
 
26
- # Offense count: 1
33
+ # Offense count: 3
27
34
  Metrics/PerceivedComplexity:
28
- Max: 10
35
+ Max: 11
36
+
37
+ # Offense count: 1
38
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
39
+ Style/MethodName:
40
+ Enabled: false
41
+
42
+ # Offense count: 1
43
+ # Configuration parameters: Methods.
44
+ Style/SingleLineBlockParams:
45
+ Exclude:
46
+ - 'lib/rom/commands/graph/class_interface.rb'
data/.travis.yml CHANGED
@@ -10,7 +10,7 @@ rvm:
10
10
  - 2.1
11
11
  - 2.2
12
12
  - rbx-2
13
- - jruby
13
+ - jruby-9000
14
14
  - ruby-head
15
15
  - jruby-head
16
16
  env:
data/CHANGELOG.md CHANGED
@@ -1,3 +1,27 @@
1
+ ## v1.0.0 to-be-released
2
+
3
+ ### Added
4
+
5
+ - Command graph DSL (endash + solnic)
6
+ - Command graph now supports update and delete commands (cflipse + solnic)
7
+ - `Gateway.adapter` setting and a corresponding `Gateway#adapter` reader. Both are
8
+ necessary to access a migrator (nepalez)
9
+ - `ROM::Commands::Result#{success?,failure?}` interface (Snuff)
10
+ - Imported relation plugins from `rom-repository`:
11
+ - `view` for explicit relation view definitions
12
+ - `key_inference` for inferring `foreign_key` of a relation
13
+
14
+ ### Changed
15
+
16
+ - **REMOVED** all deprecated APIs (solnic)
17
+ - [fixed #306] Inheriting from a misconfigured adapter relation will raise a
18
+ meaningful error (solnic)
19
+ - Command graph will raise `ROM::KeyMissing` command error when a key is missing
20
+ in the input (solnic)
21
+ - Command graph no longer rescues from any exception (solnic)
22
+
23
+ [Compare v0.9.1...HEAD](https://github.com/rom-rb/rom/compare/v0.9.1...HEAD)
24
+
1
25
  ## v0.9.1 2015-08-21
2
26
 
3
27
  This is a small bug-fix release which addresses a couple of issues for inline
data/Gemfile CHANGED
@@ -2,6 +2,10 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
+ gem 'rom-support', github: 'rom-rb/rom-support', branch: 'master'
6
+ gem 'rom-mapper', github: 'rom-rb/rom-mapper', branch: 'master'
7
+ gem 'transproc', github: 'solnic/transproc', branch: 'master'
8
+
5
9
  group :console do
6
10
  gem 'pry'
7
11
  gem 'pg', platforms: [:mri]
@@ -9,7 +13,7 @@ end
9
13
 
10
14
  group :test do
11
15
  gem 'virtus'
12
- gem 'anima'
16
+ gem 'anima', '~> 0.2.0'
13
17
  gem 'minitest'
14
18
  gem 'thread_safe'
15
19
  gem 'activesupport'
@@ -22,7 +26,7 @@ group :test do
22
26
  end
23
27
 
24
28
  group :sql do
25
- gem 'rom-sql', git: 'https://github.com/rom-rb/rom-sql.git', branch: 'master'
29
+ gem 'rom-sql', github: 'rom-rb/rom-sql', branch: 'master'
26
30
  gem 'sequel'
27
31
  gem 'jdbc-sqlite3', platforms: :jruby
28
32
  gem 'sqlite3', platforms: [:mri, :rbx]
@@ -43,7 +47,7 @@ group :tools do
43
47
  gem 'byebug', platform: :mri
44
48
 
45
49
  platform :mri do
46
- gem 'mutant', '>= 0.8.0', github: 'mbj/mutant', branch: 'master'
50
+ gem 'mutant'
47
51
  gem 'mutant-rspec'
48
52
  end
49
53
  end
data/README.md CHANGED
@@ -28,18 +28,30 @@ Learn more:
28
28
 
29
29
  You can support ROM's development via our [campaign on Bountysource](https://salt.bountysource.com/teams/rom-rb). Cheers!
30
30
 
31
+ ## Ecosystem
32
+
33
+ There are other gems within the rom ecosystem that you will find useful:
34
+
35
+ * [rom-repository](https://github.com/rom-rb/rom-repository) a higher-level, convenient abstraction with auto-mapping
36
+ * [rom-model](https://github.com/rom-rb/rom-model) extensions for coercion and validation
37
+
31
38
  ## Adapters
32
39
 
33
- * [rom-sql](https://github.com/rom-rb/rom-sql)
34
- * [rom-yesql](https://github.com/rom-rb/rom-yesql)
35
- * [rom-couchdb](https://github.com/rom-rb/rom-couchdb)
36
- * [rom-mongo](https://github.com/rom-rb/rom-mongo)
37
- * [rom-neo4j](https://github.com/rom-rb/rom-neo4j)
38
- * [rom-event_store](https://github.com/rom-rb/rom-event_store)
39
- * [rom-influxdb](https://github.com/rom-rb/rom-influxdb)
40
- * [rom-rethinkdb](https://github.com/rom-rb/rom-rethinkdb)
41
- * [rom-yaml](https://github.com/rom-rb/rom-yaml)
42
- * [rom-csv](https://github.com/rom-rb/rom-csv)
40
+ * [rom-couchdb](https://github.com/rom-rb/rom-couchdb)
41
+ * [rom-csv](https://github.com/rom-rb/rom-csv)
42
+ * [rom-cassandra](https://github.com/rom-rb/rom-cassandra)
43
+ * [rom-event_store](https://github.com/rom-rb/rom-event_store)
44
+ * [rom-git](https://github.com/rom-rb/rom-git)
45
+ * [rom-http](https://github.com/rom-rb/rom-http)
46
+ * [rom-influxdb](https://github.com/rom-rb/rom-influxdb)
47
+ * [rom-json](https://github.com/rom-rb/rom-json)
48
+ * [rom-kafka](https://github.com/rom-rb/rom-kafka)
49
+ * [rom-mongo](https://github.com/rom-rb/rom-mongo)
50
+ * [rom-neo4j](https://github.com/rom-rb/rom-neo4j)
51
+ * [rom-rethinkdb](https://github.com/rom-rb/rom-rethinkdb)
52
+ * [rom-sql](https://github.com/rom-rb/rom-sql)
53
+ * [rom-yaml](https://github.com/rom-rb/rom-yaml)
54
+ * [rom-yesql](https://github.com/rom-rb/rom-yesql)
43
55
 
44
56
  See [issues](https://github.com/rom-rb/rom/issues?q=is%3Aopen+is%3Aissue+label%3Aadapter+label%3Afeature)
45
57
  for a list of adapters that are planned to be added soon.
@@ -57,7 +69,8 @@ ROM is on its way towards 1.0.0. You can see an overview of tasks scheduled for
57
69
  ## Community
58
70
 
59
71
  * [Official Blog](http://rom-rb.org/blog/)
60
- * [Ruby Object Mapper](https://groups.google.com/forum/#!forum/rom-rb) mailing list
72
+ * [Discussion Forum](http://discourse.rom-rb.org)
73
+ * [Gitter Channel](https://gitter.im/rom-rb/chat)
61
74
 
62
75
  ## Credits
63
76
 
data/lib/rom.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'equalizer'
1
+ require 'dry-equalizer'
2
2
 
3
3
  require 'rom-support'
4
4
  require 'rom/version'
@@ -10,11 +10,10 @@ require 'rom/support/registry'
10
10
  require 'rom/support/options'
11
11
  require 'rom/support/class_macros'
12
12
  require 'rom/support/class_builder'
13
- require 'rom/support/guarded_inheritance_hook'
14
13
  require 'rom/support/inheritance_hook'
15
14
 
16
15
  # core parts
17
- require 'rom/environment_plugin'
16
+ require 'rom/configuration_plugin'
18
17
  require 'rom/plugin'
19
18
  require 'rom/relation'
20
19
  require 'rom-mapper'
@@ -23,40 +22,24 @@ require 'rom/commands'
23
22
  # rom Global
24
23
  require 'rom/global'
25
24
 
26
- # rom environments
27
- require 'rom/environment'
28
-
29
- # TODO: consider to make this part optional and don't require it here
30
- require 'rom/setup_dsl/setup'
25
+ # rom configurations
26
+ require 'rom/configuration'
31
27
 
32
28
  # container with registries
33
29
  require 'rom/container'
34
30
 
31
+ # container factory
32
+ require 'rom/create_container'
33
+
35
34
  # register core plugins
36
- require 'rom/environment_plugins/auto_registration'
35
+ require 'rom/plugins/configuration/configuration_dsl'
37
36
  require 'rom/plugins/relation/registry_reader'
38
37
 
39
38
  module ROM
40
39
  extend Global
41
40
 
42
- @environment = ROM::Environment.new
43
-
44
- class << self
45
- def method_missing(method, *args, &block)
46
- if @environment.respond_to?(method)
47
- @environment.__send__(method, *args, &block)
48
- else
49
- super
50
- end
51
- end
52
-
53
- def respond_to_missing?(method, _include_private = false)
54
- @environment.respond_to?(method) || super
55
- end
56
- end
57
-
58
41
  plugins do
59
- register :auto_registration, ROM::EnvironmentPlugins::AutoRegistration, type: :environment
42
+ register :macros, ROM::ConfigurationPlugins::ConfigurationDSL, type: :configuration
60
43
  register :registry_reader, ROM::Plugins::Relation::RegistryReader, type: :relation
61
44
  end
62
45
  end
data/lib/rom/command.rb CHANGED
@@ -1,130 +1,168 @@
1
- require 'rom/commands/abstract'
1
+ require 'rom/support/options'
2
+
3
+ require 'rom/commands/class_interface'
4
+ require 'rom/commands/composite'
5
+ require 'rom/commands/graph'
6
+ require 'rom/commands/lazy'
2
7
 
3
8
  module ROM
4
- # Base command class with factory class-level interface and setup-related logic
9
+ # Abstract command class
10
+ #
11
+ # Provides a constructor accepting relation with options and basic behavior
12
+ # for calling, currying and composing commands.
13
+ #
14
+ # Typically command subclasses should inherit from specialized
15
+ # Create/Update/Delete, not this one.
16
+ #
17
+ # @abstract
5
18
  #
6
19
  # @private
7
- class Command < Commands::Abstract
20
+ class Command
21
+ include Commands
22
+
8
23
  extend ClassMacros
9
- extend ROM::Support::GuardedInheritanceHook
24
+ extend ClassInterface
10
25
 
11
- include Equalizer.new(:relation, :options)
26
+ include Options
27
+ include Dry::Equalizer(:relation, :options)
12
28
 
13
29
  defines :adapter, :relation, :result, :input, :validator, :register_as
14
30
 
31
+ option :type, allow: [:create, :update, :delete]
32
+ option :source, reader: true
33
+ option :result, reader: true, allow: [:one, :many]
34
+ option :validator, reader: true
35
+ option :input, reader: true
36
+ option :curry_args, type: Array, reader: true, default: EMPTY_ARRAY
37
+
15
38
  input Hash
16
39
  validator proc {}
17
40
  result :many
18
41
 
19
- # Return adapter specific sub-class based on the adapter identifier
20
- #
21
- # This is a syntax sugar to make things consistent
22
- #
23
- # @example
24
- # ROM::Commands::Create[:memory]
25
- # # => ROM::Memory::Commands::Create
26
- #
27
- # @param [Symbol] adapter identifier
28
- #
29
- # @return [Class]
30
- #
31
- # @api public
32
- def self.[](adapter)
33
- adapter_namespace(adapter).const_get(Inflector.demodulize(name))
42
+ # @attr_reader [Relation] relation The command's relation
43
+ attr_reader :relation
44
+
45
+ # @api private
46
+ def initialize(relation, options = EMPTY_HASH)
47
+ super
48
+ @relation = relation
49
+ @source = options[:source] || relation
34
50
  end
35
51
 
36
- # Return namespaces that contains command subclasses of a specific adapter
52
+ # Execute the command
37
53
  #
38
- # @param [Symbol] adapter identifier
54
+ # @abstract
39
55
  #
40
- # @return [Module]
56
+ # @return [Array] an array with inserted tuples
41
57
  #
42
58
  # @api private
43
- def self.adapter_namespace(adapter)
44
- ROM.adapters.fetch(adapter).const_get(:Commands)
45
- rescue KeyError
46
- raise AdapterNotPresentError.new(adapter, :relation)
59
+ def execute(*)
60
+ raise(
61
+ NotImplementedError,
62
+ "#{self.class}##{__method__} must be implemented"
63
+ )
47
64
  end
48
65
 
49
- # Build a command class for a specific relation with options
50
- #
51
- # @example
52
- # class CreateUser < ROM::Commands::Create[:memory]
53
- # end
66
+ # Call the command and return one or many tuples
54
67
  #
55
- # command = CreateUser.build(rom.relations[:users])
68
+ # @api public
69
+ def call(*args)
70
+ tuples = execute(*(curry_args + args))
71
+
72
+ if one?
73
+ tuples.first
74
+ else
75
+ tuples
76
+ end
77
+ end
78
+ alias_method :[], :call
79
+
80
+ # Curry this command with provided args
56
81
  #
57
- # @param [Relation] relation
58
- # @param [Hash] options
82
+ # Curried command can be called without args
59
83
  #
60
84
  # @return [Command]
61
85
  #
62
86
  # @api public
63
- def self.build(relation, options = EMPTY_HASH)
64
- new(relation, self.options.merge(options))
87
+ def curry(*args)
88
+ if curry_args.empty? && args.first.is_a?(Graph::InputEvaluator)
89
+ Lazy[self].new(self, *args)
90
+ else
91
+ self.class.build(relation, options.merge(curry_args: args))
92
+ end
65
93
  end
94
+ alias_method :with, :curry
66
95
 
67
- # Use a configured plugin in this relation
96
+ # Compose a command with another one
97
+ #
98
+ # The other one will be called with the result from the first one
68
99
  #
69
100
  # @example
70
- # class CreateUser < ROM::Commands::Create[:memory]
71
- # use :pagintion
72
101
  #
73
- # per_page 30
74
- # end
102
+ # command = users.create.curry(name: 'Jane')
103
+ # command >>= tasks.create.curry(title: 'Task One')
104
+ #
105
+ # command.call # creates user, passes it to tasks and creates task
75
106
  #
76
- # @param [Symbol] plugin
77
- # @param [Hash] options
78
- # @option options [Symbol] :adapter (:default) first adapter to check for plugin
107
+ # @return [Composite]
79
108
  #
80
109
  # @api public
81
- def self.use(plugin, _options = EMPTY_HASH)
82
- ROM.plugin_registry.commands.fetch(plugin, adapter).apply_to(self)
110
+ def >>(other)
111
+ Composite.new(self, other)
112
+ end
113
+
114
+ # @api public
115
+ def combine(*others)
116
+ Graph.new(self, others)
83
117
  end
84
118
 
85
- # Build command registry hash for provided relations
86
- #
87
- # @param [RelationRegistry] relations registry
88
- # @param [Hash] gateways
89
- # @param [Array] descendants a list of command subclasses
90
- #
91
- # @return [Hash]
92
- #
93
119
  # @api private
94
- def self.registry(relations, gateways, descendants)
95
- descendants.each_with_object({}) do |klass, h|
96
- rel_name = klass.relation
120
+ def lazy?
121
+ false
122
+ end
97
123
 
98
- next unless rel_name
124
+ # @api private
125
+ def graph?
126
+ false
127
+ end
99
128
 
100
- relation = relations[rel_name]
101
- name = klass.register_as || klass.default_name
129
+ # @api private
130
+ def one?
131
+ result.equal?(:one)
132
+ end
102
133
 
103
- gateway = gateways[relation.class.gateway]
104
- gateway.extend_command_class(klass, relation.dataset)
134
+ # @api private
135
+ def many?
136
+ result.equal?(:many)
137
+ end
105
138
 
106
- (h[rel_name] ||= {})[name] = klass.build(relation)
139
+ # Assert that tuple count in the relation corresponds to :result
140
+ # setting
141
+ #
142
+ # @raise TupleCountMismatchError
143
+ #
144
+ # @api private
145
+ def assert_tuple_count
146
+ if one? && tuple_count > 1
147
+ raise TupleCountMismatchError, "#{inspect} expects one tuple"
107
148
  end
108
149
  end
109
150
 
110
- # Return default name of the command class based on its name
151
+ # Return number of tuples in the relation relation
111
152
  #
112
- # During setup phase this is used by defalut as `register_as` option
153
+ # This should be overridden by gateways when `#count` is not available
154
+ # in the relation objects
113
155
  #
114
- # @return [Symbol]
156
+ # @return [Fixnum]
115
157
  #
116
158
  # @api private
117
- def self.default_name
118
- Inflector.underscore(Inflector.demodulize(name)).to_sym
159
+ def tuple_count
160
+ relation.count
119
161
  end
120
162
 
121
- # Return default options based on class macros
122
- #
123
- # @return [Hash]
124
- #
125
163
  # @api private
126
- def self.options
127
- { input: input, validator: validator, result: result }
164
+ def new(new_relation)
165
+ self.class.build(new_relation, options.merge(source: relation))
128
166
  end
129
167
  end
130
168
  end