rom-repository 1.4.0 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -6
  3. data/{LICENSE.txt → LICENSE} +1 -1
  4. data/README.md +18 -1
  5. data/lib/rom-repository.rb +1 -2
  6. data/lib/rom/repository.rb +9 -216
  7. data/lib/rom/repository/class_interface.rb +16 -33
  8. data/lib/rom/repository/relation_reader.rb +46 -0
  9. data/lib/rom/repository/root.rb +3 -59
  10. data/lib/rom/repository/version.rb +1 -1
  11. metadata +9 -98
  12. data/.gitignore +0 -3
  13. data/.rspec +0 -3
  14. data/.travis.yml +0 -27
  15. data/.yardopts +0 -2
  16. data/Gemfile +0 -38
  17. data/Rakefile +0 -19
  18. data/lib/rom/open_struct.rb +0 -35
  19. data/lib/rom/repository/changeset.rb +0 -155
  20. data/lib/rom/repository/changeset/associated.rb +0 -100
  21. data/lib/rom/repository/changeset/create.rb +0 -16
  22. data/lib/rom/repository/changeset/delete.rb +0 -17
  23. data/lib/rom/repository/changeset/pipe.rb +0 -97
  24. data/lib/rom/repository/changeset/restricted.rb +0 -28
  25. data/lib/rom/repository/changeset/stateful.rb +0 -282
  26. data/lib/rom/repository/changeset/update.rb +0 -82
  27. data/lib/rom/repository/command_compiler.rb +0 -257
  28. data/lib/rom/repository/command_proxy.rb +0 -26
  29. data/lib/rom/repository/header_builder.rb +0 -65
  30. data/lib/rom/repository/mapper_builder.rb +0 -23
  31. data/lib/rom/repository/relation_proxy.rb +0 -337
  32. data/lib/rom/repository/relation_proxy/combine.rb +0 -320
  33. data/lib/rom/repository/relation_proxy/wrap.rb +0 -78
  34. data/lib/rom/repository/struct_builder.rb +0 -83
  35. data/lib/rom/struct.rb +0 -113
  36. data/log/.gitkeep +0 -0
  37. data/rom-repository.gemspec +0 -23
  38. data/spec/integration/changeset_spec.rb +0 -193
  39. data/spec/integration/command_macros_spec.rb +0 -191
  40. data/spec/integration/command_spec.rb +0 -228
  41. data/spec/integration/multi_adapter_spec.rb +0 -73
  42. data/spec/integration/repository/aggregate_spec.rb +0 -58
  43. data/spec/integration/repository_spec.rb +0 -406
  44. data/spec/integration/root_repository_spec.rb +0 -106
  45. data/spec/integration/typed_structs_spec.rb +0 -64
  46. data/spec/shared/database.rb +0 -79
  47. data/spec/shared/mappers.rb +0 -35
  48. data/spec/shared/models.rb +0 -41
  49. data/spec/shared/plugins.rb +0 -66
  50. data/spec/shared/relations.rb +0 -115
  51. data/spec/shared/repo.rb +0 -86
  52. data/spec/shared/seeds.rb +0 -30
  53. data/spec/shared/structs.rb +0 -140
  54. data/spec/spec_helper.rb +0 -83
  55. data/spec/support/mapper_registry.rb +0 -9
  56. data/spec/support/mutant.rb +0 -10
  57. data/spec/unit/changeset/associate_spec.rb +0 -120
  58. data/spec/unit/changeset/map_spec.rb +0 -111
  59. data/spec/unit/changeset_spec.rb +0 -186
  60. data/spec/unit/relation_proxy_spec.rb +0 -202
  61. data/spec/unit/repository/changeset_spec.rb +0 -197
  62. data/spec/unit/repository/inspect_spec.rb +0 -18
  63. data/spec/unit/repository/session_spec.rb +0 -251
  64. data/spec/unit/repository/transaction_spec.rb +0 -42
  65. data/spec/unit/session_spec.rb +0 -46
  66. data/spec/unit/struct_builder_spec.rb +0 -128
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 60e1932a1540f3a5db52bbb5a4ae073b83ee0289
4
- data.tar.gz: 8a430f76a00792c4d12d94d8271b0736310dc20b
3
+ metadata.gz: 748ea9ec748c486d611e4ac107cf338362a76b51
4
+ data.tar.gz: 111dd4763fbe363d22e4fe0179e52c3a0d343531
5
5
  SHA512:
