rom-repository 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +5 -5
  4. data/CHANGELOG.md +24 -0
  5. data/Gemfile +21 -5
  6. data/README.md +6 -110
  7. data/lib/rom/repository/changeset/create.rb +26 -0
  8. data/lib/rom/repository/changeset/pipe.rb +40 -0
  9. data/lib/rom/repository/changeset/update.rb +82 -0
  10. data/lib/rom/repository/changeset.rb +99 -0
  11. data/lib/rom/repository/class_interface.rb +142 -0
  12. data/lib/rom/repository/command_compiler.rb +214 -0
  13. data/lib/rom/repository/command_proxy.rb +22 -0
  14. data/lib/rom/repository/header_builder.rb +13 -16
  15. data/lib/rom/repository/mapper_builder.rb +7 -14
  16. data/lib/rom/repository/{loading_proxy → relation_proxy}/wrap.rb +7 -7
  17. data/lib/rom/repository/relation_proxy.rb +225 -0
  18. data/lib/rom/repository/root.rb +110 -0
  19. data/lib/rom/repository/struct_attributes.rb +46 -0
  20. data/lib/rom/repository/struct_builder.rb +31 -14
  21. data/lib/rom/repository/version.rb +1 -1
  22. data/lib/rom/repository.rb +192 -31
  23. data/lib/rom/struct.rb +13 -8
  24. data/rom-repository.gemspec +9 -10
  25. data/spec/integration/changeset_spec.rb +86 -0
  26. data/spec/integration/command_macros_spec.rb +175 -0
  27. data/spec/integration/command_spec.rb +224 -0
  28. data/spec/integration/multi_adapter_spec.rb +3 -3
  29. data/spec/integration/repository_spec.rb +97 -2
  30. data/spec/integration/root_repository_spec.rb +88 -0
  31. data/spec/shared/database.rb +47 -3
  32. data/spec/shared/mappers.rb +35 -0
  33. data/spec/shared/models.rb +41 -0
  34. data/spec/shared/plugins.rb +66 -0
  35. data/spec/shared/relations.rb +76 -0
  36. data/spec/shared/repo.rb +38 -17
  37. data/spec/shared/seeds.rb +19 -0
  38. data/spec/spec_helper.rb +4 -1
  39. data/spec/support/mapper_registry.rb +1 -3
  40. data/spec/unit/changeset_spec.rb +58 -0
  41. data/spec/unit/header_builder_spec.rb +34 -35
  42. data/spec/unit/relation_proxy_spec.rb +170 -0
  43. data/spec/unit/sql/relation_spec.rb +5 -5
  44. data/spec/unit/struct_builder_spec.rb +7 -4
  45. data/spec/unit/struct_spec.rb +22 -0
  46. metadata +38 -41
  47. data/lib/rom/plugins/relation/key_inference.rb +0 -31
  48. data/lib/rom/repository/loading_proxy/combine.rb +0 -158
  49. data/lib/rom/repository/loading_proxy.rb +0 -182
  50. data/spec/unit/loading_proxy_spec.rb +0 -147
