rom-repository 1.0.0.beta3 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,23 +12,15 @@ require 'rom/repository/session'
12
12
  module ROM
13
13
  # Abstract repository class to inherit from
14
14
  #
15
- # A repository provides access to composable relations and commands. Its job is
16
- # to provide application-specific data that is already materialized, so that
15
+ # A repository provides access to composable relations, commands and changesets.
16
+ # Its job is to provide application-specific data that is already materialized, so that
17
17
  # relations don't leak into your application layer.
18
18
  #
19
- # Typically, you're going to work with Repository::Root that are configured to
20
- # use a single relation as its root, and compose aggregates and use commands
19
+ # Typically, you're going to work with Repository::Root that is configured to
20
+ # use a single relation as its root, and compose aggregates and use changesets and commands
21
21
  # against the root relation.
22
22
  #
23
23
  # @example
24
- # class MyRepo < ROM::Repository[:users]
25
- # relations :users, :tasks
26
- #
27
- # def users_with_tasks
28
- # users.combine_children(tasks: tasks).to_a
29
- # end
30
- # end
31
- #
32
24
  # rom = ROM.container(:sql, 'sqlite::memory') do |conf|
33
25
  # conf.default.create_table(:users) do
34
26
  # primary_key :id
@@ -40,15 +32,36 @@ module ROM
40
32
  # column :user_id, Integer
41
33
  # column :title, String
42
34
  # end
35
+ #
36
+ # conf.relation(:users) do
37
+ # associations do
38
+ # has_many :tasks
39
+ # end
40
+ # end
41
+ # end
42
+ #
43
+ # class UserRepo < ROM::Repository[:users]
44
+ # relations :tasks
45
+ #
46
+ # def users_with_tasks
47
+ # aggregate(:tasks).to_a
48
+ # end
43
49
  # end
44
50
  #
45
- # my_repo = MyRepo.new(rom)
46
- # my_repo.users_with_tasks
51
+ # user_repo = UserRepo.new(rom)
52
+ # user_repo.users_with_tasks
47
53
  #
48
54
  # @see Repository::Root
49
55
  #
50
56
  # @api public
51
57
  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
+
52
65
  extend ClassInterface
53
66
 
54
67
  # @!attribute [r] container
@@ -63,7 +76,8 @@ module ROM
63
76
  # @return [MapperBuilder] The auto-generated mappers for repo relations
64
77
  attr_reader :mappers
65
78
 
66
- # @api private
79
+ # @!attribute [r] commmand_compiler
80
+ # @return [Method] Function for compiling commands bound to a repo instance
67
81
  attr_reader :command_compiler
68
82
 
69
83
  # Initializes a new repo by establishing configured relation proxies from
@@ -91,6 +105,8 @@ module ROM
91
105
  @command_compiler = method(:command)
92
106
  end
93
107
 
108
+ # Return a command for a relation
109
+ #
94
110
  # @overload command(type, relation)
95
111
  # Returns a command for a relation
96
112
  #
@@ -138,6 +154,8 @@ module ROM
138
154
  end
139
155
  end
140
156
 
157
+ # Return a changeset for a relation
158
+ #
141
159
  # @overload changeset(name, attributes)
142
160
  # Return a create changeset for a given relation identifier
143
161
  #
@@ -170,6 +188,16 @@ module ROM
170
188
  #
171
189
  # @return [Changeset]
172
190
  #
191
+ # @overload changeset(opts)
192
+ # Return a changeset object using provided changeset type and relation
193
+ #
194
+ # @example
195
+ # repo.changeset(delete: repo.users.where { id > 10 })
196
+ #
197
+ # @param [Hash<Symbol=>Relation] opts Command type => Relation config
198
+ #
199
+ # @return [Changeset]
200
+ #
173
201
  # @api public
174
202
  def changeset(*args)
175
203
  opts = { command_compiler: command_compiler }
@@ -179,10 +207,14 @@ module ROM
179
207
  elsif args.size == 3
180
208
  name, pk, data = args
