rom 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +81 -0
  3. data/.travis.yml +2 -1
  4. data/CHANGELOG.md +41 -0
  5. data/Gemfile +12 -8
  6. data/Guardfile +17 -11
  7. data/README.md +7 -7
  8. data/Rakefile +29 -0
  9. data/lib/rom.rb +9 -66
  10. data/lib/rom/adapter.rb +45 -12
  11. data/lib/rom/adapter/memory.rb +0 -4
  12. data/lib/rom/adapter/memory/commands.rb +0 -10
  13. data/lib/rom/adapter/memory/dataset.rb +18 -6
  14. data/lib/rom/adapter/memory/storage.rb +0 -3
  15. data/lib/rom/command_registry.rb +24 -43
  16. data/lib/rom/commands.rb +5 -6
  17. data/lib/rom/commands/create.rb +5 -5
  18. data/lib/rom/commands/delete.rb +8 -6
  19. data/lib/rom/commands/result.rb +82 -0
  20. data/lib/rom/commands/update.rb +5 -4
  21. data/lib/rom/commands/with_options.rb +1 -4
  22. data/lib/rom/config.rb +70 -0
  23. data/lib/rom/env.rb +11 -3
  24. data/lib/rom/global.rb +107 -0
  25. data/lib/rom/header.rb +122 -89
  26. data/lib/rom/header/attribute.rb +148 -0
  27. data/lib/rom/mapper.rb +46 -67
  28. data/lib/rom/mapper_builder.rb +20 -73
  29. data/lib/rom/mapper_builder/mapper_dsl.rb +114 -0
  30. data/lib/rom/mapper_builder/model_dsl.rb +29 -0
  31. data/lib/rom/mapper_registry.rb +21 -0
  32. data/lib/rom/model_builder.rb +11 -17
  33. data/lib/rom/processor.rb +28 -0
  34. data/lib/rom/processor/transproc.rb +105 -0
  35. data/lib/rom/reader.rb +81 -21
  36. data/lib/rom/reader_builder.rb +14 -4
  37. data/lib/rom/relation.rb +19 -5
  38. data/lib/rom/relation_builder.rb +20 -6
  39. data/lib/rom/repository.rb +0 -2
  40. data/lib/rom/setup.rb +156 -0
  41. data/lib/rom/{boot → setup}/base_relation_dsl.rb +4 -8
  42. data/lib/rom/setup/command_dsl.rb +46 -0
  43. data/lib/rom/setup/finalize.rb +125 -0
  44. data/lib/rom/setup/mapper_dsl.rb +19 -0
  45. data/lib/rom/{boot → setup}/relation_dsl.rb +1 -4
  46. data/lib/rom/setup/schema_dsl.rb +33 -0
  47. data/lib/rom/support/registry.rb +10 -6
  48. data/lib/rom/version.rb +1 -1
  49. data/rom.gemspec +3 -1
  50. data/spec/integration/adapters/extending_relations_spec.rb +0 -2
  51. data/spec/integration/commands/create_spec.rb +2 -9
  52. data/spec/integration/commands/delete_spec.rb +4 -5
  53. data/spec/integration/commands/error_handling_spec.rb +4 -3
  54. data/spec/integration/commands/update_spec.rb +3 -8
  55. data/spec/integration/mappers/deep_embedded_spec.rb +52 -0
  56. data/spec/integration/mappers/definition_dsl_spec.rb +0 -118
  57. data/spec/integration/mappers/embedded_spec.rb +82 -0
  58. data/spec/integration/mappers/group_spec.rb +170 -0
  59. data/spec/integration/mappers/prefixing_attributes_spec.rb +2 -2
  60. data/spec/integration/mappers/renaming_attributes_spec.rb +8 -6
  61. data/spec/integration/mappers/symbolizing_attributes_spec.rb +80 -0
  62. data/spec/integration/mappers/wrap_spec.rb +162 -0
  63. data/spec/integration/multi_repo_spec.rb +64 -0
  64. data/spec/integration/relations/reading_spec.rb +12 -8
  65. data/spec/integration/relations/registry_dsl_spec.rb +1 -3
  66. data/spec/integration/schema_spec.rb +10 -0
  67. data/spec/integration/setup_spec.rb +57 -6
  68. data/spec/spec_helper.rb +2 -1
  69. data/spec/unit/config_spec.rb +60 -0
  70. data/spec/unit/rom/adapter/memory/dataset_spec.rb +52 -0
  71. data/spec/unit/rom/adapter_spec.rb +31 -11
  72. data/spec/unit/rom/header_spec.rb +60 -16
  73. data/spec/unit/rom/mapper_builder_spec.rb +311 -0
  74. data/spec/unit/rom/mapper_registry_spec.rb +25 -0
  75. data/spec/unit/rom/mapper_spec.rb +4 -5
  76. data/spec/unit/rom/model_builder_spec.rb +15 -13
  77. data/spec/unit/rom/processor/transproc_spec.rb +331 -0
  78. data/spec/unit/rom/reader_spec.rb +73 -0
  79. data/spec/unit/rom/registry_spec.rb +38 -0
  80. data/spec/unit/rom/relation_spec.rb +0 -1
  81. data/spec/unit/rom/setup_spec.rb +55 -0
  82. data/spec/unit/rom_spec.rb +14 -0
  83. metadata +62 -22
  84. data/Gemfile.devtools +0 -71
  85. data/lib/rom/boot.rb +0 -197
  86. data/lib/rom/boot/command_dsl.rb +0 -48
  87. data/lib/rom/boot/dsl.rb +0 -37
  88. data/lib/rom/boot/mapper_dsl.rb +0 -23
  89. data/lib/rom/boot/schema_dsl.rb +0 -27
  90. data/lib/rom/ra.rb +0 -172
  91. data/lib/rom/ra/operation/group.rb +0 -47
  92. data/lib/rom/ra/operation/join.rb +0 -39
  93. data/lib/rom/ra/operation/wrap.rb +0 -45
  94. data/lib/rom/transformer.rb +0 -77
  95. data/spec/integration/ra/group_spec.rb +0 -46
  96. data/spec/integration/ra/join_spec.rb +0 -50
  97. data/spec/integration/ra/wrap_spec.rb +0 -37
  98. data/spec/unit/rom/ra/operation/group_spec.rb +0 -55
  99. data/spec/unit/rom/ra/operation/wrap_spec.rb +0 -29
  100. data/spec/unit/rom/transformer_spec.rb +0 -41
