rom 0.5.0 → 0.6.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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +19 -15
  3. data/.rubocop_todo.yml +28 -0
  4. data/.travis.yml +8 -1
  5. data/CHANGELOG.md +40 -0
  6. data/Gemfile +10 -2
  7. data/Guardfile +12 -10
  8. data/README.md +42 -43
  9. data/Rakefile +13 -23
  10. data/lib/rom.rb +19 -27
  11. data/lib/rom/command.rb +118 -0
  12. data/lib/rom/command_registry.rb +13 -27
  13. data/lib/rom/commands.rb +1 -59
  14. data/lib/rom/commands/abstract.rb +147 -0
  15. data/lib/rom/commands/composite.rb +47 -0
  16. data/lib/rom/commands/create.rb +2 -17
  17. data/lib/rom/commands/delete.rb +5 -25
  18. data/lib/rom/commands/result.rb +5 -5
  19. data/lib/rom/commands/update.rb +3 -27
  20. data/lib/rom/constants.rb +19 -0
  21. data/lib/rom/env.rb +85 -35
  22. data/lib/rom/global.rb +173 -42
  23. data/lib/rom/header.rb +5 -5
  24. data/lib/rom/header/attribute.rb +2 -2
  25. data/lib/rom/lint/enumerable_dataset.rb +52 -0
  26. data/lib/rom/lint/linter.rb +64 -0
  27. data/lib/rom/lint/repository.rb +78 -0
  28. data/lib/rom/lint/spec.rb +20 -0
  29. data/lib/rom/lint/test.rb +98 -0
  30. data/lib/rom/mapper.rb +32 -5
  31. data/lib/rom/mapper/attribute_dsl.rb +240 -0
  32. data/lib/rom/mapper/dsl.rb +100 -0
  33. data/lib/rom/mapper/model_dsl.rb +55 -0
  34. data/lib/rom/mapper_registry.rb +8 -1
  35. data/lib/rom/memory.rb +4 -0
  36. data/lib/rom/memory/commands.rb +46 -0
  37. data/lib/rom/memory/dataset.rb +72 -0
  38. data/lib/rom/memory/relation.rb +44 -0
  39. data/lib/rom/memory/repository.rb +62 -0
  40. data/lib/rom/memory/storage.rb +57 -0
  41. data/lib/rom/model_builder.rb +44 -5
  42. data/lib/rom/processor.rb +1 -1
  43. data/lib/rom/processor/transproc.rb +109 -16
  44. data/lib/rom/reader.rb +91 -39
  45. data/lib/rom/relation.rb +165 -26
  46. data/lib/rom/relation/composite.rb +132 -0
  47. data/lib/rom/relation/curried.rb +48 -0
  48. data/lib/rom/relation/lazy.rb +173 -0
  49. data/lib/rom/relation/loaded.rb +75 -0
  50. data/lib/rom/relation/registry_reader.rb +23 -0
  51. data/lib/rom/repository.rb +93 -34
  52. data/lib/rom/setup.rb +54 -98
  53. data/lib/rom/setup/finalize.rb +85 -76
  54. data/lib/rom/setup_dsl/command.rb +36 -0
  55. data/lib/rom/setup_dsl/command_dsl.rb +34 -0
  56. data/lib/rom/setup_dsl/mapper.rb +32 -0
  57. data/lib/rom/setup_dsl/mapper_dsl.rb +30 -0
  58. data/lib/rom/setup_dsl/relation.rb +21 -0
  59. data/lib/rom/setup_dsl/setup.rb +75 -0
  60. data/lib/rom/support/array_dataset.rb +38 -0
  61. data/lib/rom/support/class_builder.rb +44 -0
  62. data/lib/rom/support/class_macros.rb +56 -0
  63. data/lib/rom/support/data_proxy.rb +102 -0
  64. data/lib/rom/support/enumerable_dataset.rb +58 -0
  65. data/lib/rom/support/inflector.rb +73 -0
  66. data/lib/rom/support/options.rb +188 -0
  67. data/lib/rom/support/registry.rb +4 -8
  68. data/lib/rom/version.rb +1 -1
  69. data/rakelib/benchmark.rake +13 -0
  70. data/rakelib/mutant.rake +16 -0
  71. data/rakelib/rubocop.rake +18 -0
  72. data/rom.gemspec +4 -7
  73. data/spec/integration/commands/create_spec.rb +32 -24
  74. data/spec/integration/commands/delete_spec.rb +15 -7
  75. data/spec/integration/commands/update_spec.rb +13 -11
  76. data/spec/integration/mappers/deep_embedded_spec.rb +4 -11
  77. data/spec/integration/mappers/definition_dsl_spec.rb +31 -44
  78. data/spec/integration/mappers/embedded_spec.rb +9 -24
  79. data/spec/integration/mappers/group_spec.rb +22 -30
  80. data/spec/integration/mappers/prefixing_attributes_spec.rb +18 -23
  81. data/spec/integration/mappers/renaming_attributes_spec.rb +23 -38
  82. data/spec/integration/mappers/symbolizing_attributes_spec.rb +18 -24
  83. data/spec/integration/mappers/wrap_spec.rb +22 -30
  84. data/spec/integration/multi_repo_spec.rb +15 -37
  85. data/spec/integration/relations/reading_spec.rb +82 -14
  86. data/spec/integration/repositories/extending_relations_spec.rb +50 -0
  87. data/spec/integration/{adapters → repositories}/setting_logger_spec.rb +6 -5
  88. data/spec/integration/setup_spec.rb +59 -62
  89. data/spec/shared/enumerable_dataset.rb +49 -0
  90. data/spec/shared/one_behavior.rb +26 -0
  91. data/spec/shared/users_and_tasks.rb +11 -23
  92. data/spec/spec_helper.rb +16 -7
  93. data/spec/support/constant_leak_finder.rb +14 -0
  94. data/spec/test/memory_repository_lint_test.rb +27 -0
  95. data/spec/unit/rom/command_registry_spec.rb +44 -0
  96. data/spec/unit/rom/commands/result_spec.rb +14 -0
  97. data/spec/unit/rom/commands_spec.rb +174 -0
  98. data/spec/unit/rom/env_spec.rb +40 -7
  99. data/spec/unit/rom/global_spec.rb +14 -0
  100. data/spec/unit/rom/{mapper_builder_spec.rb → mapper/dsl_spec.rb} +52 -38
  101. data/spec/unit/rom/mapper_spec.rb +51 -10
  102. data/spec/unit/rom/{adapter/memory → memory}/dataset_spec.rb +6 -4
  103. data/spec/unit/rom/memory/repository_spec.rb +12 -0
  104. data/spec/unit/rom/memory/storage_spec.rb +45 -0
  105. data/spec/unit/rom/model_builder_spec.rb +4 -3
  106. data/spec/unit/rom/processor/transproc_spec.rb +1 -0
  107. data/spec/unit/rom/reader_spec.rb +97 -24
  108. data/spec/unit/rom/relation/composite_spec.rb +65 -0
  109. data/spec/unit/rom/relation/lazy_spec.rb +145 -0
  110. data/spec/unit/rom/relation/loaded_spec.rb +28 -0
  111. data/spec/unit/rom/relation_spec.rb +111 -6
  112. data/spec/unit/rom/repository_spec.rb +59 -9
  113. data/spec/unit/rom/setup_spec.rb +99 -11
  114. data/spec/unit/rom/support/array_dataset_spec.rb +59 -0
  115. data/spec/unit/rom/support/class_builder_spec.rb +42 -0
  116. data/spec/unit/rom/support/enumerable_dataset_spec.rb +17 -0
  117. data/spec/unit/rom/support/inflector_spec.rb +89 -0
  118. data/spec/unit/rom/support/options_spec.rb +119 -0
  119. metadata +74 -112
  120. data/lib/rom/adapter.rb +0 -191
  121. data/lib/rom/adapter/memory.rb +0 -32
  122. data/lib/rom/adapter/memory/commands.rb +0 -31
  123. data/lib/rom/adapter/memory/dataset.rb +0 -67
  124. data/lib/rom/adapter/memory/storage.rb +0 -26
  125. data/lib/rom/commands/with_options.rb +0 -18
  126. data/lib/rom/config.rb +0 -70
  127. data/lib/rom/mapper_builder.rb +0 -52
  128. data/lib/rom/mapper_builder/mapper_dsl.rb +0 -114
  129. data/lib/rom/mapper_builder/model_dsl.rb +0 -29
  130. data/lib/rom/reader_builder.rb +0 -48
  131. data/lib/rom/relation_builder.rb +0 -62
  132. data/lib/rom/setup/base_relation_dsl.rb +0 -46
  133. data/lib/rom/setup/command_dsl.rb +0 -46
  134. data/lib/rom/setup/mapper_dsl.rb +0 -19
  135. data/lib/rom/setup/relation_dsl.rb +0 -20
  136. data/lib/rom/setup/schema_dsl.rb +0 -33
  137. data/spec/integration/adapters/extending_relations_spec.rb +0 -41
  138. data/spec/integration/commands/try_spec.rb +0 -27
  139. data/spec/integration/schema_spec.rb +0 -77
  140. data/spec/unit/config_spec.rb +0 -60
  141. data/spec/unit/rom/adapter_spec.rb +0 -79
  142. data/spec/unit/rom_spec.rb +0 -14