181
209
  elsif args.size == 1
182
- type = args[0]
210
+ if args[0].is_a?(Class)
211
+ klass = args[0]
183
212
 
184
- if type.is_a?(Class) && type < Changeset
185
- return type.new(relations[type.relation], opts)
213
+ if klass < Changeset
214
+ return klass.new(relations[klass.relation], opts)
215
+ else
216
+ raise ArgumentError, "+#{klass.name}+ is not a Changeset subclass"
217
+ end
186
218
  else
187
219
  type, relation = args[0].to_a[0]
188
220
  end
@@ -191,41 +223,69 @@ module ROM
191
223
  end
192
224
 
193
225
  if type
194
- if type.equal?(:delete)
195
- Changeset::Delete.new(relation, opts)
196
- end
226
+ klass = CHANGESET_TYPES.fetch(type) {
227
+ raise ArgumentError, "+#{type.inspect}+ is not a valid changeset type. Must be one of: #{CHANGESET_TYPES.keys.inspect}"
228
+ }
229
+
230
+ klass.new(relation, opts)
197
231
  else
198
232
  relation = relations[name]
199
233
 
200
234
  if pk
201
- Changeset::Update.new(relation, opts.merge(__data__: data, primary_key: pk))
235
+ Changeset::Update.new(relation.by_pk(pk), opts.update(__data__: data))
202
236
  else
203
- Changeset::Create.new(relation, opts.merge(__data__: data))
237
+ Changeset::Create.new(relation, opts.update(__data__: data))
204
238
  end
205
239
  end
206
240
  end
207
241
 
208
- # TODO: document me, please
242
+ # Open a database transaction
209
243
  #
210
- # @api public
211
- def session(&block)
212
- session = Session.new(self)
213
- yield(session)
214
- transaction { session.commit! }
215
- end
216
-
217
- # TODO: document me, please
244
+ # @example commited transaction
245
+ # user = transaction do |t|
246
+ # create(changeset(name: 'Jane'))
247
+ # end
248
+ #
249
+ # user
250
+ # # => #<ROM::Struct[User] id=1 name="Jane">
251
+ #
252
+ # @example with a rollback
253
+ # user = transaction do |t|
254
+ # changeset(name: 'Jane').commit
255
+ # t.rollback!
256
+ # end
257
+ #
258
+ # user
259
+ # # nil
218
260
  #
219
261
  # @api public
220
262
  def transaction(&block)
221
263
  container.gateways[:default].transaction(&block)
222
264
  end
223
265
 
266
+ # Return a string representation of a repository object
267
+ #
268
+ # @return [String]
269
+ #
224
270
  # @api public
225
271
  def inspect