@@ -4,7 +4,6 @@ require 'rom/adapter/memory/commands'
4
4
 
5
5
  module ROM
6
6
  class Adapter
7
-
8
7
  class Memory < Adapter
9
8
  attr_accessor :logger
10
9
 
@@ -28,9 +27,6 @@ module ROM
28
27
  def [](name)
29
28
  connection[name]
30
29
  end
31
-
32
- Adapter.register(self)
33
30
  end
34
-
35
31
  end
36
32
  end
@@ -1,41 +1,31 @@
1
1
  module ROM
2
2
  class Adapter
3
3
  class Memory < Adapter
4
-
5
4
  module Commands
6
-
7
5
  class Create < ROM::Commands::Create
8
-
9
6
  def execute(tuple)
10
7
  attributes = input[tuple]
11
8
  validator.call(attributes)
12
9
  [relation.insert(attributes.to_h).to_a.last]
13
10
  end
14
-
15
11
  end
16
12
 
17
13
  class Update < ROM::Commands::Update
18
-
19
14
  def execute(params)
20
15
  attributes = input[params]
21
16
  validator.call(attributes)
22
17
  relation.map { |tuple| tuple.update(attributes.to_h) }
23
18
  end
24
-
25
19
  end
26
20
 
27
21
  class Delete < ROM::Commands::Delete
