rom 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/rom/relation.rb CHANGED
@@ -43,24 +43,6 @@ module ROM
43
43
  dataset.each(&block)
44
44
  end
45
45
 
46
- # @api private
47
- def insert(tuple)
48
- dataset.insert(tuple)
49
- self
50
- end
51
-
52
- # @api private
53
- def update(tuple)
54
- dataset.update(tuple)
55
- self
56
- end
57
-
58
- # @api private
59
- def delete
60
- dataset.delete
61
- self
62
- end
63
-
64
46
  end
65
47
 
66
48
  end
@@ -16,6 +16,24 @@ module ROM
16
16
  adapter[name]
17
17
  end
18
18
 
19
+ # Set a logger for the adapter
20
+ #
21
+ # @param [Object] logger
22
+ #
23
+ # @api public
24
+ def use_logger(logger)
25
+ adapter.logger = logger
26
+ end
27
+
28
+ # Return logger used by the adapter
29
+ #
30
+ # @return [Object] logger
31
+ #
32
+ # @api public
33
+ def logger
34
+ adapter.logger
35
+ end
36
+
19
37
  # Return the database connection provided by the adapter
20
38
  #
21
39
  # @api public
@@ -32,14 +50,18 @@ module ROM
32
50
 
33
51
  # @api private
34
52
  def respond_to_missing?(name, include_private = false)
35
- adapter[name]
53
+ adapter.dataset?(name) || super
36
54
  end
37
55
 
38
56
  private
39
57
 
40
58
  # @api private
41
- def method_missing(name)
42
- adapter[name]
59
+ def method_missing(name, *args, &block)
60
+ if adapter.dataset?(name)
61
+ adapter[name]
62
+ else
63
+ super
64
+ end
43
65
  end
44
66
  end
45
67
 
data/lib/rom/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ROM
2
- VERSION = '0.3.1'.freeze
2
+ VERSION = '0.4.0'.freeze
3
3
  end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ require 'logger'
