rom-core 4.0.0.beta3 → 4.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -1
  3. data/lib/rom/association_set.rb +3 -0
  4. data/lib/rom/associations/abstract.rb +72 -1
  5. data/lib/rom/associations/definitions/abstract.rb +22 -6
  6. data/lib/rom/associations/definitions/many_to_many.rb +3 -0
  7. data/lib/rom/associations/definitions/many_to_one.rb +1 -0
  8. data/lib/rom/associations/definitions/one_to_many.rb +1 -0
  9. data/lib/rom/associations/definitions/one_to_one.rb +1 -0
  10. data/lib/rom/associations/definitions/one_to_one_through.rb +1 -0
  11. data/lib/rom/associations/many_to_many.rb +44 -0
  12. data/lib/rom/associations/many_to_one.rb +26 -0
  13. data/lib/rom/associations/one_to_many.rb +26 -0
  14. data/lib/rom/associations/one_to_one.rb +3 -0
  15. data/lib/rom/associations/one_to_one_through.rb +3 -0
  16. data/lib/rom/attribute.rb +2 -2
  17. data/lib/rom/auto_curry.rb +11 -0
  18. data/lib/rom/cache.rb +29 -0
  19. data/lib/rom/command_compiler.rb +4 -4
  20. data/lib/rom/command_registry.rb +9 -5
  21. data/lib/rom/commands/class_interface.rb +7 -7
  22. data/lib/rom/commands/graph/input_evaluator.rb +33 -3
  23. data/lib/rom/commands/lazy.rb +4 -0
  24. data/lib/rom/commands/lazy/create.rb +10 -0
  25. data/lib/rom/commands/lazy/delete.rb +10 -0
  26. data/lib/rom/commands/lazy/update.rb +10 -0
  27. data/lib/rom/configuration.rb +34 -14
  28. data/lib/rom/configuration_dsl.rb +0 -2
  29. data/lib/rom/constants.rb +10 -0
  30. data/lib/rom/container.rb +16 -0
  31. data/lib/rom/create_container.rb +7 -0
  32. data/lib/rom/environment.rb +3 -2
  33. data/lib/rom/gateway.rb +16 -1
  34. data/lib/rom/global.rb +1 -1
  35. data/lib/rom/global/plugin_dsl.rb +3 -1
  36. data/lib/rom/initializer.rb +25 -13
  37. data/lib/rom/mapper_registry.rb +4 -1
  38. data/lib/rom/memory/dataset.rb +29 -2
  39. data/lib/rom/memory/schema.rb +7 -0
  40. data/lib/rom/plugin_base.rb +1 -1
  41. data/lib/rom/plugin_registry.rb +2 -2
  42. data/lib/rom/plugins/command/schema.rb +7 -0
  43. data/lib/rom/plugins/relation/instrumentation.rb +10 -0
  44. data/lib/rom/plugins/relation/registry_reader.rb +0 -3
  45. data/lib/rom/registry.rb +15 -3
  46. data/lib/rom/relation.rb +38 -23
  47. data/lib/rom/relation/class_interface.rb +15 -6
  48. data/lib/rom/relation/combined.rb +7 -2
  49. data/lib/rom/relation/curried.rb +23 -0
  50. data/lib/rom/relation/graph.rb +25 -14
  51. data/lib/rom/relation/loaded.rb +7 -4
  52. data/lib/rom/relation/materializable.rb +2 -2
  53. data/lib/rom/relation/view_dsl.rb +2 -1
  54. data/lib/rom/relation/wrap.rb +14 -0
  55. data/lib/rom/relation_registry.rb +2 -0
  56. data/lib/rom/schema.rb +25 -4
  57. data/lib/rom/schema/associations_dsl.rb +9 -0
  58. data/lib/rom/schema/dsl.rb +27 -4
  59. data/lib/rom/setup.rb +20 -7
  60. data/lib/rom/setup/auto_registration.rb +27 -0
  61. data/lib/rom/setup/auto_registration_strategies/base.rb +7 -2
  62. data/lib/rom/setup/auto_registration_strategies/custom_namespace.rb +17 -0
  63. data/lib/rom/setup/auto_registration_strategies/no_namespace.rb +11 -0
  64. data/lib/rom/setup/auto_registration_strategies/with_namespace.rb +9 -0
  65. data/lib/rom/setup/finalize/finalize_mappers.rb +4 -2
  66. data/lib/rom/setup/finalize/finalize_relations.rb +1 -1
  67. data/lib/rom/support/configurable.rb +19 -0
  68. data/lib/rom/support/notifications.rb +29 -2
  69. data/lib/rom/types.rb +53 -8
  70. data/lib/rom/version.rb +1 -1
  71. metadata +7 -13
