rom-repository 1.4.0 → 2.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -6
- data/{LICENSE.txt → LICENSE} +1 -1
- data/README.md +18 -1
- data/lib/rom-repository.rb +1 -2
- data/lib/rom/repository.rb +9 -216
- data/lib/rom/repository/class_interface.rb +16 -33
- data/lib/rom/repository/relation_reader.rb +46 -0
- data/lib/rom/repository/root.rb +3 -59
- data/lib/rom/repository/version.rb +1 -1
- metadata +9 -98
- data/.gitignore +0 -3
- data/.rspec +0 -3
- data/.travis.yml +0 -27
- data/.yardopts +0 -2
- data/Gemfile +0 -38
- data/Rakefile +0 -19
- data/lib/rom/open_struct.rb +0 -35
- data/lib/rom/repository/changeset.rb +0 -155
- data/lib/rom/repository/changeset/associated.rb +0 -100
- data/lib/rom/repository/changeset/create.rb +0 -16
- data/lib/rom/repository/changeset/delete.rb +0 -17
- data/lib/rom/repository/changeset/pipe.rb +0 -97
- data/lib/rom/repository/changeset/restricted.rb +0 -28
- data/lib/rom/repository/changeset/stateful.rb +0 -282
- data/lib/rom/repository/changeset/update.rb +0 -82
- data/lib/rom/repository/command_compiler.rb +0 -257
- data/lib/rom/repository/command_proxy.rb +0 -26
- data/lib/rom/repository/header_builder.rb +0 -65
- data/lib/rom/repository/mapper_builder.rb +0 -23
- data/lib/rom/repository/relation_proxy.rb +0 -337
- data/lib/rom/repository/relation_proxy/combine.rb +0 -320
- data/lib/rom/repository/relation_proxy/wrap.rb +0 -78
- data/lib/rom/repository/struct_builder.rb +0 -83
- data/lib/rom/struct.rb +0 -113
- data/log/.gitkeep +0 -0
- data/rom-repository.gemspec +0 -23
- data/spec/integration/changeset_spec.rb +0 -193
- data/spec/integration/command_macros_spec.rb +0 -191
- data/spec/integration/command_spec.rb +0 -228
- data/spec/integration/multi_adapter_spec.rb +0 -73
- data/spec/integration/repository/aggregate_spec.rb +0 -58
- data/spec/integration/repository_spec.rb +0 -406
- data/spec/integration/root_repository_spec.rb +0 -106
- data/spec/integration/typed_structs_spec.rb +0 -64
- data/spec/shared/database.rb +0 -79
- data/spec/shared/mappers.rb +0 -35
- data/spec/shared/models.rb +0 -41
- data/spec/shared/plugins.rb +0 -66
- data/spec/shared/relations.rb +0 -115
- data/spec/shared/repo.rb +0 -86
- data/spec/shared/seeds.rb +0 -30
- data/spec/shared/structs.rb +0 -140
- data/spec/spec_helper.rb +0 -83
- data/spec/support/mapper_registry.rb +0 -9
- data/spec/support/mutant.rb +0 -10
- data/spec/unit/changeset/associate_spec.rb +0 -120
- data/spec/unit/changeset/map_spec.rb +0 -111
- data/spec/unit/changeset_spec.rb +0 -186
- data/spec/unit/relation_proxy_spec.rb +0 -202
- data/spec/unit/repository/changeset_spec.rb +0 -197
- data/spec/unit/repository/inspect_spec.rb +0 -18
- data/spec/unit/repository/session_spec.rb +0 -251
- data/spec/unit/repository/transaction_spec.rb +0 -42
- data/spec/unit/session_spec.rb +0 -46
- data/spec/unit/struct_builder_spec.rb +0 -128
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 748ea9ec748c486d611e4ac107cf338362a76b51
|
4
|
+
data.tar.gz: 111dd4763fbe363d22e4fe0179e52c3a0d343531
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4027a4c8fd3cacfb40a6f0ffe99bae2d88b0e98cd3a8993ef83b6a07e2fac9510e528578b71a1abb673dea61e9dd93b832406a002d7b80e457d1abfc66174549
|
7
|
+
data.tar.gz: 5f45222483b70724de8837fa0e2d3cb87737f5acf6944fbccd3c26fc110dd2b5c9d52a76082902a29d3d96a17a8053c131af62214bcb56412ddb74662843871d
|
data/CHANGELOG.md
CHANGED
@@ -1,17 +1,25 @@
|
|
1
|
-
#
|
1
|
+
# v2.0.0 to-be-released
|
2
2
|
|
3
|
-
###
|
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
|
-
|
6
|
-
* Deprecation warnings in preparation for rom 4.0 release (solnic)
|
11
|
+
### Internal
|
7
12
|
|
8
|
-
|
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
|
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
|
|
data/{LICENSE.txt → LICENSE}
RENAMED
data/README.md
CHANGED
@@ -1 +1,18 @@
|
|
1
|
-
|
1
|
+
[gem]: https://rubygems.org/gems/rom-repository
|
2
|
+
[gemnasium]: https://gemnasium.com/rom-rb/rom-repository
|
3
|
+
|
4
|
+
# rom-repository
|
5
|
+
|
6
|
+
[][gem]
|
7
|
+
[][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.
|
data/lib/rom-repository.rb
CHANGED
data/lib/rom/repository.rb
CHANGED
@@ -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
|
121
|
-
def initialize(container,
|
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}
|
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
|
-
|
111
|
-
map_tuple(changeset.relation, changeset.commit)
|
96
|
+
input[0].commit
|
112
97
|
else
|
113
|
-
command(type
|
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
|
-
|
114
|
+
changeset.commit
|
130
115
|
else
|
131
|
-
command(type
|
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
|