@@ -0,0 +1,75 @@
1
+ module ROM
2
+ class Relation
3
+ # Materializes a relation and exposes interface to access the data
4
+ #
5
+ # @api public
6
+ class Loaded
7
+ include Enumerable
8
+
9
+ # Source relation
10
+ #
11
+ # @return [Relation]
12
+ #
13
+ # @api private
14
+ attr_reader :source
15
+
16
+ # Materialized relation
17
+ #
18
+ # @return [Object]
19
+ #
20
+ # @api private
21
+ attr_reader :collection
22
+
23
+ # @api private
24
+ def initialize(source, collection = source.to_a)
25
+ @source = source
26
+ @collection = collection
27
+ end
28
+
29
+ # Yield relation tuples
30
+ #
31
+ # @yield [Hash]
32
+ #
33
+ # @api public
34
+ def each(&block)
35
+ return to_enum unless block
36
+ collection.each { |object| yield(object) }
37
+ end
38
+
39
+ # @api public
40
+ def new(collection)
41
+ self.class.new(source, collection)
42
+ end
43
+
44
+ # Returns a single tuple from the relation if there is one.
45
+ #
46
+ # @raise [ROM::TupleCountMismatchError] if the relation contains more than
47
+ # one tuple
48
+ #
49
+ # @api public
50
+ def one
51
+ if collection.count > 1
52
+ raise(
53
+ TupleCountMismatchError,
54
+ 'The relation consists of more than one tuple'
55
+ )
56
+ else
57
+ collection.first
58
+ end
59
+ end
60
+
61
+ # Like [one], but additionally raises an error if the relation is empty.
62
+ #
63
+ # @raise [ROM::TupleCountMismatchError] if the relation does not contain
64
+ # exactly one tuple
65
+ #
66
+ # @api public
67
+ def one!
68
+ one || raise(
69
+ TupleCountMismatchError,
70
+ 'The relation does not contain any tuples'
71
+ )
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,23 @@
1
+ module ROM
2
+ class Relation
3
+ module RegistryReader
4
+ # @api private
5
+ def self.included(klass)
6
+ super
7
+ klass.option :__registry__, type: Hash, default: {}, reader: true
8
+ end
9
+
10
+ # @api private
11
+ def respond_to_missing?(name, _include_private = false)
12
+ __registry__.key?(name) || super
13
+ end
14
+
15
+ private
16
+
17
+ # @api private
18
+ def method_missing(name, *)
19
+ __registry__.fetch(name) { super }
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,66 +1,125 @@
1
1
  module ROM