226
272
  %(#<#{self.class} relations=[#{self.class.relations.map(&:inspect).join(' ')}]>)
227
273
  end
228
274
 
275
+ # Start a session for multiple changesets
276
+ #
277
+ # TODO: this is partly done, needs tweaks in changesets so that we can gather
278
+ # command results and return them in a nice way
279
+ #
280
+ # @!visibility private
281
+ #
282
+ # @api public
283
+ def session(&block)
284
+ session = Session.new(self)
285
+ yield(session)
286
+ transaction { session.commit! }
287
+ end
288
+
229
289
  private
230
290
 
231
291
  # Local command cache
data/lib/rom/struct.rb CHANGED
@@ -1,9 +1,47 @@
1
1
  require 'dry/struct'
2
2
 
3
3
  module ROM
4
- # Simple data-struct
4
+ # Simple data-struct class
5
5
  #
6
- # By default mappers use this as the model
6
+ # ROM structs are plain data structures loaded by repositories.
7
+ # They implement Hash protocol which means that they can be used
8
+ # in places where Hash-like objects are supported.
9
+ #
10
+ # Repositories define subclasses of ROM::Struct automatically, they are not
11
+ # defined as constants in any module, instead, generated mappers are configured
12
+ # to use anonymous struct classes as models.
13
+ #
14
+ # Structs are based on dry-struct gem, they include `schema` with detailed information
15
+ # about attribute types returned from relations, thus can be introspected to build
16
+ # additional functionality when desired.
17
+ #
18
+ # @example accessing relation struct model
19
+ # rom = ROM.container(:sql, 'sqlite::memory') do |conf|
20
+ # conf.default.create_table(:users) do
21
+ # primary_key :id
22
+ # column :name, String
23
+ # end
24
+ # end
25
+ #
26
+ # class UserRepo < ROM::Repository[:users]
27
+ # end
28
+ #
29
+ # user_repo = UserRepo.new(rom)
30
+ #
31
+ # # get auto-generated User struct
32
+ # model = user_repo.users.mapper.model
33
+ # # => ROM::Struct[User]
34
+ #
35
+ # # see struct's schema attributes
36
+ #
37
+ # # model.schema[:id]
38
+ # # => #<Dry::Types::Constrained type=#<Dry::Types::Definition primitive=Integer options={}> options={:rule=>#<Dry::Logic::Rule::Predicate predicate=#<Method: Module(Dry::Logic::Predicates::Methods)#gt?> options={:args=>[0]}>, :meta=>{:primary_key=>true, :name=>:id, :source=>ROM::Relation::Name(users)}} rule=#<Dry::Logic::Rule::Predicate predicate=#<Method: Module(Dry::Logic::Predicates::Methods)#gt?> options={:args=>[0]}>>
39
+ #
40
+ # model.schema[:name]
41
+ # # => #<Dry::Types::Sum left=#<Dry::Types::Constrained type=#<Dry::Types::Definition primitive=NilClass options={}> options={:rule=>#<Dry::Logic::Rule::Predicate predicate=#<Method: Module(Dry::Logic::Predicates::Methods)#type?> options={:args=>[NilClass]}>} rule=#<Dry::Logic::Rule::Predicate predicate=#<Method: Module(Dry::Logic::Predicates::Methods)#type?> options={:args=>[NilClass]}>> right=#<Dry::Types::Definition primitive=String options={}> options={:meta=>{:name=>:name, :source=>ROM::Relation::Name(users)}}>
42
+ #
43
+ # @see http://dry-rb.org/gems/dry-struct dry-struct
44
+ # @see http://dry-rb.org/gems/dry-types dry-types
7
45
  #
8
46
  # @api public
9
47
  class Struct < Dry::Struct
@@ -15,8 +15,8 @@ Gem::Specification.new do |gem|
15
15
  gem.test_files = `git ls-files -- {spec}/*`.split("\n")
16
16
  gem.license = 'MIT'
17
17
 
18
- gem.add_runtime_dependency 'rom', '~> 3.0.0.beta'
19
- gem.add_runtime_dependency 'rom-mapper', '~> 0.5.0.beta'
18
+ gem.add_runtime_dependency 'rom', '~> 3.0.0.rc'
19
+ gem.add_runtime_dependency 'rom-mapper', '~> 0.5.0.rc'
20
20
  gem.add_runtime_dependency 'dry-core', '~> 0.2', '>= 0.2.1'
21
21
  gem.add_runtime_dependency 'dry-struct', '~> 0.1'
22
22
 
@@ -43,6 +43,33 @@ RSpec.describe 'Using changesets' do
43
43
  expect(result.created_at).to be_instance_of(Time)
44
44
  expect(result.updated_at).to be_instance_of(Time)
45
45
  end
46
+
47
+ it 'preprocesses data using custom block' do
48
+ changeset = repo.
49
+ changeset(:books, title: "rom-rb is awesome").
50
+ map { |tuple| tuple.merge(created_at: Time.now) }
51
+
52
+ command = repo.command(:create, repo.books)
53
+ result = command.(changeset)
54
+
55
+ expect(result.id).to_not be(nil)
56
+ expect(result.title).to eql("rom-rb is awesome")
57
+ expect(result.created_at).to be_instance_of(Time)
58
+ end
59
+
60
+ it 'preprocesses data using built-in steps and custom block' do
61
+ changeset = repo.
62
+ changeset(:books, title: "rom-rb is awesome").
63
+ map(:touch) { |tuple| tuple.merge(created_at: Time.now) }
64
+
65
+ command = repo.command(:create, repo.books)
66
+ result = command.(changeset)
67
+
68
+ expect(result.id).to_not be(nil)
69
+ expect(result.title).to eql("rom-rb is awesome")
70
+ expect(result.created_at).to be_instance_of(Time)
71
+ expect(result.updated_at).to be_instance_of(Time)
72
+ end
46
73
  end
47
74
 
48
75
  describe 'Update' do
@@ -1,6 +1,6 @@
1
1
  RSpec.describe ROM::Changeset do
2
2
  let(:jane) { { id: 2, name: "Jane" } }
3
- let(:relation) { double(ROM::Relation, primary_key: :id) }
3
+ let(:relation) { double(ROM::Relation, name: :users) }
4
4
 
5
5
  describe '.[]' do
6
6
  it 'returns a changeset preconfigured for a specific relation' do
@@ -24,9 +24,9 @@ RSpec.describe ROM::Changeset do
24
24
 
25
25
  describe '#diff' do
26
26
  it 'returns a hash with changes' do
27
- expect(relation).to receive(:fetch).with(2).and_return(jane)
27
+ expect(relation).to receive(:one).and_return(jane)
28
28
 
29
- changeset = ROM::Changeset::Update.new(relation, __data__: { name: "Jane Doe" }, primary_key: 2)
29
+ changeset = ROM::Changeset::Update.new(relation, __data__: { name: "Jane Doe" })
30
30
 
31
31
  expect(changeset.diff).to eql(name: "Jane Doe")
32
32
  end
@@ -34,22 +34,40 @@ RSpec.describe ROM::Changeset do
34
34
 
35
35
  describe '#diff?' do
36
36
  it 'returns true when data differs from the original tuple' do
37
- expect(relation).to receive(:fetch).with(2).and_return(jane)
37
+ expect(relation).to receive(:one).and_return(jane)
38
38
 
39
- changeset = ROM::Changeset::Update.new(relation, __data__: { name: "Jane Doe" }, primary_key: 2)
39
+ changeset = ROM::Changeset::Update.new(relation, __data__: { name: "Jane Doe" })
40
40
 
41
41
  expect(changeset).to be_diff
42
42
  end
43
43
 
44
44
  it 'returns false when data are equal to the original tuple' do
45
- expect(relation).to receive(:fetch).with(2).and_return(jane)
45
+ expect(relation).to receive(:one).and_return(jane)
46
46
 
47
- changeset = ROM::Changeset::Update.new(relation, __data__: { name: "Jane" }, primary_key: 2)
47
+ changeset = ROM::Changeset::Update.new(relation, __data__: { name: "Jane" })
48
48
 
49
49
  expect(changeset).to_not be_diff
50
50
  end
51
51
  end
52
52
 
53
+ describe '#clean?' do
54
+ it 'returns true when data are equal to the original tuple' do
55
+ expect(relation).to receive(:one).and_return(jane)
56
+
57
+ changeset = ROM::Changeset::Update.new(relation, __data__: { name: "Jane" })
58
+
59
+ expect(changeset).to be_clean
60
+ end
61
+
62
+ it 'returns false when data differs from the original tuple' do
63
+ expect(relation).to receive(:one).and_return(jane)
64
+
65
+ changeset = ROM::Changeset::Update.new(relation, __data__: { name: "Jane Doe" })
66
+
67
+ expect(changeset).to_not be_clean
68
+ end
69
+ end
70
+
53
71
  describe 'quacks like a hash' do
54
72
  subject(:changeset) { ROM::Changeset::Create.new(relation, __data__: data) }
55
73
 
@@ -101,4 +119,24 @@ RSpec.describe ROM::Changeset do
101
119
  expect { changeset.not_here }.to raise_error(NoMethodError, /not_here/)
102
120
  end
103
121
  end
122
+
123
+ describe '#inspect' do
124
+ context 'with a stateful changeset' do
125
+ subject(:changeset) { ROM::Changeset::Create.new(relation).data(name: 'Jane') }
126
+
127
+ specify do
128
+ expect(changeset.inspect).
129
+ to eql('#<ROM::Changeset::Create relation=:users data={:name=>"Jane"}>')
130
+ end
131
+ end
132
+
133
+ context 'with a data-less changeset' do
134
+ subject(:changeset) { ROM::Changeset::Delete.new(relation) }
135
+
136
+ specify do
137
+ expect(changeset.inspect).
138
+ to eql('#<ROM::Changeset::Delete relation=:users>')
139
+ end
140
+ end
141
+ end
104
142
  end
@@ -20,8 +20,8 @@ RSpec.describe ROM::Repository, '#changeset' do
20
20
  expect(changeset.relation).to be(repo.users)
21
21
  end
22
22
 
23
- it 'can return a dedicated command' do
24
- expect(changeset.command.call).to eql(id: 1, name: 'Jane')
23
+ it 'can be commited' do
24
+ expect(changeset.commit).to eql(id: 1, name: 'Jane')
25
25
  end
26
26
  end
27
27
 
@@ -42,35 +42,53 @@ RSpec.describe ROM::Repository, '#changeset' do
42
42
  expect(changeset.relation).to be(repo.users)
43
43
  end
44
44
 
45
- it 'can return a dedicated command' do
46
- expect(changeset.command.call).to eql([{ id: 1, name: 'Jane' }, { id: 2, name: 'Joe' }])
45
+ it 'can be commited' do
46
+ expect(changeset.commit).to eql([{ id: 1, name: 'Jane' }, { id: 2, name: 'Joe' }])
47
47
  end
48
48
  end
49
49
  end
50
50
 
51
51
  describe ROM::Changeset::Update do
52
- let(:changeset) do
53
- repo.changeset(:users, user[:id], name: 'Jane Doe')
52
+ let(:data) do
53
+ { name: 'Jane Doe' }
54
54
  end
55
55
 
56
- let(:user) do
57
- repo.command(:create, repo.users).call(name: 'Jane')
58
- end
56
+ shared_context 'a valid update changeset' do
57
+ let(:user) do
58
+ repo.command(:create, repo.users).call(name: 'Jane')
59
+ end
59
60
 
60
- it 'has data' do
61
- expect(changeset.to_h).to eql(name: 'Jane Doe')
62
- end
61
+ it 'has data' do
62
+ expect(changeset.to_h).to eql(name: 'Jane Doe')
63
+ end
64
+
65
+ it 'has diff' do
66
+ expect(changeset.diff).to eql(name: 'Jane Doe')
67
+ end
63
68
 
64
- it 'has diff' do
65
- expect(changeset.diff).to eql(name: 'Jane Doe')
69
+ it 'has relation' do
70
+ expect(changeset.relation.one).to eql(repo.users.by_pk(user[:id]).one)
71
+ end
72
+
73
+ it 'can return be commited' do
74
+ expect(changeset.commit).to eql(id: 1, name: 'Jane Doe')
75
+ end
66
76
  end
67
77
 
68
- it 'has relation' do
69
- expect(changeset.relation).to be(repo.users)
78
+ context 'using PK to restrict a relation' do
79
+ let(:changeset) do
80
+ repo.changeset(:users, user[:id], data)
81
+ end
82
+
83
+ include_context 'a valid update changeset'
70
84
  end
71
85
 
72
- it 'can return a dedicated command' do
73
- expect(changeset.command.call).to eql(id: 1, name: 'Jane Doe')
86
+ context 'using custom relation' do
87
+ let(:changeset) do
88
+ repo.changeset(update: repo.users.by_pk(user[:id])).data(data)
89
+ end
90
+
91
+ include_context 'a valid update changeset'
74
92
  end
75
93
  end
76
94
 
@@ -91,8 +109,8 @@ RSpec.describe ROM::Repository, '#changeset' do
91
109
  expect(changeset.relation).to eql(relation)
92
110
  end
93
111
 
94
- it 'can return a dedicated command' do
95
- expect(changeset.command.call.to_h).to eql(id: 1, name: 'Jane')
112
+ it 'can be commited' do
113
+ expect(changeset.commit.to_h).to eql(id: 1, name: 'Jane')
96
114
  expect(relation.one).to be(nil)
97
115
  end
98
116
  end
@@ -118,8 +136,27 @@ RSpec.describe ROM::Repository, '#changeset' do
118
136
  expect(changeset.relation).to be(repo.users)
119
137
  end
120
138
 
121
- it 'can return a dedicated command' do
122
- expect(changeset.command.call).to eql(id: 1, name: 'Jane')
139
+ it 'can be commited' do
140
+ expect(changeset.commit).to eql(id: 1, name: 'Jane')
123
141
  end
124
142
  end
143
+
144
+ it 'raises ArgumentError when unknown type was used' do
145
+ expect { repo.changeset(not_here: repo.users) }.
146
+ to raise_error(
147
+ ArgumentError,
148
+ '+:not_here+ is not a valid changeset type. Must be one of: [:create, :update, :delete]'
149
+ )
150
+ end
151
+
152
+ it 'raises ArgumentError when unknown class was used' do
153
+ klass = Class.new {
154
+ def self.name
155
+ 'SomeClass'
156
+ end
157
+ }
158
+
159
+ expect { repo.changeset(klass) }.
160
+ to raise_error(ArgumentError, /SomeClass/)
161
+ end
125
162
  end
@@ -4,7 +4,7 @@ RSpec.describe ROM::Repository, '#transaction' do
4
4
  end
5
5
 
6
6
  let(:task_repo) do
7
- Class.new(ROM::Repository[:tasks]) { commands :create }.new(rom)
7
+ Class.new(ROM::Repository[:tasks]) { commands :create, :update }.new(rom)
8
8
  end
9
9
 
10
10
  include_context 'database'
@@ -25,4 +25,18 @@ RSpec.describe ROM::Repository, '#transaction' do
25
25
  expect(task.user_id).to be(user.id)
26
26
  expect(task.title).to eql('Task One')
27
27
  end
28
+
29
+ it 'updating tasks user' do
30
+ jane = user_repo.create(name: 'Jane')
31
+ john = user_repo.create(name: 'John')
32
+ task = task_repo.create(title: 'Jane Task', user_id: jane.id)
33
+
34
+ task = task_repo.transaction do
35
+ task_changeset = task_repo.changeset(task.id, title: 'John Task').associate(john, :user).commit
36
+ task_repo.update(task_changeset)
37
+ end
38
+
39
+ expect(task.user_id).to be(john.id)
40
+ expect(task.title).to eql('John Task')
41
+ end
28
42
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rom-repository
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta3
4
+ version: 1.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-21 00:00:00.000000000 Z
11
+ date: 2017-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rom
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 3.0.0.beta
19
+ version: 3.0.0.rc
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 3.0.0.beta
26
+ version: 3.0.0.rc
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rom-mapper
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.5.0.beta
33
+ version: 0.5.0.rc
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.5.0.beta
40
+ version: 0.5.0.rc
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: dry-core
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -119,9 +119,11 @@ files:
119
119
  - lib/rom-repository.rb
120
120
  - lib/rom/repository.rb
121
121
  - lib/rom/repository/changeset.rb
122
+ - lib/rom/repository/changeset/associated.rb
122
123
  - lib/rom/repository/changeset/create.rb
123
124
  - lib/rom/repository/changeset/delete.rb
124
125
  - lib/rom/repository/changeset/pipe.rb
126
+ - lib/rom/repository/changeset/stateful.rb
125
127
  - lib/rom/repository/changeset/update.rb
126
128
  - lib/rom/repository/class_interface.rb
127
129
  - lib/rom/repository/command_compiler.rb