6
- metadata.gz: 514906df2e8c7c3b33fb3cce5083d65f4b238ca1aa7ca03df9d736f0ceb4752b610d66937e372645cc0f71dd7a0d845cbcdeca27a69a8ca13a367bf75a42b3e8
7
- data.tar.gz: a75e84fd982d615e4f57802a130658d5d0482c62bf0216f6cf70c6c348c4b99d50561cdcd33de73f6b7ff3700fc15702d4023711b2fe0c0c599b184dc45a77b4
6
+ metadata.gz: 4027a4c8fd3cacfb40a6f0ffe99bae2d88b0e98cd3a8993ef83b6a07e2fac9510e528578b71a1abb673dea61e9dd93b832406a002d7b80e457d1abfc66174549
7
+ data.tar.gz: 5f45222483b70724de8837fa0e2d3cb87737f5acf6944fbccd3c26fc110dd2b5c9d52a76082902a29d3d96a17a8053c131af62214bcb56412ddb74662843871d
data/CHANGELOG.md CHANGED
@@ -1,17 +1,25 @@
1
- # v1.4.0 2017-07-04
1
+ # v2.0.0 to-be-released
2
2
 
3
- ### Added
3
+ ### Changed
4
+
5
+ * [BREAKING] `Relation#combine` no longer works with arbitrary `many` and `one` options. Configure associations instead and use their identifiers as arguments (solnic)
6
+ * [BREAKING] `Relation#combine_parents` was removed (solnic)
7
+ * [BREAKING] `Relation#combine_children` was removed (solnic)
8
+ * [BREAKING] `Relation#wrap_parent` was removed, configure associations and use their identifiers in `wrap` instead (solnic)
9
+ * [BREAKING] `Repository#command` was removed in favor of `Relation#command` (solnic)
4
10
 
5
- * `Relation#map_to` available in repository relations to ease upgrade to rom 4.0 (solnic)
6
- * Deprecation warnings in preparation for rom 4.0 release (solnic)
11
+ ### Internal
7
12
 