@@ -2,17 +2,35 @@ require 'rom/associations/abstract'
2
2
 
3
3
  module ROM
4
4
  module Associations
5
+ # Abstract one-to-many association
6
+ #
7
+ # @api public
5
8
  class OneToMany < Abstract
9
+ # Adapters must implement this method
10
+ #
11
+ # @abstract
12
+ #
6
13
  # @api public
7
14
  def call(*)
8
15
  raise NotImplementedError
9
16
  end
10
17
 
18
+ # Return configured or inferred FK name
19
+ #
20
+ # @return [Symbol]
21
+ #
11
22
  # @api public
12
23
  def foreign_key
13
24
  definition.foreign_key || target.foreign_key(source.name)
14
25
  end
15
26
 
27
+ # Associate child tuple with a parent
28
+ #
29
+ # @param [Hash] child The child tuple
30
+ # @param [Hash] parent The parent tuple
31
+ #
32
+ # @return [Hash]
33
+ #
16
34
  # @api private
17
35
  def associate(child, parent)
18
36
  pk, fk = join_key_map
@@ -21,11 +39,19 @@ module ROM
21
39
 
22
40
  protected
23
41
 
42
+ # Return primary key on the source side
43
+ #
44
+ # @return [Symbol]
45
+ #
24
46
  # @api protected
25
47
  def source_key
26
48
  source.schema.primary_key_name
27
49
  end
28
50
 
51
+ # Return foreign key name on the target side
52
+ #
53
+ # @return [Symbol]
54
+ #
29
55
  # @api protected
30
56
  def target_key
31
57
  foreign_key
@@ -2,6 +2,9 @@ require 'rom/associations/one_to_many'
2
2
 
3
3
  module ROM
4
4
  module Associations
5
+ # Abstract one-to-one association type
6
+ #
7
+ # @api public
5
8
  class OneToOne < OneToMany
6
9
  end
7
10
  end
@@ -2,6 +2,9 @@ require 'rom/associations/many_to_many'
2
2
 
3
3
  module ROM
4
4
  module Associations
5
+ # Abstract one-to-one-through association type
6
+ #
7
+ # @api public
5
8
  class OneToOneThrough < ManyToMany
6
9
  end
7
10
  end
data/lib/rom/attribute.rb CHANGED
@@ -20,7 +20,7 @@ module ROM
20
20
  extend Initializer
21
21
 
22
22
  # @!attribute [r] type
23
- # @return [Dry::Types::Definition, Dry::Types::Sum, Dry::Types::Constrained]
23
+ # @return [Dry::Types::Definition, Dry::Types::Sum, Dry::Types::Constrained] The attribute's type object
24
24
  param :type
25
25
 
26
26
  # @api private
@@ -336,7 +336,7 @@ module ROM
336
336
 
337
337
  # Check if the attribute type is equal to another
338
338
  #
339
- # @param [Dry::Type, Attribute]
339
+ # @param [Dry::Type, Attribute] other
340
340
  #
341
341
  # @return [TrueClass,FalseClass]
342
342
  #
@@ -1,4 +1,7 @@
1
1
  module ROM
2
+ # Relation extension which provides auto-currying of relation view methods
3
+ #
4
+ # @api private
2
5
  module AutoCurry
3
6
  def self.extended(klass)
4
7
  klass.define_singleton_method(:method_added) do |name|
@@ -8,6 +11,7 @@ module ROM
8
11
  end
9
12
  end
10
13
 
14
+ # @api private
11
15
  def auto_curry_guard
12
16
  @__auto_curry_busy__ = true
13
17
  yield
@@ -15,14 +19,21 @@ module ROM
15
19
  @__auto_curry_busy__ = false
16
20
  end
17
21
 
22
+ # @api private
18
23
  def auto_curry_busy?
19
24
  @__auto_curry_busy__ ||= false
20
25
  end
21
26
 