28
-
29
22
  def execute
30
23
  tuples = target.to_a
31
24
  tuples.each { |tuple| relation.delete(tuple) }
32
25
  tuples
33
26
  end
34
-
35
27
  end
36
-
37
28
  end
38
-
39
29
  end
40
30
  end
41
31
  end
@@ -1,7 +1,6 @@
1
1
  module ROM
2
2
  class Adapter
3
3
  class Memory < Adapter
4
-
5
4
  class Dataset
6
5
  include Charlatan.new(:data)
7
6
 
@@ -22,16 +21,31 @@ module ROM
22
21
  data.each(&block)
23
22
  end
24
23
 
25
- def restrict(criteria = nil, &block)
24
+ def join(*args)
25
+ left, right = args.size > 1 ? args : [self, args.first]
26
+
27
+ join_map = left.to_a.each_with_object({}) { |tuple, h|
28
+ others = right.to_a.find_all { |t| (tuple.to_a & t.to_a).any? }
29
+ (h[tuple] ||= []).concat(others)
30
+ }
31
+
32
+ tuples = left.map { |tuple|
33
+ join_map[tuple].map { |other| tuple.merge(other) }
34
+ }.flatten
35
+
36
+ self.class.new(tuples, left.header + right.header)
37
+ end
38
+
39
+ def restrict(criteria = nil)
26
40
  if criteria
27
- find_all { |tuple| criteria.all? { |k, v| tuple[k] == v } }
41
+ find_all { |tuple| criteria.all? { |k, v| tuple[k].eql?(v) } }
28
42
  else
29
43
  find_all { |tuple| yield(tuple) }
30
44
  end
31
45
  end
32
46
 
33
47
  def project(*names)
34
- map { |tuple| tuple.reject { |key,_| names.include?(key) } }
48
+ map { |tuple| tuple.reject { |key| !names.include?(key) } }
35
49
  end
36
50
 
37
51
  def order(*names)
@@ -47,9 +61,7 @@ module ROM
47
61
  data.delete(tuple)
48
62
  self
49
63
  end
50
-
51
64
  end
52
-
53
65
  end
54
66
  end
55
67
  end
@@ -1,7 +1,6 @@
1
1
  module ROM
2
2
  class Adapter
3
3
  class Memory < Adapter
4
-
5
4
  class Storage
6
5
  attr_reader :data
7
6
 
@@ -21,9 +20,7 @@ module ROM
21
20
  def key?(name)
22
21
  data.key?(name)
23
22
  end
24
-
25
23
  end
26
-
27
24
  end
28
25
  end
29
26
  end
@@ -1,50 +1,21 @@
1
- module ROM
2
-
3
- class Result
4
- attr_reader :value, :error
5
-
6
- def to_ary
7
- raise NotImplementedError
8
- end
9
- alias_method :to_a, :to_ary
10
-
11
- class Success < Result
12
- def initialize(value)
13
- @value = value
14
- end
15
-
16
- def >(f)
17
- f.call(value)
18
- end
19
-
20
- def to_ary
21
- value
22
- end
23
- alias_method :to_a, :to_ary
24
- end
25
-
26
- class Failure < Result
27
- def initialize(error)
28
- @error = error
29
- end
30
-
31
- def >(f)
32
- self
33
- end
34
-
35
- def to_ary
36
- error
37
- end
38
- end
39
- end
1
+ require 'rom/commands/result'
40
2
 
3
+ module ROM
4
+ # Command registry exposes "try" interface for executing commands
5
+ #
6
+ # @public
41
7
  class CommandRegistry < Registry
42
-
43
8
  class Evaluator
44
9
  include Concord.new(:registry)
45
10
 
46
11
  private
47
12
 