2
- # Repository exposes native database connection and schema when it's
3
- # supported by the adapter
2
+ # Abstract repository class
4
3
  #
5
4
  # @api public
6
5
  class Repository
7
- include Concord::Public.new(:adapter)
6
+ # Return connection object
7
+ #
8
+ # @return [Object] type varies depending on the repository
9
+ #
10
+ # @api public
11
+ attr_reader :connection
8
12
 
9
- # Return the dataset identified by name
13
+ # Setup a repository
14
+ #
15
+ # @overload setup(type, *args)
16
+ # Sets up a single-repository given a repository type.
17
+ # For custom repositories, create an instance and pass it directly.
18
+ #
19
+ # @param [Symbol] type
20
+ # @param [Array] *args
21
+ #
22
+ # @overload setup(repository)
23
+ # @param [Repository] repository
24
+ #
25
+ # @return [Repository] a specific repository subclass
26
+ #
27
+ # @example
28
+ # module SuperDB
29
+ # class Repository < ROM::Repository
30
+ # def initialize(options)
31
+ # end
32
+ # end
33
+ # end
34
+ #
35
+ # ROM.register_adapter(:super_db, SuperDB)
10
36
  #
11
- # @param [String,Symbol] name
37
+ # Repository.setup(:super_db, some: 'options')
38
+ # # SuperDB::Repository.new(some: 'options') is called
39
+ #
40
+ # # or alternatively
41
+ # super_db = Repository.setup(SuperDB::Repository.new(some: 'options'))
42
+ # Repository.setup(super_db)
12
43
  #