27
+ # @api private
22
28
  def auto_curried_methods
23
29
  @__auto_curried_methods__ ||= Set.new
24
30
  end
25
31
 
32
+ # Auto-curry a method
33
+ #
34
+ # @param [Symbol] name The name of a method
35
+ #
36
+ # @api private
26
37
  def auto_curry(name, &block)
27
38
  arity = instance_method(name).arity
28
39
 
data/lib/rom/cache.rb CHANGED
@@ -1,27 +1,45 @@
1
1
  require 'concurrent/map'
2
2
 
3
3
  module ROM
4
+ # Thread-safe cache used by various rom components
5
+ #
4
6
  # @api private
5
7
  class Cache
6
8
  attr_reader :objects
7
9
 
10
+ # @api private
8
11
  class Namespaced
12
+ # @api private
9
13
  attr_reader :cache
10
14
 
15
+ # @api private
11
16
  attr_reader :namespace
12
17
 
18
+ # @api private
13
19
  def initialize(cache, namespace)
14
20
  @cache = cache
15
21
  @namespace = namespace.to_sym
16
22
  end
17
23
 
24
+ # @api private
18
25
  def [](key)
19
26
  cache[[namespace, key].hash]
20
27
  end
21
28
 
29
+ # @api private
22
30
  def fetch_or_store(*args, &block)
23
31
  cache.fetch_or_store([namespace, args.hash].hash, &block)
24
32
  end