13
+ # Call a command when method is matching command name
14
+ #
15
+ # TODO: this will be replaced by explicit definition of methods for all
16
+ # registered commands
17
+ #
18
+ # @api public
48
19
  def method_missing(name, *args, &block)
49
20
  command = registry[name]
50
21
 
@@ -58,11 +29,21 @@ module ROM
58
29
  end
59
30
  end
60
31
 
32
+ # Try to execute a command in a block
33
+ #
34
+ # @example
35
+ #
36
+ # rom.command(:users).try { create(name: 'Jane') }
37
+ # rom.command(:users).try { update(:by_id, 1).set(name: 'Jane Doe') }
38
+ # rom.command(:users).try { delete(:by_id, 1) }
39
+ #
40
+ # @return [Commands::Result]
41
+ #
42
+ # @api public
61
43
  def try(&f)
62
- Result::Success.new(Evaluator.new(self).instance_exec(&f))
44
+ Commands::Result::Success.new(Evaluator.new(self).instance_exec(&f))
63
45
  rescue CommandError => e
64
- Result::Failure.new(e)
46
+ Commands::Result::Failure.new(e)
65
47
  end
66
48
  end
67
-
68
49
  end
@@ -1,6 +1,5 @@
1
1
  module ROM
2
2
  module Commands
3
-
4
3
  class AbstractCommand
5
4
  VALID_RESULTS = [:one, :many].freeze
6
5
 
@@ -13,7 +12,7 @@ module ROM
13
12
 
14
13
  @result = options[:result] || :many
15
14
 
16
- if !VALID_RESULTS.include?(result)
15
+ unless VALID_RESULTS.include?(result)
17
16
  raise InvalidOptionError.new(:result, VALID_RESULTS)
18
17
  end
19
18
  end
@@ -34,7 +33,8 @@ module ROM
34
33
  # Target relation on which the command will operate
35
34
  #
36
35
  # By default this is set to the relation that's passed to the constructor.
37
- # Specialized commands like Delete may set the target to a different relation.
36
+ # Specialized commands like Delete may set the target to a different
37
+ # relation.
38
38
  #
39
39
  # @return [Relation]
40
40
  #
@@ -43,7 +43,8 @@ module ROM
43
43
  relation
44
44
  end
45
45
 
46
- # Assert that tuple count in the target relation corresponds to :result setting
46
+ # Assert that tuple count in the target relation corresponds to :result
47
+ # setting
47
48
  #
48
49
  # @raises TupleCountMismatchError
49
50
  #
@@ -53,9 +54,7 @@ module ROM
53
54
  raise TupleCountMismatchError, "#{inspect} expects one tuple"
54
55
  end
55
56
  end
56
-
57
57
  end
58
-
59
58
  end
60
59
  end
61
60
 
@@ -2,7 +2,6 @@ require 'rom/commands/with_options'
2
2
 
3
3
  module ROM
4
4
  module Commands
5
-
6
5
  # Create command
7
6
  #
8
7
  # This command inserts a new tuple into a relation
@@ -18,11 +17,12 @@ module ROM
18
17
  # @return [Array] an array with inserted tuples
19
18
  #
20
19
  # @api private
21
- def execute(tuple)
22
- raise NotImplementedError, "#{self.class}##{__method__} must be implemented"
20
+ def execute(_tuple)
21
+ raise(
22
+ NotImplementedError,
23
+ "#{self.class}##{__method__} must be implemented"
24
+ )
23
25
  end
24
-
25
26
  end
26
-
27
27
  end
28
28
  end
@@ -1,6 +1,5 @@
1
1
  module ROM
2
2
  module Commands
3
-
4
3
  # Delete command
5
4
  #
6
5
  # This command removes tuples from its target relation
@@ -28,17 +27,20 @@ module ROM
28
27
  #
29
28
  # @api private
30
29
  def execute
31
- raise NotImplementedError, "#{self.class}##{__method__} must be implemented"
30
+ raise(
31
+ NotImplementedError,
32
+ "#{self.class}##{__method__} must be implemented"
33
+ )
32
34
  end