8
- [Compare v1.3.3...v1.3.4](https://github.com/rom-rb/rom-repository/compare/v1.3.3...v1.3.4)
13
+ * `RelationProxy` was removed as its functionality was ported and improved in rom-core (solnic)
9
14
 
10
15
  # v1.3.3 2017-05-31
11
16
 
12
17
  ### Added
13
18
 
14
- * `Changeset#extend` to exclude steps from the `#diff` output, this allows to filter out timestamp changes prior to updates so that we can avoid hitting the database in case of timestamp-only changes. You still can call `.map(:touch)` if you want to have `updated_at` refreshed unconditionally (flash-gordon)
19
+ * `Changeset#extend` to exclude steps from the `#diff` output, this allows
20
+ to filter out timestamp changes prior to updates so that we can avoid
21
+ hitting the database in case of timestamp-only changes. You still can call `.map(:touch)`
22
+ if you want to have `updated_at` refreshed unconditionally (flash-gordon)
15
23
 
16
24
  ## Fixed
17
25
 
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 Piotr Solnica
1
+ Copyright (c) 2014-2017 Piotr Solnica
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1 +1,18 @@
1
- # This project was moved to [rom-rb/rom](https://github.com/rom-rb/rom/tree/master/repository)
1
+ [gem]: https://rubygems.org/gems/rom-repository
2
+ [gemnasium]: https://gemnasium.com/rom-rb/rom-repository
3
+
4
+ # rom-repository
5
+
6
+ [![Gem Version](https://badge.fury.io/rb/rom-repository.svg)][gem]
7
+ [![Dependency Status](https://gemnasium.com/rom-rb/rom-repository.svg)][gemnasium]
8
+
9
+ Repositories for [rom-rb](https://github.com/rom-rb/rom) with auto-mapping, changesets and commands.
10
+
11
+ Resources:
12
+
13
+ * [User documentation](http://rom-rb.org/learn/repositories)
14
+ * [API documentation](http://rubydoc.info/gems/rom-repository)
15
+
16
+ ## License
17
+
18
+ See `LICENSE` file.
@@ -1,3 +1,2 @@
1
- require 'rom'
2
-
1
+ require 'rom/core'
3
2
  require 'rom/repository'
@@ -2,11 +2,6 @@ require 'dry/core/deprecations'
2
2
 
3
3
  require 'rom/initializer'
4
4
  require 'rom/repository/class_interface'
5
- require 'rom/repository/mapper_builder'
6
- require 'rom/repository/relation_proxy'
7
- require 'rom/repository/command_compiler'
8
-
9
- require 'rom/repository/changeset'
10
5
  require 'rom/repository/session'
11
6
 
12
7
  module ROM
@@ -55,13 +50,6 @@ module ROM
55
50
  #
56
51
  # @api public
57
52
  class Repository
58
- # Mapping for supported changeset classes used in #changeset(type => relation) method
59
- CHANGESET_TYPES = {
60
- create: Changeset::Create,
61
- update: Changeset::Update,
62
- delete: Changeset::Delete
63
- }.freeze
64
-
65
53
  extend ClassInterface
66
54
  extend Initializer
67
55
  extend Dry::Core::ClassAttributes
@@ -86,6 +74,11 @@ module ROM
86
74
  # Get or set struct namespace
87
75
  defines :struct_namespace
88
76
 
77
+ # @!method self.relation_reader
78
+ # Get or set relation reader module
79
+ # @return [RelationReader]
80
+ defines :relation_reader
81
+
89
82
  struct_namespace ROM::Struct
90
83
 
91
84
  # @!attribute [r] container
@@ -104,175 +97,15 @@ module ROM
104
97
  # @return [RelationRegistry] The relation proxy registry used by a repo
105
98
  attr_reader :relations
106
99
 
107
- # @!attribute [r] mappers
108
- # @return [MapperBuilder] The auto-generated mappers for repo relations
109
- attr_reader :mappers
110
-
111
- # @!attribute [r] commmand_compiler
112
- # @return [Method] Function for compiling commands bound to a repo instance
113
- attr_reader :command_compiler
114
-
115
100
  # Initializes a new repo by establishing configured relation proxies from
116
101
  # the passed container
117
102
  #
118
103
  # @param container [ROM::Container] The rom container with relations and optional commands
119
104
  #
120
- # @api public
121
- def initialize(container, opts = EMPTY_HASH)
105
+ # @api private
106
+ def initialize(container, options = EMPTY_HASH)
122
107
  super
123
-
124
- @mappers = MapperBuilder.new(struct_namespace: struct_namespace)
125
-
126
- @relations = RelationRegistry.new do |registry, relations|
127
- self.class.relations.each do |name|
128
- relation = container.relations[name]
129
- relation = relation.with(mappers: container.mappers[name]) if container.mappers.key?(name)
130
-
131
- proxy = RelationProxy.new(
132
- relation, name: name, mappers: mappers, registry: registry, auto_struct: auto_struct
133
- )
134
-
135
- instance_variable_set("@#{name}", proxy)
136
-
137
- relations[name] = proxy
138
- end
139
- end
140
-
141
- @command_compiler = method(:command)
142
- end
143
-
144
- # Return a command for a relation
145
- #
146
- # @overload command(type, relation)
147
- # Returns a command for a relation
148
- #
149
- # @example
150
- # repo.command(:create, repo.users)
151
- #
152
- # @param type [Symbol] The command type (:create, :update or :delete)
153
- # @param relation [RelationProxy] The relation for which command should be built for
154
- #
155
- # @overload command(options)
156
- # Builds a command for a given relation identifier
157
- #
158
- # @example
159
- # repo.command(create: :users)
160
- #
161
- # @param options [Hash<Symbol=>Symbol>] A type => rel_name map
162
- #
163
- # @overload command(rel_name)
164
- # Returns command registry for a given relation identifier
165
- #
166
- # @example
167
- # repo.command(:users)[:my_custom_command]
168
- #
169
- # @param rel_name [Symbol] The relation identifier from the container
170
- #
171
- # @return [CommandRegistry]
172
- #
173
- # @overload command(rel_name, &block)
174
- # Yields a command graph composer for a given relation identifier
175
- #
176
- # @param rel_name [Symbol] The relation identifier from the container
177
- #
178
- # @return [ROM::Command]
179
- #
180
- # @api public
181
- def command(*args, **opts, &block)
182
- all_args = args + opts.to_a.flatten
183
-
184
- if all_args.size > 1
185
- commands.fetch_or_store(all_args.hash) do
186
- compile_command(*args, **opts)
187
- end
188
- else
189
- container.command(*args, &block)
190
- end
191
- end
192
-
193
- # Return a changeset for a relation
194
- #
195
- # @overload changeset(name, attributes)
196
- # Return a create changeset for a given relation identifier
197
- #
198
- # @example
199
- # repo.changeset(:users, name: "Jane")
200
- #
201
- # @param name [Symbol] The relation container identifier
202
- # @param attributes [Hash]
203
- #
204
- # @return [Changeset::Create]
205
- #
206
- # @overload changeset(name, primary_key, attributes)
207
- # Return an update changeset for a given relation identifier
208
- #
209
- # @example
210
- # repo.changeset(:users, 1, name: "Jane Doe")
211
- #
212
- # @param name [Symbol] The relation container identifier
213
- # @param restriction_arg [Object] The argument passed to restricted view
214
- #
215
- # @return [Changeset::Update]
216
- #
217
- # @overload changeset(changeset_class)
218
- # Return a changeset object using provided class
219
- #
220
- # @example
221
- # repo.changeset(NewUserChangeset).data(attributes)
222
- #
223
- # @param [Class] changeset_class Custom changeset class
224
- #
225
- # @return [Changeset]
226
- #
227
- # @overload changeset(opts)
228
- # Return a changeset object using provided changeset type and relation
229
- #
230
- # @example
231
- # repo.changeset(delete: repo.users.where { id > 10 })
232
- #
233
- # @param [Hash<Symbol=>Relation] opts Command type => Relation config
234
- #
235
- # @return [Changeset]
236
- #
237
- # @api public
238
- def changeset(*args)
239
- opts = { command_compiler: command_compiler }
240
-
241
- if args.size == 2
242
- name, data = args
243
- elsif args.size == 3
244
- name, pk, data = args
245
- elsif args.size == 1
246
- if args[0].is_a?(Class)
247
- klass = args[0]
248
-
249
- if klass < Changeset
250
- return klass.new(relations[klass.relation], opts)
251
- else
252
- raise ArgumentError, "+#{klass.name}+ is not a Changeset subclass"
253
- end
254
- else
255
- type, relation = args[0].to_a[0]
256
- end
257
- else
258
- raise ArgumentError, 'Repository#changeset accepts 1-3 arguments'
259
- end
260
-
261
- if type
262
- klass = CHANGESET_TYPES.fetch(type) {
263
- raise ArgumentError, "+#{type.inspect}+ is not a valid changeset type. Must be one of: #{CHANGESET_TYPES.keys.inspect}"
264
- }
265
-
266
- klass.new(relation, opts)
267
- else
268
- relation = relations[name]
269
-
270
- if pk
271
- Changeset::Update.new(relation.by_pk(pk), opts.update(__data__: data))
272
- else
273
- Changeset::Create.new(relation, opts.update(__data__: data))
274
- end
275
- end
108
+ @relations = {}
276
109
  end
277
110
 
278
111
  # Open a database transaction
@@ -305,7 +138,7 @@ module ROM
305
138
  #
306
139
  # @api public
307
140
  def inspect
308
- %(#<#{self.class} relations=[#{self.class.relations.map(&:inspect).join(' ')}]>)
141
+ %(#<#{self.class} struct_namespace=#{struct_namespace} auto_struct=#{auto_struct}>)
309
142
  end
310
143
 
311
144
  # Start a session for multiple changesets
@@ -321,46 +154,6 @@ module ROM
321
154
  yield(session)
322
155
  transaction { session.commit! }
323
156
  end
324
-
325
- private
326
-
327
- # Local command cache
328
- #
329
- # @api private
330
- def commands
331
- @__commands__ ||= Concurrent::Map.new
332
- end
333
-
334
- # Build a new command or return existing one
335
- #
336
- # @api private
337
- def compile_command(*args, mapper: nil, use: nil, **opts)
338
- type, name = args + opts.to_a.flatten(1)
339
-
340
- relation = name.is_a?(Symbol) ? relations[name] : name
341
-
342
- ast = relation.to_ast
343
- adapter = relations[relation.name].adapter
344
-
345
- if mapper
346
- mapper_instance = container.mappers[relation.name.relation][mapper]
347
- elsif mapper.nil?
348
- mapper_instance = mappers[ast]
349
- end
350
-
351
- command = CommandCompiler[container, type, adapter, ast, use, opts]
352
-
353
- if mapper_instance
354
- command >> mapper_instance
355
- else
356
- command.new(relation)
357
- end
358
- end
359
-
360
- # @api private
361
- def map_tuple(relation, tuple)
362
- relations[relation.name].mapper.([tuple]).first
363
- end
364
157
  end
365
158
  end
366
159
 
@@ -1,3 +1,5 @@
1
+ require 'rom/repository/relation_reader'
2
+
1
3
  module ROM
2
4
  class Repository
3
5
  # Class-level APIs for repositories
@@ -18,11 +20,20 @@ module ROM
18
20
  # @api public
19
21
  def [](name)
20
22
  klass = Class.new(self < Repository::Root ? self : Repository::Root)
21
- klass.relations(name)
22
23
  klass.root(name)
23
24
  klass
24
25
  end
25
26
 
27
+ # @api public
28
+ def new(container, options = EMPTY_HASH)
29
+ unless relation_reader
30
+ relation_reader(RelationReader.new(self, container.relations.elements.keys))
31
+ include(relation_reader)
32
+ end
33
+
34
+ super
35
+ end
36
+
26
37
  # Inherits configured relations and commands
27
38
  #
28
39
  # @api private
@@ -31,34 +42,9 @@ module ROM
31
42
 
32
43
  return if self === Repository
33
44
 
34
- klass.relations(*relations)
35
45
  klass.commands(*commands)
36
46
  end
37
47
 
38
- # Define which relations your repository is going to use
39
- #
40
- # @example
41
- # class MyRepo < ROM::Repository
42
- # relations :users, :tasks
43
- # end
44
- #
45
- # my_repo = MyRepo.new(rom)
46
- #
47
- # my_repo.users
48
- # my_repo.tasks
49
- #
50
- # @return [Array<Symbol>]
51
- #
52
- # @api public
53
- def relations(*names)
54
- if names.empty?
55
- @relations ||= []
56
- else
57
- attr_reader(*(names - relations))
58
- @relations = relations | names
59
- end
60
- end
61
-
62
48
  # Defines command methods on a root repository
63
49
  #
64
50
  # @example
@@ -107,10 +93,9 @@ module ROM
107
93
  def define_command_method(type, **opts)
108
94
  define_method(type) do |*input|
109
95
  if input.size == 1 && input[0].respond_to?(:commit)
110
- changeset = input[0]
111
- map_tuple(changeset.relation, changeset.commit)
96
+ input[0].commit
112
97
  else
113
- command(type => self.class.root, **opts).call(*input)
98
+ root.command(type, **opts).call(*input)
114
99
  end
115
100
  end
116
101
  end
@@ -126,11 +111,9 @@ module ROM
126
111
  changeset = input.first
127
112
 
128
113
  if changeset.respond_to?(:commit)
129
- map_tuple(changeset.relation, changeset.commit)
114
+ changeset.commit
130
115
  else
131
- command(type => self.class.root, **opts)
132
- .public_send(view_name, *view_args)
133
- .call(*input)
116
+ root.command(type, **opts).public_send(view_name, *view_args).call(*input)
134
117
  end
135
118
  end
136
119
  end
@@ -0,0 +1,46 @@
1
+ module ROM
2
+ class Repository
3
+ # @api private
4
+ class RelationReader < Module
5
+ # @api private
6
+ attr_reader :klass
7
+
8
+ # @api private
9
+ attr_reader :relations
10
+
11
+ module InstanceMethods
12
+ # @api private
13
+ def set_relation(name)
14
+ container.
15
+ relations[name].
16
+ with(auto_struct: auto_struct).
17
+ struct_namespace(struct_namespace)
18
+ end
19
+ end
20
+
21
+ # @api private
22
+ def initialize(klass, relations)
23
+ @klass = klass
24
+ @relations = relations
25
+ define_readers!
26
+ end
27
+
28
+ # @api private
29
+ def included(klass)
30
+ super
31
+ klass.include(InstanceMethods)
32
+ end
33
+
34
+ private
35
+
36
+ # @api private
37
+ def define_readers!
38
+ relations.each do |name|
39
+ define_method(name) do
40
+ @relations[name] ||= set_relation(name)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end