rom-repository 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,11 @@
1
+ module MapperRegistry
2
+ def mapper_for(relation)
3
+ ROM::Repository::MapperBuilder.registry.fetch(relation.to_ast.hash) {
4
+ mapper_builder[relation.to_ast]
5
+ }
6
+ end
7
+
8
+ def mapper_builder
9
+ @mapper_builder ||= ROM::Repository::MapperBuilder.new
10
+ end
11
+ end
@@ -0,0 +1,74 @@
1
+ RSpec.describe 'header builder', '#call' do
2
+ subject(:builder) { ROM::Repository::HeaderBuilder.new }
3
+
4
+ let(:user_struct) { builder.struct_builder[:users, [:id, :name]] }
5
+ let(:task_struct) { builder.struct_builder[:tasks, [:user_id, :title]] }
6
+ let(:tag_struct) { builder.struct_builder[:tags, [:user_id, :tag]] }
7
+
8
+ describe 'with a relation' do
9
+ let(:ast) do
10
+ [
11
+ :relation, :users, [
12
+ :header, [[:attribute, :id], [:attribute, :name]]
13
+ ],
14
+ base_name: :users
15
+ ]
16
+ end
17
+
18
+ it 'produces a valid header' do
19
+ header = ROM::Header.coerce([[:id], [:name]], model: user_struct)
20
+
21
+ expect(builder[ast]).to eql(header)
22
+ end
23
+ end
24
+
25
+ describe 'with a graph' do
26
+ let(:ast) do
27
+ [
28
+ :relation, :users, [
29
+ :header, [
30
+ [:attribute, :id],
31
+ [:attribute, :name],
32
+ [
33
+ :relation, :tasks, [
34
+ :header, [
35
+ [:attribute, :user_id],
36
+ [:attribute, :title]
37
+ ]
38
+ ],
39
+ { base_name: :tasks, keys: { id: :user_id }, combine_type: :many }
40
+ ],
41
+ [
42
+ :relation, :tags, [
43
+ :header, [
44
+ [:attribute, :user_id],
45
+ [:attribute, :tag]
46
+ ]
47
+ ],
48
+ { base_name: :tags, keys: { id: :user_id }, combine_type: :many }
49
+ ]
50
+ ]
51
+ ],
52
+ base_name: :users
53
+ ]
54
+ end
55
+
56
+ it 'produces a valid header' do
57
+ attributes = [
58
+ [:id],
59
+ [:name],
60
+ [:tasks, combine: true, type: :array, keys: { id: :user_id },
61
+ header: ROM::Header.coerce([[:user_id], [:title]], model: task_struct)],
62
+ [:tags, combine: true, type: :array, keys: { id: :user_id },
63
+ header: ROM::Header.coerce([[:user_id], [:tag]], model: tag_struct)]
64
+ ]
65
+
66
+ header = ROM::Header.coerce(
67
+ attributes,
68
+ model: builder.struct_builder[:users, [:id, :name, :tasks, :tags]]
69
+ )
70
+
71
+ expect(builder[ast]).to eql(header)
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,138 @@
1
+ RSpec.describe 'loading proxy' do
2
+ include_context 'database'
3
+ include_context 'relations'
4
+ include_context 'repo'
5
+ include_context 'structs'
6
+ include_context 'seeds'
7
+
8
+ let(:users) do
9
+ ROM::Repository::LoadingProxy.new(rom.relation(:users), name: :users)
10
+ end
11
+
12
+ let(:tasks) do
13
+ ROM::Repository::LoadingProxy.new(rom.relation(:tasks), name: :tasks)
14
+ end
15
+
16
+ let(:tags) do
17
+ ROM::Repository::LoadingProxy.new(rom.relation(:tags), name: :tags)
18
+ end
19
+
20
+ describe '#each' do
21
+ it 'yields loaded structs' do
22
+ result = []
23
+
24
+ users.each { |user| result << user }
25
+
26
+ expect(result).to eql([jane, joe])
27
+ end
28
+
29
+ it 'returns an enumerator when block is not given' do
30
+ expect(users.each.to_a).to eql([jane, joe])
31
+ end
32
+ end
33
+
34
+ describe '#map_with' do
35
+ before do
36
+ setup.mappers do
37
+ register :users, name_list: -> users { users.map(&:name) }
38
+ end
39
+ end
40
+
41
+ it 'sends the relation through multiple mappers' do
42
+ expect(users.map_with(:name_list).to_a).to eql(%w(Jane Joe))
43
+ end
44
+ end
45
+
46
+ describe 'retrieving a single struct' do
47
+ describe '#first' do
48
+ it 'returns exactly one struct' do
49
+ expect(users.first).to eql(jane)
50
+ end
51
+ end
52
+
53
+ describe '#one' do
54
+ it 'returns exactly one struct' do
55
+ expect(users.find(id: 1).one).to eql(jane)
56
+
57
+ expect(users.find(id: 3).one).to be(nil)
58
+
59
+ expect { users.find(id: [1,2]).one }.to raise_error(ROM::TupleCountMismatchError)
60
+ end
61
+ end
62
+
63
+ describe '#one!' do
64
+ it 'returns exactly one struct' do
65
+ expect(users.find(id: 1).one!).to eql(jane)
66
+
67
+ expect { users.find(id: [1, 2]).one! }.to raise_error(ROM::TupleCountMismatchError)
68
+ expect { users.find(id: [3]).one! }.to raise_error(ROM::TupleCountMismatchError)
69
+ end
70
+ end
71
+ end
72
+
73
+ describe '#to_ast' do
74
+ it 'returns valid ast for a single relation' do
75
+ expect(users.to_ast).to eql(
76
+ [
77
+ :relation, :users, [
78
+ :header, [[:attribute, :id], [:attribute, :name]]
79
+ ],
80
+ base_name: :users
81
+ ]
82
+ )
83
+ end
84
+
85
+ it 'returns valid ast for a combined relation' do
86
+ relation = users.combine(many: { user_tasks: [tasks, id: :user_id] })
87
+
88
+ expect(relation.to_ast).to eql(
89
+ [
90
+ :relation, :users, [
91
+ :header, [
92
+ [:attribute, :id],
93
+ [:attribute, :name],
94
+ [
95
+ :relation, :user_tasks, [
96
+ :header, [
97
+ [:attribute, :id],
98
+ [:attribute, :user_id],
99
+ [:attribute, :title]
100
+ ]
101
+ ],
102
+ { base_name: :tasks, keys: { id: :user_id }, combine_type: :many }
103
+ ]
104
+ ]
105
+ ],
106
+ base_name: :users
107
+ ]
108
+ )
109
+ end
110
+
111
+ it 'returns valid ast for a wrapped relation' do
112
+ relation = tags.wrap_parent(task: tasks)
113
+
114
+ expect(relation.to_ast).to eql(
115
+ [
116
+ :relation, :tags, [
117
+ :header, [
118
+ [:attribute, :id],
119
+ [:attribute, :task_id],
120
+ [:attribute, :name],
121
+ [
122
+ :relation, :task, [
123
+ :header, [
124
+ [:attribute, :id],
125
+ [:attribute, :user_id],
126
+ [:attribute, :title]
127
+ ]
128
+ ],
129
+ { base_name: :tasks, keys: { id: :task_id }, wrap: true }
130
+ ]
131
+ ]
132
+ ],
133
+ base_name: :tags
134
+ ]
135
+ )
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,48 @@
1
+ RSpec.describe 'SQL Relation extensions' do
2
+ include_context 'database'
3
+
4
+ shared_context 'valid view' do
5
+ let(:users) { rom.relation(:users) }
6
+
7
+ it 'has valid column names' do
8
+ expect(users.columns).to eql([:id, :name])
9
+
10
+ expect(users.by_id.columns).to eql([:name])
11
+ expect(users.by_id(1).columns).to eql([:name])
12
+ end
13
+
14
+ it 'defines a valid method with correct arity' do
15
+ expect(users.relation.method(:by_id).arity).to be(1)
16
+ end
17
+ end
18
+
19
+ describe '.view' do
20
+ context 'using short syntax' do
21
+ before do
22
+ setup.relation(:users) do
23
+ view(:by_id, [:name]) do |name|
24
+ where(name: name).select(:name)
25
+ end
26
+ end
27
+ end
28
+
29
+ include_context 'valid view'
30
+ end
31
+
32
+ context 'with multi-block syntax' do
33
+ before do
34
+ setup.relation(:users) do
35
+ view(:by_id) do
36
+ header [:name]
37
+
38
+ relation do |name|
39
+ where(name: name).select(:name)
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ include_context 'valid view'
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,25 @@
1
+ RSpec.describe 'struct builder', '#call' do
2
+ subject(:builder) { ROM::Repository::StructBuilder.new }
3
+
4
+ let(:input) { [:users, [:id, :name]] }
5
+
6
+ before { builder[*input] }
7
+
8
+ it 'generates a struct for a given relation name and columns' do
9
+ struct = builder.registry[input.hash]
10
+
11
+ user = struct.new(id: 1, name: 'Jane')
12
+
13
+ expect(user.id).to be(1)
14
+ expect(user.name).to eql('Jane')
15
+
16
+ expect(user[:id]).to be(1)
17
+ expect(user[:name]).to eql('Jane')
18
+
19
+ expect(Hash[user]).to eql(id: 1, name: 'Jane')
20
+ end
21
+
22
+ it 'stores struct in the registry' do
23
+ expect(builder.registry[input.hash]).to be(builder[*input])
24
+ end
25
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rom-repository
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Piotr Solnica
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: anima
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.2'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: '0.2'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.2'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0.2'
33
+ - !ruby/object:Gem::Dependency
34
+ name: rom
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.8'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 0.8.1
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '0.8'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 0.8.1
53
+ - !ruby/object:Gem::Dependency
54
+ name: rom-sql
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '0.5'
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 0.5.3
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '0.5'
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 0.5.3
73
+ - !ruby/object:Gem::Dependency
74
+ name: rake
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '10.3'
80
+ type: :development
81
+ prerelease: false
82
+ version_requirements: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - "~>"
85
+ - !ruby/object:Gem::Version
86
+ version: '10.3'
87
+ - !ruby/object:Gem::Dependency
88
+ name: rspec
89
+ requirement: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - "~>"
92
+ - !ruby/object:Gem::Version
93
+ version: '3.3'
94
+ type: :development
95
+ prerelease: false
96
+ version_requirements: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: '3.3'
101
+ description: Repository for ROM with auto-mapping and relation extensions
102
+ email: piotr.solnica@gmail.com
103
+ executables: []
104
+ extensions: []
105
+ extra_rdoc_files: []
106
+ files:
107
+ - ".gitignore"
108
+ - ".rspec"
109
+ - ".travis.yml"
110
+ - CHANGELOG.md
111
+ - Gemfile
112
+ - LICENSE.txt
113
+ - README.md
114
+ - Rakefile
115
+ - lib/rom-repository.rb
116
+ - lib/rom/repository/base.rb
117
+ - lib/rom/repository/ext/relation.rb
118
+ - lib/rom/repository/ext/relation/view_dsl.rb
119
+ - lib/rom/repository/header_builder.rb
120
+ - lib/rom/repository/loading_proxy.rb
121
+ - lib/rom/repository/loading_proxy/combine.rb
122
+ - lib/rom/repository/loading_proxy/wrap.rb
123
+ - lib/rom/repository/mapper_builder.rb
124
+ - lib/rom/repository/struct_builder.rb
125
+ - lib/rom/repository/version.rb
126
+ - lib/rom/struct.rb
127
+ - rom-repository.gemspec
128
+ - spec/integration/repository_spec.rb
129
+ - spec/shared/database.rb
130
+ - spec/shared/relations.rb
131
+ - spec/shared/repo.rb
132
+ - spec/shared/seeds.rb
133
+ - spec/shared/structs.rb
134
+ - spec/spec_helper.rb
135
+ - spec/support/mapper_registry.rb
136
+ - spec/unit/header_builder_spec.rb
137
+ - spec/unit/loading_proxy_spec.rb
138
+ - spec/unit/sql/relation_spec.rb
139
+ - spec/unit/struct_builder_spec.rb
140
+ homepage: http://rom-rb.org
141
+ licenses:
142
+ - MIT
143
+ metadata: {}
144
+ post_install_message:
145
+ rdoc_options: []
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 2.4.5
161
+ signing_key:
162
+ specification_version: 4
163
+ summary: Repository for ROM with auto-mapping and relation extensions
164
+ test_files: []