33
35
 
34
- # Return new delete command with new target
36
+ # Create a new delete command scoped to specific relation and execute it
35
37
  #
36
38
  # @api private
37
39
  def new(*args, &block)
38
- self.class.new(relation, options.merge(target: relation.public_send(*args, &block)))
40
+ new_options = options.merge(target: relation.public_send(*args, &block))
41
+ command = self.class.new(relation, new_options)
42
+ command.call
39
43
  end
40
-
41
44
  end
42
-
43
45
  end
44
46
  end
@@ -0,0 +1,82 @@
1
+ module ROM
2
+ module Commands
3
+ # Abstract result class for success and error results
4
+ #
5
+ # @public
6
+ class Result
7
+ # Return command execution result
8
+ #
9
+ # @api public
10
+ attr_reader :value
11
+
12
+ # Return potential command execution result error
13
+ #
14
+ # @api public
15
+ attr_reader :error
16
+
17
+ # Coerce result to an array
18
+ #
19
+ # @abstract
20
+ #
21
+ # @api public
22
+ def to_ary
23
+ raise NotImplementedError
24
+ end
25
+ alias_method :to_a, :to_ary
26
+
27
+ # Success result has a value and no error
28
+ #
29
+ # @public
30
+ class Success < Result
31
+ # @api private
32
+ def initialize(value)
33
+ @value = value
34
+ end
35
+
36
+ # Call next command on continuation
37
+ #
38
+ # @api public
39
+ def >(other)
40
+ other.call(value)
41
+ end
42
+
43
+ # Return the value
44
+ #
45
+ # @return [Array]
46
+ #
47
+ # @api public
48
+ def to_ary
49
+ value
50
+ end
51
+ end
52
+
53
+ # Failure result has an error and no value
54
+ #
55
+ # @public
56
+ class Failure < Result
57
+ # @api private
58
+ def initialize(error)
59
+ @error = error
60
+ end
61
+
62
+ # Do not call next command on continuation
63
+ #
64
+ # @return [self]
65
+ #
66
+ # @api public
67
+ def >(_other)
68
+ self
69
+ end
70
+
71
+ # Return the error
72
+ #
73
+ # @return [Array<CommandError>]
74
+ #
75
+ # @api public
76
+ def to_ary
77
+ error
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -2,7 +2,6 @@ require 'rom/commands/with_options'
2
2
 
3
3
  module ROM
4
4
  module Commands
5
-
6
5
  # Update command
7
6
  #
8
7
  # This command updates all tuples in its relation with new attributes
@@ -26,8 +25,11 @@ module ROM
26
25
  # @abstract
27
26
  #
28
27
  # @api private
29
- def execute(params)
30
- raise NotImplementedError, "#{self.class}##{__method__} must be implemented"
28
+ def execute(_params)
29
+ raise(
30
+ NotImplementedError,
31
+ "#{self.class}##{__method__} must be implemented"
32
+ )
31
33
  end
32
34
 
33
35
  # Return new update command with new relation
@@ -37,6 +39,5 @@ module ROM
37
39
  self.class.new(relation.public_send(*args, &block), options)
38
40
  end
39
41
  end
40
-
41
42
  end
42
43
  end
@@ -1,6 +1,5 @@
1
1
  module ROM
2
2
  module Commands
3
-
4
3
  # Common behavior for Create and Update commands
5
4
  #
6
5
  # TODO: find a better name for this module
@@ -11,11 +10,9 @@ module ROM
11
10
  def initialize(relation, options)
12
11
  super
13
12
 
14
- @validator = options[:validator] || Proc.new {}
13
+ @validator = options[:validator] || proc {}
15
14
  @input = options[:input] || Hash
16
15
  end
17
-
18
16
  end
19
-
20
17
  end
21
18
  end