13
44
  # @api public
14
- def [](name)
15
- adapter[name]
45
+ def self.setup(repository_or_scheme, *args)
46
+ case repository_or_scheme
47
+ when String
48
+ raise ArgumentError, <<-STRING.gsub(/^ {10}/, '')
49
+ URIs without an explicit scheme are not supported anymore.
50
+ See https://github.com/rom-rb/rom/blob/master/CHANGELOG.md
51
+ STRING
52
+ when Symbol
53
+ class_from_symbol(repository_or_scheme).new(*args)
54
+ else
55
+ if args.empty?
56
+ repository_or_scheme
57
+ else
58
+ raise ArgumentError, "Can't accept arguments when passing an instance"
59
+ end
60
+ end
16
61
  end
17
62
 
18
- # Set a logger for the adapter
63
+ # Get repository subclass for a specific adapter
19
64
  #
20
- # @param [Object] logger
65
+ # @param [Symbol] type adapter identifier
21
66
  #
22
- # @api public
23
- def use_logger(logger)
24
- adapter.logger = logger
67
+ # @return [Class]
68
+ #
69
+ # @api private
70
+ def self.class_from_symbol(type)
71
+ begin
72
+ require "rom/#{type}"
73
+ rescue LoadError
74
+ raise AdapterLoadError, "Failed to load adapter rom/#{type}"
75
+ end
76
+
77
+ adapter = ROM.adapters.fetch(type)
78
+ adapter.const_get(:Repository)
25
79
  end
26
80
 
27
- # Return logger used by the adapter
81
+ # A generic interface for setting up a logger
28
82
  #
29
- # @return [Object] logger
83
+ # @api public
84
+ def use_logger(*)
85
+ # noop
86
+ end
87
+
88
+ # A generic interface for returning default logger
30
89
  #
31
90
  # @api public
32
91
  def logger
33
- adapter.logger
92
+ # noop
34
93
  end
35
94
 
36
- # Return the database connection provided by the adapter
95
+ # Extension hook for adding repository-specific behavior to a command class
96
+ #
97
+ # @param [Class] klass command class
98
+ # @param [Object] _dataset dataset that will be used with this command class
99
+ #
100
+ # @return [Class]
37
101
  #
38
102
  # @api public
39
- def connection
40
- adapter.connection
103
+ def extend_command_class(klass, _dataset)
104
+ klass
41
105
  end
42
106
 
43
- # Return the schema provided by the adapter
107
+ # Schema inference hook
108
+ #
109
+ # Every repository that supports schema inference should implement this method
110
+ #
111
+ # @return [Array] array with datasets and their names
44
112
  #
45
113
  # @api private
46
114
  def schema
47
- adapter.schema
48
- end
49
-
50
- # @api private
51
- def respond_to_missing?(name, include_private = false)
52
- adapter.dataset?(name) || super
115
+ []
53
116
  end
54
117
 
55
- private
56
-
57
- # @api private
58
- def method_missing(name, *args, &block)
59
- if adapter.dataset?(name)
60
- adapter[name]
61
- else
62
- super
63
- end
118
+ # Disconnect is optional and it's a no-op by default
119
+ #
120
+ # @api public
121
+ def disconnect
122
+ # noop
64
123
  end
65
124
  end
66
125
  end
data/lib/rom/setup.rb CHANGED
@@ -1,128 +1,67 @@
1
- require 'rom/setup/schema_dsl'
2
- require 'rom/setup/mapper_dsl'
3
- require 'rom/setup/command_dsl'
4
-
5
1
  require 'rom/setup/finalize'
6
2
 
7
3
  module ROM
8
- # Exposes DSL for defining schema, relations, mappers and commands
4
+ # Exposes DSL for defining relations, mappers and commands
9
5
  #
10
- # @public
6
+ # @api public
11
7
  class Setup
12
8
  include Equalizer.new(:repositories, :env)
13
9
 
10
+ # @return [Hash] configured repositories
11
+ #
14
12
  # @api private
15
- attr_reader :repositories, :env
13
+ attr_reader :repositories
16
14
 
15
+ # @return [Symbol] default (first) adapter
16
+ #
17
17
  # @api private
18
- def initialize(repositories)
19
- @repositories = repositories
20
- @schema = {}
21
- @relations = {}
22
- @mappers = []
23
- @commands = {}
24
- @adapter_relation_map = {}
25
- @env = nil
26
- end
18
+ attr_reader :default_adapter
27
19
 
