rom-repository 1.3.1 → 1.3.2
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/.travis.yml +8 -5
- data/CHANGELOG.md +12 -0
- data/lib/rom/repository/changeset/create.rb +4 -0
- data/lib/rom/repository/changeset/stateful.rb +11 -2
- data/lib/rom/repository/changeset/update.rb +5 -2
- data/lib/rom/repository/relation_proxy/wrap.rb +1 -1
- data/lib/rom/repository/root.rb +1 -1
- data/lib/rom/repository/version.rb +1 -1
- data/spec/integration/changeset_spec.rb +50 -0
- data/spec/integration/multi_adapter_spec.rb +13 -2
- data/spec/integration/repository_spec.rb +11 -0
- data/spec/shared/database.rb +7 -6
- data/spec/shared/relations.rb +10 -0
- data/spec/shared/repo.rb +1 -1
- data/spec/spec_helper.rb +11 -7
- data/spec/unit/changeset/map_spec.rb +28 -1
- data/spec/unit/changeset_spec.rb +18 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d274cac190d09e34254d67581d2cd8647e30301
|
4
|
+
data.tar.gz: 39db9816c2762e1c47422df900b85d4d82b91556
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55676bbb6a54903a047c3218334038039e8a26d3239ddec34011cef262450f6ed56a63bc0074c1094ebc5d547a845f8ffa20c0ad8ec9b4d5feed2c1eabcb7e09
|
7
|
+
data.tar.gz: 9e04a30eecd17b3741f22c3efac94f7a643d73b68dd781bf15e80f37a00be65eb2c5cdb13214ad0b3016e0fe877df7478c6a1c958dd08af654d345ca27880e4e
|
data/.travis.yml
CHANGED
@@ -8,13 +8,16 @@ before_script:
|
|
8
8
|
- rvm get master
|
9
9
|
script: "bundle exec rake ci"
|
10
10
|
after_success:
|
11
|
-
- '[
|
11
|
+
- '[ -d coverage ] && bundle exec codeclimate-test-reporter'
|
12
12
|
rvm:
|
13
|
-
- 2.
|
14
|
-
- 2.3
|
15
|
-
- 2.
|
13
|
+
- 2.2.7
|
14
|
+
- 2.3.4
|
15
|
+
- 2.4.1
|
16
16
|
- rbx-3
|
17
|
-
- jruby-9.1.
|
17
|
+
- jruby-9.1.8.0
|
18
|
+
matrix:
|
19
|
+
allow_failures:
|
20
|
+
- rvm: rbx-3
|
18
21
|
env:
|
19
22
|
global:
|
20
23
|
- JRUBY_OPTS='--dev -J-Xmx1024M'
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
# v1.3.2 2017-05-02
|
2
|
+
|
3
|
+
### Fixed
|
4
|
+
|
5
|
+
* Fix building changesets with relation using `Root#changeset` (flash-gordon)
|
6
|
+
* Fix wrap when aliased relation is used (solnic)
|
7
|
+
* Fix accessing `data` in map block in changesets (flash-gordon+solnic)
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
|
11
|
+
* Calculate diff only with respect to keys present on the original tuple (yuszuv+solnic)
|
12
|
+
|
1
13
|
# v1.3.1 2017-03-25
|
2
14
|
|
3
15
|
### Fixed
|
@@ -18,7 +18,7 @@ module ROM
|
|
18
18
|
# @!attribute [r] pipe
|
19
19
|
# @return [Changeset::Pipe] data transformation pipe
|
20
20
|
# @api private
|
21
|
-
option :pipe,
|
21
|
+
option :pipe, reader: false, optional: true
|
22
22
|
|
23
23
|
# Define a changeset mapping
|
24
24
|
#
|
@@ -56,7 +56,7 @@ module ROM
|
|
56
56
|
#
|
57
57
|
# @api public
|
58
58
|
def self.map(&block)
|
59
|
-
if block.
|
59
|
+
if block.parameters.empty?
|
60
60
|
pipes << Class.new(Pipe, &block).new
|
61
61
|
else
|
62
62
|
pipes << Pipe.new(block)
|
@@ -212,6 +212,15 @@ module ROM
|
|
212
212
|
%(#<#{self.class} relation=#{relation.name.inspect} data=#{__data__}>)
|
213
213
|
end
|
214
214
|
|
215
|
+
# Data transformation pipe
|
216
|
+
#
|
217
|
+
# @return [Changeset::Pipe]
|
218
|
+
#
|
219
|
+
# @api private
|
220
|
+
def pipe
|
221
|
+
@pipe ||= self.class.default_pipe(self)
|
222
|
+
end
|
223
|
+
|
215
224
|
private
|
216
225
|
|
217
226
|
# @api private
|
@@ -77,8 +77,11 @@ module ROM
|
|
77
77
|
def diff
|
78
78
|
@diff ||=
|
79
79
|
begin
|
80
|
-
|
81
|
-
|
80
|
+
data_tuple = __data__.to_a
|
81
|
+
data_keys = __data__.keys & original.keys
|
82
|
+
|
83
|
+
new_tuple = data_tuple.to_a.select { |(k, _)| data_keys.include?(k) }
|
84
|
+
ori_tuple = original.to_a.select { |(k, _)| data_keys.include?(k) }
|
82
85
|
|
83
86
|
Hash[new_tuple - (new_tuple & ori_tuple)]
|
84
87
|
end
|
@@ -69,7 +69,7 @@ module ROM
|
|
69
69
|
def wraps_from_names(names)
|
70
70
|
names.map { |name|
|
71
71
|
assoc = associations[name]
|
72
|
-
registry[assoc.target].wrapped(name, assoc.combine_keys(__registry__), true)
|
72
|
+
registry[assoc.target.relation].wrapped(name, assoc.combine_keys(__registry__), true)
|
73
73
|
}
|
74
74
|
end
|
75
75
|
end
|
data/lib/rom/repository/root.rb
CHANGED
@@ -2,6 +2,22 @@ RSpec.describe 'Using changesets' do
|
|
2
2
|
include_context 'database'
|
3
3
|
include_context 'relations'
|
4
4
|
|
5
|
+
before do
|
6
|
+
module Test
|
7
|
+
class User < Dry::Struct
|
8
|
+
attribute :id, Dry::Types['strict.int']
|
9
|
+
attribute :name, Dry::Types['strict.string']
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
configuration.mappers do
|
14
|
+
define(:users) do
|
15
|
+
model Test::User
|
16
|
+
register_as :user
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
5
21
|
describe 'Create' do
|
6
22
|
subject(:repo) do
|
7
23
|
Class.new(ROM::Repository[:users]) {
|
@@ -10,6 +26,18 @@ RSpec.describe 'Using changesets' do
|
|
10
26
|
}.new(rom)
|
11
27
|
end
|
12
28
|
|
29
|
+
let(:create_changeset) do
|
30
|
+
Class.new(ROM::Changeset::Create)
|
31
|
+
end
|
32
|
+
|
33
|
+
let(:add_book_changeset) do
|
34
|
+
Class.new(ROM::Changeset::Create[:books])
|
35
|
+
end
|
36
|
+
|
37
|
+
let(:update_changeset) do
|
38
|
+
Class.new(ROM::Changeset::Update)
|
39
|
+
end
|
40
|
+
|
13
41
|
it 'can be passed to a command' do
|
14
42
|
changeset = repo.changeset(name: "Jane Doe")
|
15
43
|
command = repo.command(:create, repo.users)
|
@@ -70,6 +98,28 @@ RSpec.describe 'Using changesets' do
|
|
70
98
|
expect(result.created_at).to be_instance_of(Time)
|
71
99
|
expect(result.updated_at).to be_instance_of(Time)
|
72
100
|
end
|
101
|
+
|
102
|
+
it 'preserves relation mappers with create' do
|
103
|
+
changeset = repo.
|
104
|
+
changeset(create_changeset).
|
105
|
+
new(repo.users.relation.as(:user)).
|
106
|
+
data(name: 'Joe Dane')
|
107
|
+
|
108
|
+
expect(changeset.commit).to eql(Test::User.new(id: 1, name: 'Joe Dane'))
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'creates changesets for non-root relations' do
|
112
|
+
repo.create(name: 'John Doe')
|
113
|
+
changeset = repo.changeset(add_book_changeset).data(title: 'The War of the Worlds')
|
114
|
+
|
115
|
+
expect(changeset.commit).
|
116
|
+
to include(
|
117
|
+
id: 1,
|
118
|
+
title: 'The War of the Worlds',
|
119
|
+
created_at: nil,
|
120
|
+
updated_at: nil
|
121
|
+
)
|
122
|
+
end
|
73
123
|
end
|
74
124
|
|
75
125
|
describe 'Update' do
|
@@ -1,8 +1,11 @@
|
|
1
|
+
# coding: utf-8
|
1
2
|
RSpec.describe 'Repository with multi-adapters configuration' do
|
2
|
-
let
|
3
|
+
let(:configuration) {
|
3
4
|
ROM::Configuration.new(default: [:sql, DB_URI], memory: [:memory])
|
4
5
|
}
|
5
6
|
|
7
|
+
let(:sql_conn) { configuration.gateways[:default].connection }
|
8
|
+
|
6
9
|
let(:rom) { ROM.container(configuration) }
|
7
10
|
|
8
11
|
let(:users) { rom.relation(:sql_users) }
|
@@ -11,6 +14,14 @@ RSpec.describe 'Repository with multi-adapters configuration' do
|
|
11
14
|
let(:repo) { Test::Repository.new(rom) }
|
12
15
|
|
13
16
|
before do
|
17
|
+
[:tags, :tasks, :posts, :books, :users, :posts_labels, :labels,
|
18
|
+
:reactions, :messages].each { |table| sql_conn.drop_table?(table) }
|
19
|
+
|
20
|
+
sql_conn.create_table :users do
|
21
|
+
primary_key :id
|
22
|
+
column :name, String
|
23
|
+
end
|
24
|
+
|
14
25
|
module Test
|
15
26
|
class Users < ROM::Relation[:sql]
|
16
27
|
gateway :default
|
@@ -34,7 +45,7 @@ RSpec.describe 'Repository with multi-adapters configuration' do
|
|
34
45
|
end
|
35
46
|
|
36
47
|
def for_users(users)
|
37
|
-
restrict(user_id: users.
|
48
|
+
restrict(user_id: users.pluck(:id))
|
38
49
|
end
|
39
50
|
end
|
40
51
|
|
@@ -71,6 +71,17 @@ RSpec.describe 'ROM repository' do
|
|
71
71
|
expect(repo.tag_with_wrapped_task.first).to eql(tag_with_task)
|
72
72
|
end
|
73
73
|
|
74
|
+
it 'loads wraps using aliased relation' do
|
75
|
+
author = repo.users.where(name: 'Jane').one
|
76
|
+
|
77
|
+
repo.command(:create, repo.books).(title: 'Hello World', author_id: author.id)
|
78
|
+
|
79
|
+
book = repo.books.wrap(:author).to_a.first
|
80
|
+
|
81
|
+
expect(book.author.id).to eql(author.id)
|
82
|
+
expect(book.author.name).to eql(author.name)
|
83
|
+
end
|
84
|
+
|
74
85
|
it 'loads multiple wraps' do
|
75
86
|
post_label = repo.posts_labels.wrap(:post).wrap(:label).to_a.first
|
76
87
|
|
data/spec/shared/database.rb
CHANGED
@@ -14,21 +14,22 @@ RSpec.shared_context 'database' do
|
|
14
14
|
include_context 'database setup'
|
15
15
|
|
16
16
|
before do
|
17
|
-
[:tags, :tasks, :posts, :users, :posts_labels, :labels,
|
17
|
+
[:tags, :tasks, :posts, :books, :users, :posts_labels, :labels,
|
18
18
|
:reactions, :messages].each { |table| conn.drop_table?(table) }
|
19
19
|
|
20
|
+
conn.create_table :users do
|
21
|
+
primary_key :id
|
22
|
+
column :name, String
|
23
|
+
end
|
24
|
+
|
20
25
|
conn.create_table :books do
|
21
26
|
primary_key :id
|
27
|
+
foreign_key :author_id, :users, on_delete: :cascade
|
22
28
|
column :title, String
|
23
29
|
column :created_at, Time
|
24
30
|
column :updated_at, Time
|
25
31
|
end
|
26
32
|
|
27
|
-
conn.create_table :users do
|
28
|
-
primary_key :id
|
29
|
-
column :name, String
|
30
|
-
end
|
31
|
-
|
32
33
|
conn.create_table :tasks do
|
33
34
|
primary_key :id
|
34
35
|
foreign_key :user_id, :users, null: false, on_delete: :cascade
|
data/spec/shared/relations.rb
CHANGED
@@ -9,9 +9,14 @@ RSpec.shared_context 'relations' do
|
|
9
9
|
configuration.relation(:books) do
|
10
10
|
schema(:books) do
|
11
11
|
attribute :id, ROM::SQL::Types::Serial
|
12
|
+
attribute :author_id, ROM::SQL::Types.ForeignKey(:users)
|
12
13
|
attribute :title, ROM::SQL::Types::String
|
13
14
|
attribute :created_at, ROM::SQL::Types::Time
|
14
15
|
attribute :updated_at, ROM::SQL::Types::Time
|
16
|
+
|
17
|
+
associations do
|
18
|
+
belongs_to :users, as: :author, relation: :authors, foreign_key: :author_id
|
19
|
+
end
|
15
20
|
end
|
16
21
|
end
|
17
22
|
|
@@ -21,6 +26,7 @@ RSpec.shared_context 'relations' do
|
|
21
26
|
has_many :posts
|
22
27
|
has_many :posts, as: :aliased_posts
|
23
28
|
has_many :labels, through: :posts
|
29
|
+
has_many :books, foreign_key: :author_id
|
24
30
|
end
|
25
31
|
end
|
26
32
|
|
@@ -37,6 +43,10 @@ RSpec.shared_context 'relations' do
|
|
37
43
|
end
|
38
44
|
end
|
39
45
|
|
46
|
+
configuration.relation(:authors) do
|
47
|
+
schema(:users, infer: true)
|
48
|
+
end
|
49
|
+
|
40
50
|
configuration.relation(:tasks) do
|
41
51
|
schema(infer: true) do
|
42
52
|
associations do
|
data/spec/shared/repo.rb
CHANGED
@@ -6,7 +6,7 @@ RSpec.shared_context('repo') do
|
|
6
6
|
|
7
7
|
let(:repo_class) do
|
8
8
|
Class.new(ROM::Repository[:users]) do
|
9
|
-
relations :tasks, :tags, :posts, :labels, :posts_labels
|
9
|
+
relations :tasks, :tags, :posts, :labels, :posts_labels, :books, :authors
|
10
10
|
|
11
11
|
def find_users(criteria)
|
12
12
|
users.find(criteria)
|
data/spec/spec_helper.rb
CHANGED
@@ -1,13 +1,17 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
# this is needed for guard to work, not sure why :(
|
4
2
|
require "bundler"
|
5
3
|
Bundler.setup
|
6
4
|
|
7
|
-
if
|
8
|
-
require '
|
9
|
-
|
10
|
-
|
5
|
+
if RUBY_ENGINE == 'ruby' && ENV['COVERAGE'] == 'true'
|
6
|
+
require 'yaml'
|
7
|
+
rubies = YAML.load(File.read(File.join(__dir__, '..', '.travis.yml')))['rvm']
|
8
|
+
latest_mri = rubies.select { |v| v =~ /\A\d+\.\d+.\d+\z/ }.max
|
9
|
+
|
10
|
+
if RUBY_VERSION == latest_mri
|
11
|
+
require 'simplecov'
|
12
|
+
SimpleCov.start do
|
13
|
+
add_filter '/spec/'
|
14
|
+
end
|
11
15
|
end
|
12
16
|
end
|
13
17
|
|
@@ -61,7 +65,7 @@ Warning.extend(SileneceWarnings) if warning_api_available
|
|
61
65
|
|
62
66
|
RSpec.configure do |config|
|
63
67
|
config.disable_monkey_patching!
|
64
|
-
config.warnings =
|
68
|
+
config.warnings = warning_api_available
|
65
69
|
|
66
70
|
config.after do
|
67
71
|
Test.remove_constants
|
@@ -42,6 +42,29 @@ RSpec.describe ROM::Changeset, '.map' do
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
+
context 'accessing data in a map block' do
|
46
|
+
subject(:changeset) do
|
47
|
+
Class.new(ROM::Changeset::Create[:users]) do
|
48
|
+
map do |tuple|
|
49
|
+
extend_data(tuple)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def extend_data(tuple)
|
55
|
+
tuple.merge(email: "#{self[:name].downcase}@test.com")
|
56
|
+
end
|
57
|
+
end.new(relation).data(user_data)
|
58
|
+
end
|
59
|
+
|
60
|
+
let(:relation) { double(:relation) }
|
61
|
+
let(:user_data) { { name: 'Jane' } }
|
62
|
+
|
63
|
+
it 'extends data in a map block' do
|
64
|
+
expect(changeset.to_h).to eql(name: 'Jane', email: 'jane@test.com')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
45
68
|
context 'multi mapping with custom blocks' do
|
46
69
|
subject(:changeset) do
|
47
70
|
Class.new(ROM::Changeset::Create[:users]) do
|
@@ -53,6 +76,10 @@ RSpec.describe ROM::Changeset, '.map' do
|
|
53
76
|
tuple.merge(two: next_value)
|
54
77
|
end
|
55
78
|
|
79
|
+
map do |three: next_value, **other|
|
80
|
+
{ three: three, **other }
|
81
|
+
end
|
82
|
+
|
56
83
|
def initialize(*args)
|
57
84
|
super
|
58
85
|
@counter = 0
|
@@ -72,7 +99,7 @@ RSpec.describe ROM::Changeset, '.map' do
|
|
72
99
|
let(:user_data) { { name: 'Jane' } }
|
73
100
|
|
74
101
|
it 'applies mappings in order of definition' do
|
75
|
-
expect(changeset.to_h).to eql(name: 'Jane', one: 1, two: 2)
|
102
|
+
expect(changeset.to_h).to eql(name: 'Jane', one: 1, two: 2, three: 3)
|
76
103
|
end
|
77
104
|
|
78
105
|
it 'inherits pipes' do
|
data/spec/unit/changeset_spec.rb
CHANGED
@@ -32,13 +32,21 @@ RSpec.describe ROM::Changeset do
|
|
32
32
|
|
33
33
|
expect(changeset.diff).to eql(name: "Jane Doe")
|
34
34
|
end
|
35
|
+
|
36
|
+
it 'does not consider keys that are not present on the original tuple' do
|
37
|
+
expect(relation).to receive(:one).and_return(jane)
|
38
|
+
|
39
|
+
changeset = ROM::Changeset::Update.new(relation).data(foo: 'bar')
|
40
|
+
|
41
|
+
expect(changeset.diff).to eql({})
|
42
|
+
end
|
35
43
|
end
|
36
44
|
|
37
45
|
describe '#diff?' do
|
38
46
|
it 'returns true when data differs from the original tuple' do
|
39
47
|
expect(relation).to receive(:one).and_return(jane)
|
40
48
|
|
41
|
-
changeset = ROM::Changeset::Update.new(relation
|
49
|
+
changeset = ROM::Changeset::Update.new(relation).data(name: "Jane Doe")
|
42
50
|
|
43
51
|
expect(changeset).to be_diff
|
44
52
|
end
|
@@ -46,7 +54,15 @@ RSpec.describe ROM::Changeset do
|
|
46
54
|
it 'returns false when data are equal to the original tuple' do
|
47
55
|
expect(relation).to receive(:one).and_return(jane)
|
48
56
|
|
49
|
-
changeset = ROM::Changeset::Update.new(relation
|
57
|
+
changeset = ROM::Changeset::Update.new(relation).data(name: 'Jane')
|
58
|
+
|
59
|
+
expect(changeset).to_not be_diff
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'returns false when data contains keys that are not available on the original tuple' do
|
63
|
+
expect(relation).to receive(:one).and_return(jane)
|
64
|
+
|
65
|
+
changeset = ROM::Changeset::Update.new(relation).data(foo: 'bar')
|
50
66
|
|
51
67
|
expect(changeset).to_not be_diff
|
52
68
|
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.3.
|
4
|
+
version: 1.3.2
|
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-
|
11
|
+
date: 2017-05-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rom
|
@@ -191,7 +191,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
191
191
|
version: '0'
|
192
192
|
requirements: []
|
193
193
|
rubyforge_project:
|
194
|
-
rubygems_version: 2.6.
|
194
|
+
rubygems_version: 2.6.11
|
195
195
|
signing_key:
|
196
196
|
specification_version: 4
|
197
197
|
summary: Repository abstraction for rom-rb
|