33
+
34
+ # @api private
35
+ def size
36
+ cache.size
37
+ end
38
+
39
+ # @api private
40
+ def inspect
41
+ %(#<#{self.class} size=#{size}>)
42
+ end
25
43
  end
26
44
 
27
45
  # @api private
@@ -39,8 +57,19 @@ module ROM
39
57
  objects.fetch_or_store(args.hash, &block)
40
58
  end
41
59
 
60
+ # @api private
61
+ def size
62
+ objects.size
63
+ end
64
+
65
+ # @api private
42
66
  def namespaced(namespace)
43
67
  @namespaced[namespace] ||= Namespaced.new(objects, namespace)
44
68
  end
69
+
70
+ # @api private
71
+ def inspect
72
+ %(#<#{self.class} size=#{size} namespaced=#{@namespaced.inspect}>)
73
+ end
45
74
  end
46
75
  end
@@ -23,15 +23,15 @@ module ROM
23
23
  end
24
24
 
25
25
  # @!attribute [r] gateways
26
- # @return [ROM::Registry]
26
+ # @return [ROM::Registry] Gateways used for command extensions
27
27
  param :gateways
28
28
 
29
29
  # @!attribute [r] relations
30
- # @return [ROM::RelationRegistry]
30
+ # @return [ROM::RelationRegistry] Relations used with a given compiler
31
31
  param :relations
32
32
 
33
- # @!attribute [r] relations
34
- # @return [ROM::Registry]
33
+ # @!attribute [r] commands
34
+ # @return [ROM::Registry] Command registries with custom commands
35
35
  param :commands
36
36
 
37
37
  # @!attribute [r] notifications
@@ -15,19 +15,23 @@ module ROM
15
15
  # @api private
16
16
  param :elements
17
17
 
18
- # Name of the relation from which commands are under
19
- #
20
- # @return [String]
21
- #
22
- # @api private
18
+ # @!attribute [r] relation_name
19
+ # @return [Relation::Name] The name of a relation
23
20
  option :relation_name
24
21
 
22
+ # @!attribute [r] mappers
23
+ # @return [MapperRegistry] Optional mapper registry
25
24
  option :mappers, optional: true
26
25
 
26
+ # @!attribute [r] mapper
27
+ # @return [Object#call] Default mapper for processing command results
27
28
  option :mapper, optional: true
28
29
 
30
+ # @!attribute [r] compiler
31
+ # @return [CommandCompiler] A command compiler instance
29
32
  option :compiler, optional: true
30
33
 
34
+ # @api private
31
35
  def self.element_not_found_error
32
36
  CommandNotFoundError
33
37
  end
@@ -75,12 +75,12 @@ module ROM
75
75
 
76
76
  # Create a command class with a specific type
77
77
  #
78
- # @param [Symbol] command name
79
- # @param [Class] parent class
78
+ # @param [Symbol] name Command name
79
+ # @param [Class] type Command class
80
80
  #
81
- # @yield [Class] create class
81
+ # @yield [Class]
82
82
  #
83
- # @return [Class, Object] return result of the block if it was provided
83
+ # @return [Class, Object]
84
84
  #
85
85
  # @api public
86
86
  def create_class(name, type, &block)
@@ -105,8 +105,8 @@ module ROM
105
105
  # end
106
106
  #
107
107
  # @param [Symbol] plugin
108
- # @param [Hash] options
109
- # @option options [Symbol] :adapter (:default) first adapter to check for plugin
108
+ # @param [Hash] _options
109
+ # @option _options [Symbol] :adapter (:default) first adapter to check for plugin
110
110
  #
111
111
  # @api public
112
112
  def use(plugin, _options = EMPTY_HASH)
@@ -115,7 +115,7 @@ module ROM
115
115
 
116
116
  # Extend a command class with relation view methods
117
117
  #
118
- # @param [Relation]
118
+ # @param [Relation] relation
119
119
  #
120
120
  # @return [Class]
121
121
  #
@@ -1,19 +1,37 @@
1
1
  module ROM
2
2
  module Commands
3
3
  class Graph
4
+ # Evaluator for lazy commands which extracts values for commands from nested hashes
5
+ #
6
+ # @api private
4
7
  class InputEvaluator
5
8
  include Dry::Equalizer(:tuple_path, :excluded_keys)
6
9
 
10
+ # @!attribute [r] tuple_path
11
+ # @return [Array<Symbol>] A list of keys pointing to a value inside a hash
7
12
  attr_reader :tuple_path
8
13
 
14
+ # @!attribute [r] excluded_keys
15
+ # @return [Array<Symbol>] A list of keys that should be excluded
9
16
  attr_reader :excluded_keys
10
17
 
18
+ # @!attribute [r] exclude_proc
19
+ # @return [Array<Symbol>] A function that should determine which keys should be excluded
11
20
  attr_reader :exclude_proc
12
21
 
22
+ # Build an input evaluator
23
+ #
24
+ # @param [Array<Symbol>] tuple_path The tuple path
25
+ # @param [Array] nodes
26
+ #
27
+ # @return [InputEvaluator]
28
+ #
29
+ # @api private
13
30
  def self.build(tuple_path, nodes)
14
31
  new(tuple_path, extract_excluded_keys(nodes))
15
32
  end
16
33
 
34
+ # @api private
17
35
  def self.extract_excluded_keys(nodes)
18
36
  return unless nodes
19
37
 
@@ -24,19 +42,31 @@ module ROM
24
42
  .reject { |item| item.is_a?(Array) }
25
43
  end
26
44
 
45
+ # Return default exclude_proc
46
+ #
47
+ # @api private
27
48
  def self.exclude_proc(excluded_keys)
28
49
  -> input { input.reject { |k, _| excluded_keys.include?(k) } }
29
50
  end
30
51
 
52
+ # Initialize a new input evaluator
53
+ #
54
+ # @return [InputEvaluator]
55
+ #
56
+ # @api private
31
57
  def initialize(tuple_path, excluded_keys)
32
58
  @tuple_path = tuple_path
33
59
  @excluded_keys = excluded_keys
34
60
  @exclude_proc = self.class.exclude_proc(excluded_keys)
35
61
  end
36
62
 
37
- def call(*args)
38
- input, index = args
39
-
63
+ # Evaluate input hash
64
+ #
65
+ # @param [Hash] input The input hash
66
+ # @param [Integer] index Optional index
67
+ #
68
+ # @return [Hash]
69
+ def call(input, index = nil)
40
70
  value =
41
71
  begin
42
72
  if index
@@ -57,8 +57,12 @@ module ROM
57
57
  Composite.new(self, other)
58
58
  end
59
59
 
60
+ # Combine with other lazy commands
61
+ #
60
62
  # @see Abstract#combine
61
63
  #
64
+ # @return [Graph]
65
+ #
62
66
  # @api public
63
67
  def combine(*others)
64
68
  Graph.new(self, others)
@@ -1,7 +1,17 @@
1
1
  module ROM
2
2
  module Commands
3
3
  class Lazy
4
+ # Lazy command wrapper for create commands
5
+ #
6
+ # @api public
4
7
  class Create < Lazy
8
+ # Execute a command
9
+ #
10
+ # @see Command::Create#call
11
+ #
12
+ # @return [Hash,Array<Hash>]
13
+ #
14
+ # @api public
5
15
  def call(*args)
6
16
  first = args.first
7
17
  last = args.last
@@ -1,7 +1,17 @@
1
1
  module ROM
2
2
  module Commands
3
3
  class Lazy
4
+ # Lazy command wrapper for delete commands
5
+ #
6
+ # @api public
4
7
  class Delete < Lazy
8
+ # Execute a lazy delete command
9
+ #
10
+ # @see Commands::Delete#call
11
+ #
12
+ # @return [Hash, Array<Hash>]
13
+ #
14
+ # @api public
5
15
  def call(*args)
6
16
  first = args.first
7
17
  last = args.last
@@ -1,7 +1,17 @@
1
1
  module ROM
2
2
  module Commands
3
3
  class Lazy
4
+ # Lazy command wrapper for update commands
5
+ #
6
+ # @api public
4
7
  class Update < Lazy
8
+ # Execute a lazy update command
9
+ #
10
+ # @see Commands::Update#call
11
+ #
12
+ # @return [Hash, Array<Hash>]
13
+ #
14
+ # @api public
5
15
  def call(*args)
6
16
  first = args.first
7
17
  last = args.last
@@ -22,7 +22,17 @@ module ROM
22
22
 
23
23
  NoDefaultAdapterError = Class.new(StandardError)
24
24
 
25
- attr_reader :environment, :setup, :notifications
25
+ # @!attribute [r] environment
26
+ # @return [Environment] Environment object with gateways
27
+ attr_reader :environment
28
+
29
+ # @!attribute [r] setup
30
+ # @return [Setup] Setup object which collects component classes and plugins
31
+ attr_reader :setup
32
+
33
+ # @!attribute [r] notifications
34
+ # @return [Notifications] Notification bus instance
35
+ attr_reader :notifications
26
36
 
27
37
  def_delegators :@setup, :register_relation, :register_command, :register_mapper, :register_plugin,
28
38
  :command_classes, :mapper_classes,
@@ -30,7 +40,13 @@ module ROM
30
40
 
31
41
  def_delegators :@environment, :gateways, :gateways_map, :configure, :config
32
42
 
33
- # @api public
43
+ # Initialize a new configuration
44
+ #
45
+ # @see Environment#initialize
46
+ #
47
+ # @return [Configuration]
48
+ #
49
+ # @api private
34
50
  def initialize(*args, &block)
35
51
  @environment = Environment.new(*args)
36
52
  @notifications = Notifications.event_bus(:configuration)
@@ -38,13 +54,15 @@ module ROM
38
54
 
39
55
  use :mappers # enable mappers by default
40
56
 
41
- block.call(self) unless block.nil?
57
+ block.call(self) if block
42
58
  end
43
59
 
44
60
  # Apply a plugin to the configuration
45
61
  #
46
- # @param [Mixed] The plugin identifier, usually a Symbol
47
- # @param [Hash] Plugin options
62
+ # @param [Mixed] plugin The plugin identifier, usually a Symbol
63
+ # @param [Hash] options Plugin options
64
+ #
65
+ # @return [Configuration]
48
66
  #
49
67
  # @api public
50
68
  def use(plugin, options = {})
@@ -68,15 +86,6 @@ module ROM
68
86
  gateways.fetch(name)
69
87
  end
70
88
 
71
- # Returns gateway if method is a name of a registered gateway
72
- #
73
- # @return [Gateway]
74
- #
75
- # @api private
76
- def method_missing(name, *)
77
- gateways.fetch(name) { super }
78
- end
79
-
80
89
  # Hook for respond_to? used internally
81
90
  #
82
91
  # @api private
@@ -110,5 +119,16 @@ module ROM
110
119
  def default_adapter
111
120
  @default_adapter ||= adapter_for_gateway(default_gateway) || ROM.adapters.keys.first
112
121
  end
122
+
123
+ private
124
+
125
+ # Returns gateway if method is a name of a registered gateway
126
+ #
127
+ # @return [Gateway]
128
+ #
129
+ # @api private
130
+ def method_missing(name, *)
131
+ gateways.fetch(name) { super }
132
+ end
113
133
  end
114
134
  end