28
- # Schema definition DSL
20
+ # @return [Array] registered relation subclasses
29
21
  #
30
- # @example
31
- #
32
- # setup.schema do
33
- # base_relation(:users) do
34
- # repository :sqlite
35
- #
36
- # attribute :id
37
- # attribute :name
38
- # end
39
- # end
40
- #
41
- # @api public
42
- def schema(&block)
43
- SchemaDSL.new(self, @schema, &block)
44
- end
22
+ # @api private
23
+ attr_reader :relation_classes
45
24
 
46
- # Relation definition DSL
25
+ # @return [Array] registered mapper subclasses
47
26
  #
48
- # @example
49
- #
50
- # setup.relation(:users) do
51
- # def names
52
- # project(:name)
53
- # end
54
- # end
55
- #
56
- # @api public
57
- def relation(name, &block)
58
- @relations.update(name => block)
59
- end
27
+ # @api private
28
+ attr_reader :mapper_classes
60
29
 
61
- # Mapper definition DSL
62
- #
63
- # @example
30
+ # @return [Array] registered command subclasses
64
31
  #
65
- # setup.mappers do
66
- # define(:users) do
67
- # model name: 'User'
68
- # end
69
- #
70
- # define(:names, parent: :users) do
71
- # exclude :id
72
- # end
73
- # end
74
- #
75
- # @api public
76
- def mappers(&block)
77
- dsl = MapperDSL.new(&block)
78
- @mappers.concat(dsl.mappers)
79
- end
32
+ # @api private
33
+ attr_reader :command_classes
80
34
 
81
- # Command definition DSL
82
- #
83
- # @example
35
+ # @return [Env] finalized env after setup phase is over
84
36
  #
85
- # setup.commands(:users) do
86
- # define(:create) do
87
- # input NewUserParams
88
- # validator NewUserValidator
89
- # result :one
90
- # end
91
- #
92
- # define(:update) do
93
- # input UserParams
94
- # validator UserValidator
95
- # result :many
96
- # end
97
- #
98
- # define(:delete) do
99
- # result :many
100
- # end
101
- # end
102
- #
103
- # @api public
104
- def commands(name, &block)
105
- dsl = CommandDSL.new(&block)
106
- @commands.update(name => dsl.commands)
37
+ # @api private
38
+ attr_reader :env
39
+
40
+ # @api private
41
+ def initialize(repositories, default_adapter = nil)
42
+ @repositories = repositories
43
+ @default_adapter = default_adapter
44
+ @relation_classes = []
45
+ @mapper_classes = []
46
+ @command_classes = []
47
+ @env = nil
107
48
  end
108
49
 
109
50
  # Finalize the setup
110
51
  #
111
- # @return [Env] frozen env with access to repositories, schema, relations,
52
+ # @return [Env] frozen env with access to repositories, relations,
112
53
  # mappers and commands
113
54
  #
114
55
  # @api public
115
56
  def finalize
116
57
  raise EnvAlreadyFinalizedError if env
117
-
118
58
  finalize = Finalize.new(
119
- repositories, @schema, @relations, @mappers, @commands
59
+ repositories, relation_classes, mapper_classes, command_classes
120
60
  )
121
-
122
61
  @env = finalize.run!
123
62
  end
124
63
 
125
- # Returns repository identified by name
64
+ # Return repository identified by name
126
65
  #
127
66
  # @return [Repository]
128
67
  #
@@ -131,6 +70,27 @@ module ROM
131
70
  repositories.fetch(name)
132
71
  end
133
72
 
73
+ # Relation sub-classes are being registered with this method during setup
74
+ #
75
+ # @api private
76
+ def register_relation(klass)
77
+ @relation_classes << klass
78
+ end
79
+
80
+ # Mapper sub-classes are being registered with this method during setup
81
+ #
82
+ # @api private
83
+ def register_mapper(klass)
84
+ @mapper_classes << klass
85
+ end
86
+
87
+ # Command sub-classes are being registered with this method during setup
88
+ #
89
+ # @api private
90
+ def register_command(klass)
91
+ @command_classes << klass
92
+ end
93
+
134
94
  # Hook for respond_to? used internally
135
95
  #
136
96
  # @api private
@@ -146,11 +106,7 @@ module ROM
146
106
  #
147
107
  # @api private
148
108
  def method_missing(name, *)
149
- if repositories.key?(name)
150
- repositories.fetch(name)
151
- else
152
- super
153
- end
109
+ repositories.fetch(name) { super }
154
110
  end
155
111
  end
156
112
  end