@@ -0,0 +1,170 @@
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::RelationProxy.new(rom.relation(:users), name: :users)
10
+ end
11
+
12
+ let(:tasks) do
13
+ ROM::Repository::RelationProxy.new(rom.relation(:tasks), name: :tasks)
14
+ end
15
+
16
+ let(:tags) do
17
+ ROM::Repository::RelationProxy.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/#as' do
35
+ context 'with custom mappers' do
36
+ before do
37
+ configuration.mappers do
38
+ register :users, {
39
+ name_list: -> users { users.map { |u| u[:name] } },
40
+ upcase_names: -> names { names.map(&:upcase) },
41
+ identity: -> users { users }
42
+ }
43
+ end
44
+ end
45
+
46
+ it 'sends the relation through custom mappers' do
47
+ expect(users.map_with(:name_list, :upcase_names).to_a).to match_array(%w(JANE JOE))
48
+ end
49
+
50
+ it 'does not use the default(ROM::Struct) mapper' do
51
+ expect(users.map_with(:identity).to_a).to match_array(
52
+ [{ id: 1, name: 'Jane' }, {id: 2, name: 'Joe' }]
53
+ )
54
+ end
55
+ end
56
+
57
+ context 'setting custom model type' do
58
+ let(:user_type) do
59
+ Class.new(Dry::Types::Struct) do
60
+ attribute :id, Dry::Types['strict.int']
61
+ attribute :name, Dry::Types['strict.string']
62
+ end
63
+ end
64
+
65
+ let(:custom_users) { users.as(user_type) }
66
+
67
+ it 'instantiates custom model' do
68
+ expect(custom_users.where(name: 'Jane').one).to be_instance_of(user_type)
69
+ end
70
+ end
71
+ end
72
+
73
+ describe 'retrieving a single struct' do
74
+ describe '#first' do
75
+ it 'returns exactly one struct' do
76
+ expect(users.first).to eql(jane)
77
+ end
78
+ end
79
+
80
+ describe '#one' do
81
+ it 'returns exactly one struct' do
82
+ expect(users.find(id: 1).one).to eql(jane)
83
+
84
+ expect(users.find(id: 3).one).to be(nil)
85
+
86
+ expect { users.find(id: [1,2]).one }.to raise_error(ROM::TupleCountMismatchError)
87
+ end
88
+ end
89
+
90
+ describe '#one!' do
91
+ it 'returns exactly one struct' do
92
+ expect(users.find(id: 1).one!).to eql(jane)
93
+
94
+ expect { users.find(id: [1, 2]).one! }.to raise_error(ROM::TupleCountMismatchError)
95
+ expect { users.find(id: [3]).one! }.to raise_error(ROM::TupleCountMismatchError)
96
+ end
97
+ end
98
+ end
99
+
100
+ describe '#to_ast' do
101
+ it 'returns valid ast for a single relation' do
102
+ expect(users.to_ast).to eql(
103
+ [:relation, [
104
+ :users,
105
+ { dataset: :users },
106
+ [:header, [[:attribute, :id], [:attribute, :name]]]]
107
+ ]
108
+ )
109
+ end
110
+
111
+ it 'returns valid ast for a combined relation' do
112
+ relation = users.combine(many: { user_tasks: [tasks, id: :user_id] })
113
+
114
+ expect(relation.to_ast).to eql(
115
+ [:relation, [
116
+ :users,
117
+ { dataset: :users },
118
+ [:header, [
119
+ [:attribute, :id],
120
+ [:attribute, :name],
121
+ [:relation, [
122
+ :tasks,
123
+ { dataset: :tasks, keys: { id: :user_id }, combine_type: :many, combine_name: :user_tasks },
124
+ [:header, [[:attribute, :id], [:attribute, :user_id], [:attribute, :title]]]
125
+ ]]
126
+ ]
127
+ ]]]
128
+ )
129
+ end
130
+
131
+ it 'returns valid ast for a wrapped relation' do
132
+ relation = tags.wrap_parent(task: tasks)
133
+
134
+ expect(relation.to_ast).to eql(
135
+ [:relation, [
136
+ :tags,
137
+ { dataset: :tags },
138
+ [:header, [
139
+ [:attribute, :id],
140
+ [:attribute, :task_id],
141
+ [:attribute, :name],
142
+ [:relation, [
143
+ :tasks,
144
+ { dataset: :tasks, keys: { id: :task_id }, wrap: true, combine_name: :task },
145
+ [:header, [ [:attribute, :id], [:attribute, :user_id], [:attribute, :title]]]
146
+ ]]
147
+ ]]
148
+ ]]
149
+ )
150
+ end
151
+ end
152
+
153
+ describe '#method_missing' do
154
+ it 'proxies to the underlying relation' do
155
+ expect(users.gateway).to be(:default)
156
+ end
157
+
158
+ it 'returns proxy when response was not materialized' do
159
+ expect(users.by_pk(1)).to be_instance_of(ROM::Repository::RelationProxy)
160
+ end
161
+
162
+ it 'returns curried proxy when response was curried' do
163
+ expect(users.by_pk).to be_instance_of(ROM::Repository::RelationProxy)
164
+ end
165
+
166
+ it 'raises when method is missing' do
167
+ expect { users.not_here }.to raise_error(NoMethodError, /not_here/)
168
+ end
169
+ end
170
+ end
@@ -7,8 +7,8 @@ RSpec.describe 'SQL Relation extensions' do
7
7
  it 'has valid column names' do