4
+
5
+ describe 'Adapters / Setting logger' do
6
+ let(:logger_class) do
7
+ Class.new do
8
+ attr_reader :messages
9
+
10
+ def initialize
11
+ @messages = []
12
+ end
13
+
14
+ def info(msg)
15
+ @messages << msg
16
+ end
17
+ end
18
+ end
19
+
20
+ let(:logger) do
21
+ logger_class.new
22
+ end
23
+
24
+ it 'sets up a logger for a given adapter' do
25
+ setup = ROM.setup(memory: 'memory://localhost')
26
+
27
+ setup.memory.use_logger(logger)
28
+
29
+ rom = setup.finalize
30
+
31
+ rom.memory.logger.info("test")
32
+
33
+ expect(logger.messages).to eql(["test"])
34
+ end
35
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Commands / Create' do
4
+ include_context 'users and tasks'
5
+
6
+ let(:users) { rom.commands.users }
7
+ let(:tasks) { rom.commands.tasks }
8
+
9
+ before do
10
+ UserValidator = Class.new do
11
+ ValidationError = Class.new(ROM::CommandError)
12
+
13
+ def self.call(params)
14
+ unless params[:name] && params[:email]
15
+ raise ValidationError, ":name and :email are required"
16
+ end
17
+ end
18
+ end
19
+
20
+ setup.relation(:users)
21
+ setup.relation(:tasks)
22
+
23
+ setup.commands(:users) do
24
+ define(:create) do
25
+ validator UserValidator
26
+ end
27
+ end
28
+
29
+ setup.commands(:tasks) do
30
+ define(:create)
31
+ end
32
+
33
+ end
34
+
35
+ it 'inserts user on successful validation' do
36
+ result = users.try { create(name: 'Piotr', email: 'piotr@solnic.eu') }
37
+
38
+ expect(result).to match_array([{ name: 'Piotr', email: 'piotr@solnic.eu' }])
39
+ end
40
+
41
+ it 'inserts user and associated task when things go well' do
42
+ result = users.try {
43
+ create(name: 'Piotr', email: 'piotr@solnic.eu')
44
+ } >-> users {
45
+ tasks.try {
46
+ create(name: users.first[:name], title: 'Finish command-api')
47
+ }
48
+ }
49
+
50
+ expect(result).to match_array([{ name: 'Piotr', title: 'Finish command-api' }])
51
+ end
52
+
53
+ it 'returns validation object with errors on failed validation' do
54
+ result = users.try { create(name: 'Piotr') }
55
+
56
+ expect(result.error).to be_instance_of(ValidationError)
57
+ expect(result.error.message).to eql(":name and :email are required")
58
+ expect(rom.relations.users.count).to be(2)
59
+ end
60
+
61
+ describe '"result" option' do
62
+
63
+ it 'returns a single tuple when set to :one' do
64
+ setup.commands(:users) do
65
+
66
+ define(:create_one, type: :create) do
67
+ result :one
68
+ end
69
+
70
+ end
71
+
72
+ tuple = { name: 'Piotr', email: 'piotr@solnic.eu' }
73
+
74
+ result = users.try {
75
+ create_one(tuple)
76
+ }
77
+
78
+ expect(result.value).to eql(tuple)
79
+ end
80
+
81
+ it 'allows only valid result types' do
82
+ expect {
83
+
84
+ setup.commands(:users) do
85
+ define(:create_one, type: :create) do
86
+ result :invalid_type
87
+ end
88
+ end
89
+ setup.finalize
90
+
91
+ }.to raise_error(ROM::InvalidOptionError)
92
+ end
93
+
94
+ end
95
+
96
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Commands / Delete' do
4
+ include_context 'users and tasks'
5
+
6
+ subject(:users) { rom.commands.users }
7
+
8
+ before do
9
+ setup.relation(:users) do
10
+ def by_name(name)
11
+ restrict(name: name)
12
+ end
13
+ end
14
+
15
+ setup.commands(:users) do
16
+ define(:delete)
17
+ end
18
+ end
19
+
20
+ it 'deletes all tuples when there is no restriction' do
21
+ result = users.try { delete }
22
+
23
+ expect(result).to match_array([
24
+ { name: 'Jane', email: 'jane@doe.org' },
25
+ { name: 'Joe', email: 'joe@doe.org' }
26
+ ])
27
+ end
28
+
29
+ it 'deletes tuples matching restriction' do
30
+ result = users.try { delete(:by_name, 'Joe').call }
31
+
32
+ expect(result).to match_array([{ name: 'Joe', email: 'joe@doe.org' }])
33
+ end
34
+
35
+ it 'returns untouched relation if there are no tuples to delete' do
36
+ result = users.try { delete(:by_name, 'Not here').call }
37
+
38
+ expect(result).to match_array([])
39
+ end
40
+
41
+ it 'returns deleted tuple when result is set to :one' do
42
+ setup.commands(:users) do
43
+ define(:delete_one, type: :delete) do
44
+ result :one
45
+ end
46
+ end
47
+
48
+ result = users.try { delete_one(:by_name, 'Jane').call }
49
+
50
+ expect(result.value).to eql(name: 'Jane', email: 'jane@doe.org')
51
+ end
52
+
53
+ it 'raises error when result is set to :one and relation contains more tuples' do
54
+ setup.commands(:users) do
55
+ define(:delete) do
56
+ result :one
57
+ end
58
+ end
59
+
60
+ result = users.try { delete }
61
+
62
+ expect(result.error).to be_instance_of(ROM::TupleCountMismatchError)
63
+
64
+ expect(rom.relations.users.to_a).to match_array([
65
+ { name: 'Jane', email: 'jane@doe.org' },
66
+ { name: 'Joe', email: 'joe@doe.org' }
67
+ ])
68
+ end
69
+
70
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Commands / Error handling' do
4
+ include_context 'users and tasks'
5
+
6
+ before do
7
+ setup.relation(:users)
8
+ setup.commands(:users) { define(:create) }
9
+ end
10
+
11
+ subject(:users) { rom.commands.users }
12
+
13
+ it 'rescues from ROM::CommandError' do
14
+ result = false
15
+ expect(users.try { raise ROM::CommandError } >-> test { result = true }).
16
+ to be_instance_of(ROM::Result::Failure)
17
+ expect(result).to be(false)
18
+ end
19
+
20
+ it 'raises other errors' do
21
+ expect { users.try { raise ArgumentError, 'test' } }.to raise_error(ArgumentError, 'test')
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Commands / Try api' do
4
+ include_context 'users and tasks'
5
+
6
+ before do
7
+ setup.relation(:users)
8
+
9
+ setup.commands(:users) do
10
+ define(:create)
11
+ end
12
+ end
13
+
14
+ let(:user_commands) { rom.command(:users) }
15
+
16
+ it 'exposes command functions inside the block' do
17
+ input = { name: 'Piotr', email: 'piotr@test.com' }
18
+
19
+ result = user_commands.try { create(input) }
20
+
21
+ expect(result.value).to eql([input])
22
+ end
23
+
24
+ it 'raises on method missing' do
25
+ expect { users.try { not_here } }.to raise_error(NameError)
26
+ end
27
+ end
@@ -0,0 +1,106 @@
1
+ require 'spec_helper'
2
+
3
+ require 'ostruct'
4
+
5
+ describe 'Commands / Update' do
6
+ include_context 'users and tasks'
7
+
8
+ subject(:users) { rom.commands.users }
9
+
10
+ before do
11
+ UserValidator = Class.new do
12
+ ValidationError = Class.new(ROM::CommandError)
13
+
14
+ def self.call(params)
15
+ raise ValidationError, ":email is required" unless params[:email]
16
+ end
17
+ end
18
+
19
+ setup.relation(:users) do
20
+ def all(criteria)
21
+ restrict(criteria)
22
+ end
23
+
24
+ def by_name(name)
25
+ restrict(name: name)
26
+ end
27
+ end
28
+
29
+ setup.commands(:users) do
30
+ define(:update) do
31
+ validator UserValidator
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ it 'update tuples on successful validation' do
38
+ result = users.try {
39
+ update(:all, name: 'Jane').set(email: 'jane.doe@test.com')
40
+ }
41
+
42
+ expect(result).to match_array([{ name: 'Jane', email: 'jane.doe@test.com' }])
43
+ end
44
+
45
+ it 'returns validation object with errors on failed validation' do
46
+ result = users.try { update(:all, name: 'Jane').set(email: nil) }
47
+
48
+ expect(result.error).to be_instance_of(ValidationError)
49
+ expect(result.error.message).to eql(':email is required')
50
+
51
+ expect(rom.relations.users.restrict(name: 'Jane')).to match_array([
52
+ { name: 'Jane', email: 'jane@doe.org' }
53
+ ])
54
+ end
55
+
56
+ describe '"result" option' do
57
+
58
+ it 'returns a single tuple when set to :one' do
59
+ setup.commands(:users) do
60
+ define(:update_one, type: :update) do
61
+ result :one
62
+ end
63
+ end
64
+
65
+ result = users.try {
66
+ update_one(:by_name, 'Jane').set(email: 'jane.doe@test.com')
67
+ }
68
+
69
+ expect(result.value).to eql(name: 'Jane', email: 'jane.doe@test.com')
70
+ end
71
+
72
+ it 'raises error when there is more than one tuple and result is set to :one' do
73
+ setup.commands(:users) do
74
+ define(:update_one, type: :update) do
75
+ result :one
76
+ end
77
+ end
78
+
79
+ result = users.try {
80
+ update_one.set(email: 'jane.doe@test.com')
81
+ }
82
+
83
+ expect(result.error).to be_instance_of(ROM::TupleCountMismatchError)
84
+
85
+ expect(rom.relations.users).to match_array([
86
+ { name: 'Jane', email: 'jane@doe.org' },
87
+ { name: 'Joe', email: 'joe@doe.org' }
88
+ ])
89
+ end
90
+
91
+ it 'allows only valid result types' do
92
+ expect {
93
+
94
+ setup.commands(:users) do
95
+ define(:create_one, type: :create) do
96
+ result :invalid_type
97
+ end
98
+ end
99
+ setup.finalize
100
+
101
+ }.to raise_error(ROM::InvalidOptionError)
102
+ end
103
+
104
+ end
105
+
106
+ end
@@ -30,4 +30,39 @@ describe 'Setting up ROM' do
30
30
  expect(rom.mappers).to eql(ROM::ReaderRegistry.new)
31
31
  end
32
32
  end
33
+
34
+ describe 'quick setup' do
35
+ it 'exposes boot DSL inside the setup block' do
36
+ User = Class.new { include Virtus.value_object; values { attribute :name, String } }
37
+
38
+ rom = ROM.setup(memory: 'memory://test') do
39
+ schema do
40
+ base_relation(:users) do
41
+ repository :memory
42
+ attribute :name
43
+ end
44
+ end
45
+
46
+ relation(:users) do
47
+ def by_name(name)
48
+ restrict(name: name)
49
+ end
50
+ end
51
+
52
+ commands(:users) do
53
+ define(:create)
54
+ end
55
+
56
+ mappers do
57
+ define(:users) do
58
+ model User
59
+ end
60
+ end
61
+ end
62
+
63
+ rom.command(:users).create.call(name: 'Jane')
64
+
65
+ expect(rom.read(:users).by_name('Jane').to_a).to eql([User.new(name: 'Jane')])
66
+ end
67
+ end
33
68
  end