rom 0.9.1 → 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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