8
8
  expect(users.attributes).to eql([:id, :name])
9
9
 
10
- expect(users.by_id.attributes).to eql([:name])
11
- expect(users.by_id(1).attributes).to eql([:name])
10
+ expect(users.by_pk.attributes).to eql([:name])
11
+ expect(users.by_pk(1).attributes).to eql([:name])
12
12
  end
13
13
  end
14
14
 
@@ -16,7 +16,7 @@ RSpec.describe 'SQL Relation extensions' do
16
16
  context 'using short syntax' do
17
17
  before do
18
18
  configuration.relation(:users) do
19
- view(:by_id, [:name]) do |name|
19
+ view(:by_pk, [:name]) do |name|
20
20
  where(name: name).select(:name)
21
21
  end
22
22
  end
@@ -28,7 +28,7 @@ RSpec.describe 'SQL Relation extensions' do
28
28
  context 'with multi-block syntax' do
29
29
  before do
30
30
  configuration.relation(:users) do
31
- view(:by_id) do
31
+ view(:by_pk) do
32
32
  header [:name]
33
33
 
34
34
  relation do |name|
@@ -45,7 +45,7 @@ RSpec.describe 'SQL Relation extensions' do
45
45
  it 'raises error' do
46
46
  expect {
47
47
  configuration.relation(:users) do
48
- view(:by_id) { |args| }
48
+ view(:by_pk) { |args| }
49
49
  end
50
50
  }.to raise_error(ArgumentError)
51
51
  end
@@ -1,12 +1,12 @@
1
1
  RSpec.describe 'struct builder', '#call' do
2
2
  subject(:builder) { ROM::Repository::StructBuilder.new }
3
3
 
4
- let(:input) { [:users, [:id, :name]] }
4
+ let(:input) { [:users, [:header, [[:attribute, :id], [:attribute, :name]]]] }
5
5
 
6
6
  before { builder[*input] }
7
7
 
8
8
  it 'generates a struct for a given relation name and columns' do
9
- struct = builder.registry[input.hash]
9
+ struct = builder.class.cache[input.hash]
10
10
 
11
11
  user = struct.new(id: 1, name: 'Jane')
12
12
 
@@ -17,9 +17,12 @@ RSpec.describe 'struct builder', '#call' do
17
17
  expect(user[:name]).to eql('Jane')
18
18
 
19
19
  expect(Hash[user]).to eql(id: 1, name: 'Jane')
20
+
21
+ expect(user.inspect).to eql('#<ROM::Struct[User] id=1 name="Jane">')
22
+ expect(user.to_s).to match(/\A#<ROM::Struct\[User\]:0x[0-9a-f]+>\z/)
20
23
  end
21
24
 
22
- it 'stores struct in the registry' do
23
- expect(builder.registry[input.hash]).to be(builder[*input])
25
+ it 'stores struct in the cache' do
26
+ expect(builder.class.cache[input.hash]).to be(builder[*input])
24
27
  end
25
28
  end
@@ -0,0 +1,22 @@
1
+ RSpec.describe ROM::Struct do
2
+ subject(:struct) do
3
+ Class.new(ROM::Struct) do
4
+ attr_reader :id, :name
5
+
6
+ def initialize(id, name)
7
+ @id, @name = id, name
8
+ end
9
+
10
+ def id
11
+ @id.to_i
12
+ end
13
+ end.new("1", "Jane")
14
+ end
15
+
16
+ describe '#[]' do
17
+ it 'reads an attribute value' do
18
+ expect(struct.id).to be(1)
19
+ expect(struct.name).to eql("Jane")
20
+ end
21
+ end
22
+ end
metadata CHANGED
@@ -1,107 +1,88 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rom-repository
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-06 00:00:00.000000000 Z
11
+ date: 2016-07-27 00:00:00.000000000 Z
12
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
13
  - !ruby/object:Gem::Dependency
34
14
  name: rom
35
15
  requirement: !ruby/object:Gem::Requirement
36
16
  requirements:
37
17
  - - "~>"
38
18
  - !ruby/object:Gem::Version
39
- version: 1.0.0
19
+ version: '2.0'
40
20
  type: :runtime
41
21
  prerelease: false
42
22
  version_requirements: !ruby/object:Gem::Requirement
43
23
  requirements:
44
24
  - - "~>"
45
25
  - !ruby/object:Gem::Version
46
- version: 1.0.0
26
+ version: '2.0'
47
27
  - !ruby/object:Gem::Dependency
48
28
  name: rom-support
49
29
  requirement: !ruby/object:Gem::Requirement
50
30
  requirements:
51
31
  - - "~>"
52
32
  - !ruby/object:Gem::Version
53
- version: 1.0.0
33
+ version: '2.0'
54
34
  type: :runtime
55
35
  prerelease: false
56
36
  version_requirements: !ruby/object:Gem::Requirement
57
37
  requirements:
58
38
  - - "~>"
59
39
  - !ruby/object:Gem::Version
60
- version: 1.0.0
40
+ version: '2.0'
61
41
  - !ruby/object:Gem::Dependency
62
42
  name: rom-mapper
63
43
  requirement: !ruby/object:Gem::Requirement
64
44
  requirements:
65
45
  - - "~>"
66
46
  - !ruby/object:Gem::Version
67
- version: 0.3.0
47
+ version: '0.4'
68
48
  type: :runtime
69
49
  prerelease: false
70
50
  version_requirements: !ruby/object:Gem::Requirement
71
51
  requirements:
72
52
  - - "~>"
73
53
  - !ruby/object:Gem::Version
74
- version: 0.3.0
54
+ version: '0.4'
75
55
  - !ruby/object:Gem::Dependency
76
56
  name: rake
77
57
  requirement: !ruby/object:Gem::Requirement
78
58
  requirements:
79
59
  - - "~>"
80
60
  - !ruby/object:Gem::Version
81
- version: '10.3'
61
+ version: '11.2'
82
62
  type: :development
83
63
  prerelease: false
84
64
  version_requirements: !ruby/object:Gem::Requirement
85
65
  requirements:
86
66
  - - "~>"
87
67
  - !ruby/object:Gem::Version
88
- version: '10.3'
68
+ version: '11.2'
89
69
  - !ruby/object:Gem::Dependency
90
70
  name: rspec
91
71
  requirement: !ruby/object:Gem::Requirement
92
72
  requirements:
93
73
  - - "~>"
94
74
  - !ruby/object:Gem::Version
95
- version: '3.3'
75
+ version: '3.5'
96
76
  type: :development
97
77
  prerelease: false
98
78
  version_requirements: !ruby/object:Gem::Requirement
99
79
  requirements:
100
80
  - - "~>"
101
81
  - !ruby/object:Gem::Version
102
- version: '3.3'
103
- description: Repository for ROM with auto-mapping and relation extensions
104
- email: piotr.solnica@gmail.com
82
+ version: '3.5'
83
+ description: rom-repository adds support for auto-mapping and commands on top of rom-rb
84
+ relations
85
+ email: piotr.solnica+oss@gmail.com
105
86
  executables: []
106
87
  extensions: []
107
88
  extra_rdoc_files: []
@@ -115,32 +96,48 @@ files:
115
96
  - README.md
116
97
  - Rakefile
117
98
  - lib/rom-repository.rb
118
- - lib/rom/plugins/relation/key_inference.rb
119
99
  - lib/rom/repository.rb
100
+ - lib/rom/repository/changeset.rb
101
+ - lib/rom/repository/changeset/create.rb
102
+ - lib/rom/repository/changeset/pipe.rb
103
+ - lib/rom/repository/changeset/update.rb
104
+ - lib/rom/repository/class_interface.rb
105
+ - lib/rom/repository/command_compiler.rb
106
+ - lib/rom/repository/command_proxy.rb
120
107
  - lib/rom/repository/header_builder.rb
121
- - lib/rom/repository/loading_proxy.rb
122
- - lib/rom/repository/loading_proxy/combine.rb
123
- - lib/rom/repository/loading_proxy/wrap.rb
124
108
  - lib/rom/repository/mapper_builder.rb
109
+ - lib/rom/repository/relation_proxy.rb
110
+ - lib/rom/repository/relation_proxy/wrap.rb
111
+ - lib/rom/repository/root.rb
112
+ - lib/rom/repository/struct_attributes.rb
125
113
  - lib/rom/repository/struct_builder.rb
126
114
  - lib/rom/repository/version.rb
127
115
  - lib/rom/struct.rb
128
116
  - log/.gitkeep
129
117
  - rom-repository.gemspec
118
+ - spec/integration/changeset_spec.rb
119
+ - spec/integration/command_macros_spec.rb
120
+ - spec/integration/command_spec.rb
130
121
  - spec/integration/multi_adapter_spec.rb
131
122
  - spec/integration/repository_spec.rb
123
+ - spec/integration/root_repository_spec.rb
132
124
  - spec/shared/database.rb
125
+ - spec/shared/mappers.rb
126
+ - spec/shared/models.rb
127
+ - spec/shared/plugins.rb
133
128
  - spec/shared/relations.rb
134
129
  - spec/shared/repo.rb
135
130
  - spec/shared/seeds.rb
136
131
  - spec/shared/structs.rb
137
132
  - spec/spec_helper.rb
138
133
  - spec/support/mapper_registry.rb
134
+ - spec/unit/changeset_spec.rb
139
135
  - spec/unit/header_builder_spec.rb
140
- - spec/unit/loading_proxy_spec.rb
141
136
  - spec/unit/plugins/view_spec.rb
137
+ - spec/unit/relation_proxy_spec.rb
142
138
  - spec/unit/sql/relation_spec.rb
143
139
  - spec/unit/struct_builder_spec.rb
140
+ - spec/unit/struct_spec.rb
144
141
  homepage: http://rom-rb.org
145
142
  licenses:
146
143
  - MIT
@@ -161,8 +158,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
161
158
  version: '0'
162
159
  requirements: []
163
160
  rubyforge_project:
164
- rubygems_version: 2.4.5.1
161
+ rubygems_version: 2.5.1
165
162
  signing_key:
166
163
  specification_version: 4
167
- summary: Repository for ROM with auto-mapping and relation extensions
164
+ summary: Repository abstraction for rom-rb
168
165
  test_files: []
@@ -1,31 +0,0 @@
1
- module ROM
2
- module Plugins
3
- module Relation
4
- module KeyInference
5
- # Infer foreign_key name for this relation
6
- #
7
- # TODO: this should be configurable and handled by an injected policy
8
- #
9
- # @return [Symbol]
10
- #
11
- # @api private
12
- def foreign_key
13
- :"#{Inflector.singularize(name)}_id"
14
- end
15
-
16
- # Return base name which defaults to name attribute
17
- #
18
- # @return [Symbol]
19
- #
20
- # @api private
21
- def base_name
22
- name
23
- end
24
- end
25
- end
26
- end
27
- end
28
-
29
- ROM.plugins do
30
- register :key_inference, ROM::Plugins::Relation::KeyInference, type: :relation
31
- end
@@ -1,158 +0,0 @@
1
- module ROM
2
- class Repository
3
- class LoadingProxy
4
- # Provides convenient methods for producing combined relations
5
- #
6
- # @api public
7
- module Combine
8
- # Combine with other relations
9
- #
10
- # @example
11
- # # combining many
12
- # users.combine(many: { tasks: [tasks, id: :task_id] })
13
- # users.combine(many: { tasks: [tasks.for_users, id: :task_id] })
14
- #
15
- # # combining one
16
- # users.combine(one: { task: [tasks, id: :task_id] })
17
- #
18
- # @param [Hash] options
19
- #
20
- # @return [LoadingProxy]
21
- #
22
- # @api public
23
- def combine(options)
24
- combine_opts = options.each_with_object({}) do |(type, relations), result|
25
- result[type] = relations.each_with_object({}) do |(name, (other, keys)), h|
26
- h[name] = [
27
- other.curried? ? other : other.combine_method(relation, keys), keys
28
- ]
29
- end
30
- end
31
-
32
- nodes = combine_opts.flat_map do |type, relations|
33
- relations.map { |name, (relation, keys)|
34
- relation.combined(name, keys, type)
35
- }
36
- end
37
-
38
- __new__(relation.combine(*nodes))
39
- end
40
-
41
- # Shortcut for combining with parents which infers the join keys
42
- #
43
- # @example
44
- # tasks.combine_parents(one: users)
45
- #
46
- # @param [Hash] options
47
- #
48
- # @return [LoadingProxy]
49
- #
50
- # @api public
51
- def combine_parents(options)
52
- combine(options.each_with_object({}) { |(type, parents), h|
53
- h[type] =
54
- if parents.is_a?(Hash)
55
- parents.each_with_object({}) { |(key, parent), r|
56
- r[key] = [parent, combine_keys(parent, :parent)]
57
- }
58
- else
59
- (parents.is_a?(Array) ? parents : [parents])
60
- .each_with_object({}) { |parent, r|
61
- r[parent.combine_tuple_key(type)] = [
62
- parent, combine_keys(parent, :parent)
63
- ]
64
- }
65
- end
66
- })
67
- end
68
-
69
- # Shortcut for combining with children which infers the join keys
70
- #
71
- # @example
72
- # users.combine_parents(many: tasks)
73
- #
74
- # @param [Hash] options
75
- #
76
- # @return [LoadingProxy]
77
- #
78
- # @api public
79
- def combine_children(options)
80
- combine(options.each_with_object({}) { |(type, children), h|
81
- h[type] =
82
- if children.is_a?(Hash)
83
- children.each_with_object({}) { |(key, child), r|
84
- r[key] = [child, combine_keys(relation, :children)]
85
- }
86
- else
87
- (children.is_a?(Array) ? children : [children])
88
- .each_with_object({}) { |child, r|
89
- r[child.combine_tuple_key(type)] = [
90
- child, combine_keys(relation, :children)
91
- ]
92
- }
93
- end
94
- })
95
- end
96
-
97
- # Infer join keys for a given relation and association type
98
- #
99
- # @param [LoadingProxy] relation
100
- # @param [Symbol] type The type can be either :parent or :children
101
- #
102
- # @return [Hash<Symbol=>Symbol>]
103
- #
104
- # @api private
105
- def combine_keys(relation, type)
106
- if type == :parent
107
- { relation.foreign_key => relation.primary_key }
108
- else
109
- { relation.primary_key => relation.foreign_key }
110
- end
111
- end
112
-
113
- # Infer relation for combine operation
114
- #
115
- # By default it uses `for_combine` which is implemented as SQL::Relation
116
- # extension
117
- #
118
- # @return [LoadingProxy]
119
- #
120
- # @api private
121
- def combine_method(other, keys)
122
- custom_name = :"for_#{other.base_name}"
123
-
124
- if relation.respond_to?(custom_name)
125
- __send__(custom_name)
126
- else
127
- for_combine(keys)
128
- end
129
- end
130
-
131
- # Infer key under which a combine relation will be loaded
132
- #
133
- # @return [Symbol]
134
- #
135
- # @api private
136
- def combine_tuple_key(arity)
137
- if arity == :one
138
- Inflector.singularize(base_name).to_sym
139
- else
140
- base_name
141
- end
142
- end
143
-
144
- # Return combine representation of a loading-proxy relation
145
- #
146
- # This will carry meta info used to produce a correct AST from a relation
147
- # so that correct mapper can be generated
148
- #
149
- # @return [LoadingProxy]
150
- #
151
- # @api private
152
- def combined(name, keys, type)
153
- with(name: name, meta: { keys: keys, combine_type: type })
154
- end
155
- end
156
- end
157
- end
158
- end