ree_lib 1.0.54 → 1.0.56

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c1de406ab816861e6a42c542db02cddbc0f68f6aeca80bff9dba9e8c76ef81a
4
- data.tar.gz: 05dba8342aa073f8198c42d051ca9783396b40bc8a939edd64b3ddc42d35a868
3
+ metadata.gz: 23c4603ab3ab820869ca4478b42b3d350c5484c8da7b21c99b469449f45764a1
4
+ data.tar.gz: 4293f4d083185f09f6098e11698b5f35981a748b00ff84e486389bab19445751
5
5
  SHA512:
6
- metadata.gz: cf9b082920297cca214ab5a21ce389d77833936d12c5b6583f2edcc34b3e794b1ac7565a1ae9c66745f0cd43010658f1bf9fbdee9af23cf82b7d7537529bc58e
7
- data.tar.gz: ded7b6e245997cad79fbd20cfa8ad33f4b89b402985f9a133a0d55b6daee823764d5e0888cfed8eb0761f1d4108edeb176aaf61595864820d5562d516b907295
6
+ metadata.gz: fe885988996c1f0b9aeba40c9f61e119ab4ffc02aa471afe3774b470192fc5601093c1b13673febebad76bf348baa0be61cb2e19a5abf81b1970b518d86ddc9d
7
+ data.tar.gz: acbdf84eacfa6c46c6997999af1e0eb5dc03eedc95b95d954927a3907048c9c28d924328041203d02db1bd5c9dc78310c2cc234db826c74e585a8701b7982ed9
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ree_lib (1.0.54)
4
+ ree_lib (1.0.56)
5
5
  binding_of_caller (~> 1.0.0)
6
6
  i18n (~> 1.12.0)
7
7
  loofah (~> 2.18.0)
@@ -38,6 +38,8 @@ GEM
38
38
  crass (~> 1.0.2)
39
39
  nokogiri (>= 1.5.9)
40
40
  msgpack (1.6.0)
41
+ nokogiri (1.15.3-x86_64-darwin)
42
+ racc (~> 1.4)
41
43
  nokogiri (1.15.3-x86_64-linux)
42
44
  racc (~> 1.4)
43
45
  oj (3.13.23)
@@ -26,8 +26,12 @@ module ReeDao
26
26
  load_association(assoc_type, assoc_name, **opts, &block)
27
27
  end
28
28
 
29
+ def handle_field(assoc_name, proc)
30
+ proc.call
31
+ end
32
+
29
33
  contract(
30
- Or[:belongs_to, :has_one, :has_many, :field],
34
+ Or[:belongs_to, :has_one, :has_many],
31
35
  Symbol,
32
36
  Ksplat[RestKeys => Any],
33
37
  Optblock => Nilor[Array]
@@ -56,6 +60,7 @@ module ReeDao
56
60
  assoc_name,
57
61
  list,
58
62
  scope: opts[:scope],
63
+ primary_key: opts[:primary_key],
59
64
  foreign_key: opts[:foreign_key],
60
65
  setter: opts[:setter],
61
66
  reverse: false
@@ -65,6 +70,7 @@ module ReeDao
65
70
  assoc_name,
66
71
  list,
67
72
  scope: opts[:scope],
73
+ primary_key: opts[:primary_key],
68
74
  foreign_key: opts[:foreign_key],
69
75
  setter: opts[:setter],
70
76
  reverse: true
@@ -74,6 +80,7 @@ module ReeDao
74
80
  assoc_name,
75
81
  list,
76
82
  scope: opts[:scope],
83
+ primary_key: opts[:primary_key],
77
84
  foreign_key: opts[:foreign_key],
78
85
  setter: opts[:setter]
79
86
  )
@@ -82,16 +89,16 @@ module ReeDao
82
89
  assoc_name,
83
90
  list,
84
91
  scope: opts[:scope],
92
+ primary_key: opts[:primary_key],
85
93
  foreign_key: opts[:foreign_key],
86
- setter: opts[:setter],
87
- skip_dao: true
94
+ setter: opts[:setter]
88
95
  )
89
96
  end
90
97
  end
91
98
 
92
- contract(Hash, Bool, Block => Any)
99
+ contract(Or[Hash, Array], Bool, Block => Any)
93
100
  def process_block(assoc, autoload_children, &block)
94
- assoc_list = assoc.values.flatten
101
+ assoc_list = assoc.is_a?(Array) ? assoc : assoc.values.flatten
95
102
 
96
103
  if ReeDao::Associations.sync_mode?
97
104
  ReeDao::Associations.new(
@@ -108,7 +115,7 @@ module ReeDao
108
115
  parent.local_vars,
109
116
  autoload_children,
110
117
  **global_opts
111
- ).instance_exec(assoc_list, &block).map(&:join)
118
+ ).instance_exec(assoc_list, &block)[:association_threads].map(&:join)
112
119
  end
113
120
  end
114
121
 
@@ -116,59 +123,66 @@ module ReeDao
116
123
  Symbol,
117
124
  Array,
118
125
  Kwargs[
126
+ primary_key: Nilor[Symbol],
119
127
  foreign_key: Nilor[Symbol],
120
- scope: Nilor[Sequel::Dataset],
128
+ scope: Nilor[Sequel::Dataset, Array],
121
129
  setter: Nilor[Or[Symbol, Proc]],
122
130
  reverse: Bool
123
- ] => Hash
124
- )
125
- def one_to_one(
126
- assoc_name,
127
- list,
128
- scope: nil,
129
- foreign_key: nil,
130
- setter: nil,
131
- reverse: true
131
+ ] => Or[Hash, Array]
132
132
  )
133
+ def one_to_one(assoc_name, list, scope: nil, primary_key: :id, foreign_key: nil, setter: nil, reverse: true)
133
134
  return {} if list.empty?
134
135
 
135
- assoc_dao = find_dao(assoc_name, parent, scope)
136
-
137
- if reverse
138
- if !foreign_key
139
- name = underscore(demodulize(list.first.class.name))
140
- foreign_key = "#{name}_id".to_sym
141
- end
136
+ primary_key ||= :id
142
137
 
143
- root_ids = list.map(&:id).uniq
138
+ if scope.is_a?(Array)
139
+ items = scope
144
140
  else
145
- if !foreign_key
146
- dto_class = assoc_dao
147
- .opts[:schema_mapper]
148
- .dto(:db_load)
141
+ assoc_dao = find_dao(assoc_name, parent, scope)
142
+
143
+ if reverse
144
+ if !foreign_key
145
+ name = underscore(demodulize(list.first.class.name))
146
+ foreign_key = "#{name}_id".to_sym
147
+ end
149
148
 
150
- name = underscore(demodulize(dto_class.name))
151
-
152
- root_ids = list.map(&:"#{"#{name}_id".to_sym}").uniq
153
- foreign_key = :id
149
+ root_ids = list.map(&:id).uniq
154
150
  else
155
- root_ids = list.map(&:"#{foreign_key}")
156
- foreign_key = :id
151
+ if !foreign_key
152
+ dto_class = assoc_dao
153
+ .opts[:schema_mapper]
154
+ .dto(:db_load)
155
+
156
+ name = underscore(demodulize(dto_class.name))
157
+
158
+ root_ids = list.map(&:"#{"#{name}_id".to_sym}").uniq
159
+ foreign_key = :id
160
+ else
161
+ root_ids = list.map(&:"#{foreign_key}")
162
+ foreign_key = :id
163
+ end
164
+ end
165
+
166
+ default_scope = if !scope
167
+ assoc_dao&.where(foreign_key => root_ids)
157
168
  end
169
+
170
+ items = add_scopes(default_scope, scope, global_opts[assoc_name])
158
171
  end
159
172
 
160
- default_scope = assoc_dao&.where(foreign_key => root_ids)
161
-
162
- items = add_scopes(default_scope, scope, global_opts[assoc_name])
163
-
164
- assoc = index_by(items) { _1.send(foreign_key) }
173
+ assoc = if foreign_key
174
+ index_by(items) { _1.send(foreign_key) }
175
+ else
176
+ items
177
+ end
165
178
 
166
179
  populate_association(
167
180
  list,
168
181
  assoc,
169
182
  assoc_name,
170
183
  setter: setter,
171
- reverse: reverse
184
+ reverse: reverse,
185
+ primary_key: primary_key
172
186
  )
173
187
 
174
188
  assoc
@@ -179,39 +193,45 @@ module ReeDao
179
193
  Array,
180
194
  Kwargs[
181
195
  foreign_key: Nilor[Symbol],
182
- scope: Nilor[Sequel::Dataset],
183
- setter: Nilor[Or[Symbol, Proc]],
184
- skip_dao: Bool
185
- ] => Hash
186
- )
187
- def one_to_many(
188
- assoc_name,
189
- list,
190
- foreign_key: nil,
191
- scope: nil,
192
- setter: nil,
193
- skip_dao: false
196
+ primary_key: Nilor[Symbol],
197
+ scope: Nilor[Sequel::Dataset, Array],
198
+ setter: Nilor[Or[Symbol, Proc]]
199
+ ] => Or[Hash, Array]
194
200
  )
201
+ def one_to_many(assoc_name, list, primary_key: nil, foreign_key: nil, scope: nil, setter: nil)
195
202
  return {} if list.empty?
196
203
 
197
- assoc_dao = nil
198
- assoc_dao = find_dao(assoc_name, parent, scope) if !skip_dao
204
+ primary_key ||= :id
199
205
 
200
- foreign_key ||= "#{underscore(demodulize(list.first.class.name))}_id".to_sym
201
-
202
- root_ids = list.map(&:id)
203
-
204
- default_scope = assoc_dao&.where(foreign_key => root_ids)
205
-
206
- items = add_scopes(default_scope, scope, global_opts[assoc_name])
206
+ if scope.is_a?(Array)
207
+ items = scope
208
+ else
209
+ assoc_dao = nil
210
+ assoc_dao = find_dao(assoc_name, parent, scope)
211
+
212
+ foreign_key ||= "#{underscore(demodulize(list.first.class.name))}_id".to_sym
213
+
214
+ root_ids = list.map(&:"#{primary_key}")
215
+
216
+ default_scope = if !scope
217
+ assoc_dao&.where(foreign_key => root_ids)
218
+ end
219
+
220
+ items = add_scopes(default_scope, scope, global_opts[assoc_name])
221
+ end
207
222
 
208
- assoc = group_by(items) { _1.send(foreign_key) }
223
+ assoc = if foreign_key
224
+ group_by(items) { _1.send(foreign_key) }
225
+ else
226
+ items
227
+ end
209
228
 
210
229
  populate_association(
211
230
  list,
212
231
  assoc,
213
232
  assoc_name,
214
- setter: setter
233
+ setter: setter,
234
+ primary_key: primary_key
215
235
  )
216
236
 
217
237
  assoc
@@ -219,20 +239,15 @@ module ReeDao
219
239
 
220
240
  contract(
221
241
  Array,
222
- Hash,
242
+ Or[Hash, Array],
223
243
  Symbol,
224
244
  Kwargs[
245
+ primary_key: Nilor[Symbol],
225
246
  reverse: Nilor[Bool],
226
247
  setter: Nilor[Or[Symbol, Proc]]
227
248
  ] => Any
228
249
  )
229
- def populate_association(
230
- list,
231
- association_index,
232
- assoc_name,
233
- reverse: nil,
234
- setter: nil
235
- )
250
+ def populate_association(list, association_index, assoc_name, primary_key: nil, reverse: nil, setter: nil)
236
251
  assoc_setter = if setter
237
252
  setter
238
253
  else
@@ -244,37 +259,25 @@ module ReeDao
244
259
  self.instance_exec(item, association_index, &assoc_setter)
245
260
  else
246
261
  key = if reverse.nil?
247
- :id
262
+ primary_key
248
263
  else
249
- reverse ? :id : "#{assoc_name}_id"
264
+ reverse ? primary_key : "#{assoc_name}_id"
250
265
  end
251
266
  value = association_index[item.send(key)]
252
267
  next if value.nil?
253
268
 
254
- item.send(assoc_setter, value)
269
+ begin
270
+ item.send(assoc_setter, value)
271
+ rescue NoMethodError
272
+ item.send("#{assoc_name}=", value)
273
+ end
255
274
  end
256
275
  end
257
276
  end
258
277
 
259
278
  contract(Nilor[Sequel::Dataset], Nilor[Sequel::Dataset], Nilor[Proc] => Array)
260
279
  def add_scopes(default_scope, scope, named_scope)
261
- if default_scope && !scope
262
- res = default_scope
263
- end
264
-
265
- if default_scope && scope
266
- if scope == []
267
- res = default_scope
268
- else
269
- res = merge_scopes(default_scope, scope)
270
- end
271
- end
272
-
273
- if !default_scope && scope
274
- return [] if scope.empty?
275
-
276
- res = scope
277
- end
280
+ res = scope || default_scope
278
281
 
279
282
  if named_scope
280
283
  res = named_scope.call(res)
@@ -283,18 +286,6 @@ module ReeDao
283
286
  res.all
284
287
  end
285
288
 
286
- def merge_scopes(s1, s2)
287
- if s2.opts[:where]
288
- s1 = s1.where(s2.opts[:where])
289
- end
290
-
291
- if s2.opts[:order]
292
- s1 = s1.order(*s2.opts[:order])
293
- end
294
-
295
- s1
296
- end
297
-
298
289
  def find_dao(assoc_name, parent, scope)
299
290
  dao_from_name = parent.instance_variable_get("@#{assoc_name}") || parent.instance_variable_get("@#{assoc_name}s")
300
291
  return dao_from_name if dao_from_name
@@ -307,5 +298,11 @@ module ReeDao
307
298
 
308
299
  raise ArgumentError, "can't find DAO for :#{assoc_name}, provide correct scope or association name"
309
300
  end
301
+
302
+ def method_missing(method, *args, &block)
303
+ return super if !parent.agg_caller.private_methods(false).include?(method)
304
+
305
+ parent.agg_caller.send(method, *args, &block)
306
+ end
310
307
  end
311
308
  end
@@ -8,14 +8,19 @@ module ReeDao
8
8
  @agg_caller = agg_caller
9
9
  @list = list
10
10
  @local_vars = local_vars
11
- @threads = [] if !self.class.sync_mode?
12
- @global_opts = opts
11
+ @global_opts = opts || {}
13
12
  @only = opts[:only] if opts[:only]
14
13
  @except = opts[:except] if opts[:except]
15
14
  @autoload_children = autoload_children
16
15
 
17
16
  raise ArgumentError.new("you can't use both :only and :except arguments at the same time") if @only && @except
18
17
 
18
+
19
+ if !self.class.sync_mode?
20
+ @assoc_threads = []
21
+ @field_threads = []
22
+ end
23
+
19
24
  local_vars.each do |k, v|
20
25
  instance_variable_set(k, v)
21
26
 
@@ -31,58 +36,34 @@ module ReeDao
31
36
 
32
37
  contract(
33
38
  Symbol,
34
- Ksplat[
35
- scope?: Sequel::Dataset,
36
- setter?: Or[Symbol, Proc],
37
- foreign_key?: Symbol,
38
- autoload_children?: Bool
39
- ],
39
+ Nilor[Proc, Sequel::Dataset],
40
40
  Optblock => Any
41
41
  )
42
- def belongs_to(assoc_name, **opts, &block)
43
- association(__method__, assoc_name, **opts, &block)
42
+ def belongs_to(assoc_name, opts = nil, &block)
43
+ association(__method__, assoc_name, opts, &block)
44
44
  end
45
45
 
46
46
  contract(
47
47
  Symbol,
48
- Ksplat[
49
- scope?: Sequel::Dataset,
50
- setter?: Or[Symbol, Proc],
51
- foreign_key?: Symbol,
52
- autoload_children?: Bool
53
- ],
48
+ Nilor[Proc, Sequel::Dataset],
54
49
  Optblock => Any
55
50
  )
56
- def has_one(assoc_name, **opts, &block)
57
- association(__method__, assoc_name, **opts, &block)
51
+ def has_one(assoc_name, opts = nil, &block)
52
+ association(__method__, assoc_name, opts, &block)
58
53
  end
59
54
 
60
55
  contract(
61
56
  Symbol,
62
- Ksplat[
63
- scope?: Sequel::Dataset,
64
- setter?: Or[Symbol, Proc],
65
- foreign_key?: Symbol,
66
- autoload_children?: Bool
67
- ],
57
+ Nilor[Proc, Sequel::Dataset],
68
58
  Optblock => Any
69
59
  )
70
- def has_many(assoc_name, **opts, &block)
71
- association(__method__, assoc_name, **opts, &block)
60
+ def has_many(assoc_name, opts = nil, &block)
61
+ association(__method__, assoc_name, opts, &block)
72
62
  end
73
63
 
74
- contract(
75
- Symbol,
76
- Ksplat[
77
- scope?: Sequel::Dataset,
78
- setter?: Or[Symbol, Proc],
79
- foreign_key?: Symbol,
80
- autoload_children?: Bool
81
- ],
82
- Optblock => Any
83
- )
84
- def field(assoc_name, **opts, &block)
85
- association(__method__, assoc_name, **opts, &block)
64
+ contract(Symbol, Proc => Any)
65
+ def field(assoc_name, proc)
66
+ association(__method__, assoc_name, proc)
86
67
  end
87
68
 
88
69
  private
@@ -95,26 +76,40 @@ module ReeDao
95
76
  :field
96
77
  ],
97
78
  Symbol,
98
- Ksplat[
99
- scope?: Sequel::Dataset,
100
- setter?: Or[Symbol, Proc],
101
- foreign_key?: Symbol,
102
- autoload_children?: Bool
103
- ],
79
+ Nilor[Proc, Sequel::Dataset],
104
80
  Optblock => Any
105
81
  )
106
- def association(assoc_type, assoc_name, **assoc_opts, &block)
82
+ def association(assoc_type, assoc_name, opts, &block)
107
83
  if self.class.sync_mode?
108
84
  return if association_is_not_included?(assoc_name) || list.empty?
109
-
85
+
110
86
  association = Association.new(self, list, **global_opts)
111
- association.load(assoc_type, assoc_name, **assoc_opts, &block)
87
+ if assoc_type == :field
88
+ association.handle_field(assoc_name, opts)
89
+ else
90
+ association.load(assoc_type, assoc_name, **get_assoc_opts(opts), &block)
91
+ end
112
92
  else
113
- return @threads if association_is_not_included?(assoc_name) || list.empty?
93
+ if association_is_not_included?(assoc_name) || list.empty?
94
+ return { association_threads: @assoc_threads, field_threads: @field_threads }
95
+ end
96
+
97
+ association = Association.new(self, list, **global_opts)
114
98
 
115
- @threads << Thread.new do
116
- association = Association.new(self, list, **global_opts)
117
- association.load(assoc_type, assoc_name, **assoc_opts, &block)
99
+ if assoc_type == :field
100
+ {
101
+ association_threads: @assoc_threads,
102
+ field_threads: @field_threads << Thread.new do
103
+ association.handle_field(assoc_name, opts)
104
+ end
105
+ }
106
+ else
107
+ {
108
+ association_threads: @assoc_threads << Thread.new do
109
+ association.load(assoc_type, assoc_name, **get_assoc_opts(opts), &block)
110
+ end,
111
+ field_threads: @field_threads
112
+ }
118
113
  end
119
114
  end
120
115
  end
@@ -144,5 +139,13 @@ module ReeDao
144
139
 
145
140
  agg_caller.send(method, *args, &block)
146
141
  end
142
+
143
+ def get_assoc_opts(opts)
144
+ if opts.is_a?(Proc)
145
+ opts.call
146
+ else
147
+ {}
148
+ end
149
+ end
147
150
  end
148
151
  end
@@ -151,6 +151,26 @@ module ReeDao
151
151
  for_update
152
152
  end
153
153
 
154
+ def with_mapper(mapper)
155
+ clone(
156
+ schema_mapper: mapper || opts[:schema_mapper],
157
+ ).with_row_proc(
158
+ Proc.new { |hash|
159
+ m = mapper || opts[:schema_mapper]
160
+
161
+ if m
162
+ entity = m.db_load(hash)
163
+
164
+ self.set_entity_cache(entity, hash)
165
+
166
+ entity
167
+ else
168
+ hash
169
+ end
170
+ }
171
+ )
172
+ end
173
+
154
174
  private
155
175
 
156
176
  def __ree_dao_cache
@@ -179,26 +199,6 @@ module ReeDao
179
199
  end
180
200
  end
181
201
 
182
- def with_mapper(mapper)
183
- clone(
184
- schema_mapper: mapper || opts[:schema_mapper],
185
- ).with_row_proc(
186
- Proc.new { |hash|
187
- m = mapper || opts[:schema_mapper]
188
-
189
- if m
190
- entity = m.db_load(hash)
191
-
192
- self.set_entity_cache(entity, hash)
193
-
194
- entity
195
- else
196
- hash
197
- end
198
- }
199
- )
200
- end
201
-
202
202
  def extract_primary_key(entity)
203
203
  if primary_key.is_a?(Array)
204
204
  primary_key.map do |key|
@@ -10,16 +10,17 @@ class ReeDao::LoadAgg
10
10
  end
11
11
 
12
12
  contract(
13
- Or[Sequel::Dataset, ArrayOf[Integer], ArrayOf[EntityContract], Integer],
14
13
  Nilor[DaoDatasetContract],
14
+ Or[Sequel::Dataset, ArrayOf[Integer], ArrayOf[EntityContract], Integer],
15
15
  Ksplat[
16
16
  only?: ArrayOf[Symbol],
17
17
  except?: ArrayOf[Symbol],
18
+ to_dto?: Proc,
18
19
  RestKeys => Any
19
20
  ],
20
21
  Optblock => ArrayOf[Any]
21
22
  )
22
- def call(ids_or_scope, dao = nil, **opts, &block)
23
+ def call(dao = nil, ids_or_scope, **opts, &block)
23
24
  scope = if ids_or_scope.is_a?(Array) && ids_or_scope.any? { _1.is_a?(Integer) }
24
25
  raise ArgumentError.new("Dao should be provided") if dao.nil?
25
26
  return [] if ids_or_scope.empty?
@@ -35,6 +36,10 @@ class ReeDao::LoadAgg
35
36
 
36
37
  list = scope.is_a?(Sequel::Dataset) ? scope.all : scope
37
38
 
39
+ if opts[:to_dto]
40
+ list = opts[:to_dto].call(list)
41
+ end
42
+
38
43
  load_associations(list, **opts, &block) if block_given?
39
44
 
40
45
  if ids_or_scope.is_a?(Array)
@@ -61,7 +66,8 @@ class ReeDao::LoadAgg
61
66
  if ReeDao.load_sync_associations_enabled?
62
67
  associations
63
68
  else
64
- associations.map(&:join)
69
+ associations[:association_threads].map(&:join)
70
+ associations[:field_threads].map(&:join)
65
71
  end
66
72
  end
67
73
  end
@@ -14,20 +14,20 @@
14
14
  ],
15
15
  "return": "ArrayOf[Any]",
16
16
  "args": [
17
- {
18
- "arg": "ids_or_scope",
19
- "arg_type": "req",
20
- "type": "Or[Sequel::Dataset, ArrayOf[Integer], ArrayOf[PackageName::Entity], Integer]"
21
- },
22
17
  {
23
18
  "arg": "dao",
24
19
  "arg_type": "opt",
25
20
  "type": "Nilor[PackageName::DaoName::Dao: \"SELECT * FROM `table`\"]"
26
21
  },
22
+ {
23
+ "arg": "ids_or_scope",
24
+ "arg_type": "req",
25
+ "type": "Or[Sequel::Dataset, ArrayOf[Integer], ArrayOf[PackageName::Entity], Integer]"
26
+ },
27
27
  {
28
28
  "arg": "opts",
29
29
  "arg_type": "keyrest",
30
- "type": "Ksplat[:only? => ArrayOf[Symbol], :except? => ArrayOf[Symbol], \"RestKeys\" => Any]"
30
+ "type": "Ksplat[:only? => ArrayOf[Symbol], :except? => ArrayOf[Symbol], :to_dto? => Proc, \"RestKeys\" => Any]"
31
31
  },
32
32
  {
33
33
  "arg": "block",
@@ -99,19 +99,67 @@ RSpec.describe :load_agg do
99
99
  end
100
100
 
101
101
  def call(ids_or_scope, **opts)
102
- load_agg(ids_or_scope, users, **opts) do
102
+ load_agg(users, ids_or_scope, **opts) do |users_list|
103
103
  belongs_to :organization
104
- has_many :books do
104
+ has_many :books do |books_list|
105
105
  has_one :author
106
106
  has_many :chapters
107
107
 
108
- has_many :reviews do
108
+ has_many :reviews do |reviews_list|
109
109
  has_one :review_author
110
+
111
+ field :review_calculatetable_field, -> { some_method(reviews_list) }
110
112
  end
113
+
114
+ field :book_calculatetable_field, -> { change_book_titles(books_list) }
111
115
  end
112
116
 
113
- has_one :passport, foreign_key: :user_id, scope: user_passports
114
- field :custom_field, scope: books.where(title: "1984")
117
+ has_one :passport, -> { passport_opts }
118
+ has_one :custom_field, -> { custom_field_opts }
119
+
120
+ field :user_calculatetable_field, -> { some_method(users_list) }
121
+ end
122
+ end
123
+
124
+ private
125
+
126
+ def change_book_titles(books_list)
127
+ books_list.each do |book|
128
+ book.title = "#{book.title.upcase} changed"
129
+ end
130
+ end
131
+
132
+ def some_method(list)
133
+ puts list.map(&:id)
134
+ puts list.map { _1.class.name }
135
+ end
136
+
137
+ def passport_opts
138
+ {
139
+ foreign_key: :user_id,
140
+ scope: user_passports
141
+ }
142
+ end
143
+
144
+ def custom_field_opts
145
+ {
146
+ scope: books.where(title: "1984")
147
+ }
148
+ end
149
+ end
150
+
151
+ class ReeDaoLoadAggTest::UsersAggWithDto
152
+ include ReeDao::AggregateDSL
153
+
154
+ aggregate :users_agg_with_dto do
155
+ link :users, from: :ree_dao_load_agg_test
156
+ link :organizations, from: :ree_dao_load_agg_test
157
+ link :load_agg, from: :ree_dao
158
+ end
159
+
160
+ def call(ids_or_scope, **opts)
161
+ load_agg(users, ids_or_scope, **opts) do
162
+ belongs_to :organization
115
163
  end
116
164
  end
117
165
  end
@@ -130,9 +178,9 @@ RSpec.describe :load_agg do
130
178
  end
131
179
 
132
180
  def call(ids_or_scope, **opts)
133
- load_agg(ids_or_scope, users, **opts) do
181
+ load_agg(users, ids_or_scope, **opts) do
134
182
  belongs_to :organization
135
- has_many :books, autoload_children: true do
183
+ has_many :books, -> { books_opts } do
136
184
  has_one :author
137
185
  has_many :chapters
138
186
 
@@ -142,6 +190,12 @@ RSpec.describe :load_agg do
142
190
  end
143
191
  end
144
192
  end
193
+
194
+ private
195
+
196
+ def books_opts
197
+ { autoload_children: true }
198
+ end
145
199
  end
146
200
 
147
201
  class ReeDaoLoadAggTest::UsersAggAutoloadReviewsChildren
@@ -158,18 +212,24 @@ RSpec.describe :load_agg do
158
212
  end
159
213
 
160
214
  def call(ids_or_scope, **opts)
161
- load_agg(ids_or_scope, users, **opts) do
215
+ load_agg(users, ids_or_scope, **opts) do
162
216
  belongs_to :organization
163
217
  has_many :books do
164
218
  has_one :author
165
219
  has_many :chapters
166
220
 
167
- has_many :reviews, autoload_children: true do
221
+ has_many :reviews, -> { { autoload_children: true } } do
168
222
  has_one :review_author
169
223
  end
170
224
  end
171
225
  end
172
226
  end
227
+
228
+ private
229
+
230
+ def reviews_opts
231
+ { autoload_children: true }
232
+ end
173
233
  end
174
234
 
175
235
  class ReeDaoLoadAggTest::UsersAggBlockTest
@@ -183,13 +243,22 @@ RSpec.describe :load_agg do
183
243
  end
184
244
 
185
245
  def call(ids_or_scope, **opts)
186
- load_agg(ids_or_scope, users, **opts) do
246
+ load_agg(users, ids_or_scope, **opts) do
187
247
  belongs_to :organization
188
- has_many :books, setter: -> (item, items_index) {
189
- item.set_books([1337, 1337])
190
- }
248
+ has_many :books, -> { books_opts }
191
249
  end
192
250
  end
251
+
252
+ private
253
+
254
+ def books_opts
255
+ {
256
+ setter: -> (item, items_index) {
257
+ b = items_index[item.id].each { |b| b.title = "Changed" }
258
+ item.set_books(b)
259
+ }
260
+ }
261
+ end
193
262
  end
194
263
 
195
264
  class ReeDaoLoadAggTest::UsersAggScopeMethodTest
@@ -203,17 +272,21 @@ RSpec.describe :load_agg do
203
272
  end
204
273
 
205
274
  def call(ids_or_scope, **opts)
206
- load_agg(ids_or_scope, users, **opts) do |agg_list|
275
+ load_agg(users, ids_or_scope, **opts) do |agg_list|
207
276
  some_id = agg_list.first.id
208
277
  title = "1984"
209
278
  belongs_to :organization
210
279
 
211
- has_many :books, scope: books_scope(title)
280
+ has_many :books, -> { books_opts(title) }
212
281
  end
213
282
  end
214
283
 
215
284
  private
216
285
 
286
+ def books_opts(title)
287
+ { scope: books_scope(title) }
288
+ end
289
+
217
290
  def books_scope(title)
218
291
  books.where(title: title)
219
292
  end
@@ -230,7 +303,7 @@ RSpec.describe :load_agg do
230
303
  end
231
304
 
232
305
  def call(ids_or_scope, **opts)
233
- load_agg(ids_or_scope, users, **opts) do
306
+ load_agg(users, ids_or_scope, **opts) do
234
307
  has_many :something
235
308
  end
236
309
  end
@@ -242,6 +315,7 @@ RSpec.describe :load_agg do
242
315
  let(:users_agg_autoload_books_children) { ReeDaoLoadAggTest::UsersAggAutoloadBooksChildren.new }
243
316
  let(:users_agg_autoload_reviews_children) { ReeDaoLoadAggTest::UsersAggAutoloadReviewsChildren.new }
244
317
  let(:users_agg_without_dao) { ReeDaoLoadAggTest::UsersAggWithoutDao.new }
318
+ let(:users_agg_with_dto) { ReeDaoLoadAggTest::UsersAggWithDto.new }
245
319
  let(:organizations) { ReeDaoLoadAggTest::Organizations.new }
246
320
  let(:users) { ReeDaoLoadAggTest::Users.new }
247
321
  let(:user_passports) { ReeDaoLoadAggTest::UserPassports.new }
@@ -266,6 +340,37 @@ RSpec.describe :load_agg do
266
340
  }.to raise_error(ArgumentError)
267
341
  }
268
342
 
343
+ it {
344
+ organizations.delete_all
345
+ users.delete_all
346
+
347
+ organization = ReeDaoLoadAggTest::Organization.new(name: "Test Org")
348
+ organizations.put(organization)
349
+
350
+ user_1 = ReeDaoLoadAggTest::User.new(name: "John", age: 33, organization_id: organization.id)
351
+ user_2 = ReeDaoLoadAggTest::User.new(name: "Sam", age: 21, organization_id: organization.id)
352
+ users.put(user_1)
353
+ users.put(user_2)
354
+
355
+ res = users_agg_with_dto.call(
356
+ users.all,
357
+ to_dto: -> (users) {
358
+ users.map do |user|
359
+ ReeDaoLoadAggTest::UserDto.new(
360
+ id: user.id,
361
+ name: user.name,
362
+ organization_id: user.organization_id,
363
+ full_name: user.name
364
+ )
365
+ end
366
+ }
367
+ )
368
+
369
+ res_user = res[0]
370
+
371
+ expect(res_user.class).to eq(ReeDaoLoadAggTest::UserDto)
372
+ }
373
+
269
374
  it {
270
375
  organizations.delete_all
271
376
  users.delete_all
@@ -316,6 +421,7 @@ RSpec.describe :load_agg do
316
421
  expect(res_user.passport).to eq(passport_1)
317
422
  expect(res_user.passport.info).to eq("some info")
318
423
  expect(res_user.books.count).to eq(2)
424
+ expect(res_user.books.map(&:title)).to eq(["1984 changed", "1408 changed"])
319
425
  expect(res_user.books[0].author.name).to eq("George Orwell")
320
426
  expect(res_user.books[0].chapters.map(&:title)).to eq(["beginning"])
321
427
  expect(res_user.books[0].reviews[0].review_author.name).to eq("John Review")
@@ -540,7 +646,7 @@ RSpec.describe :load_agg do
540
646
  res = users_agg_block.call(user_1.id)
541
647
 
542
648
  u = res[0]
543
- expect(u.books).to eq([1337, 1337])
649
+ expect(u.books.map(&:title)).to eq(["Changed"])
544
650
  }
545
651
 
546
652
  it {
@@ -594,7 +700,7 @@ RSpec.describe :load_agg do
594
700
 
595
701
  ids = [user_1, user_2].map(&:id)
596
702
 
597
- res = load_agg(ids, users)
703
+ res = load_agg(users, ids)
598
704
  expect(res.count).to eq(2)
599
705
  }
600
706
 
@@ -608,7 +714,7 @@ RSpec.describe :load_agg do
608
714
  user_1 = ReeDaoLoadAggTest::User.new(name: "John", age: 33, organization_id: organization.id)
609
715
  users.put(user_1)
610
716
 
611
- res = load_agg(user_1.id, users)
717
+ res = load_agg(users, user_1.id)
612
718
  expect(res.count).to eq(1)
613
719
  }
614
720
 
@@ -624,7 +730,7 @@ RSpec.describe :load_agg do
624
730
  users.put(user_1)
625
731
  users.put(user_2)
626
732
 
627
- res = load_agg(users.where(organization_id: organization.id), users)
733
+ res = load_agg(users, users.where(organization_id: organization.id))
628
734
  expect(res.count).to eq(2)
629
735
  }
630
736
  end
@@ -35,25 +35,45 @@ class ReeDaoLoadAggTest::Db
35
35
  end
36
36
  end
37
37
 
38
- class ReeDaoLoadAggTest::Organization
38
+ class ReeDaoLoadAggTest::Book
39
39
  include ReeDto::EntityDSL
40
40
 
41
41
  properties(
42
42
  id: Nilor[Integer],
43
- name: String
43
+ user_id: Integer,
44
+ title: Nilor[String]
44
45
  )
45
46
 
46
- def set_users(users)
47
- @users = users
47
+ def set_chapters(chapters)
48
+ @chapters = chapters; nil
48
49
  end
49
50
 
50
- def users
51
- @users ||= []
51
+ def chapters
52
+ @chapters
52
53
  end
53
54
 
54
- attr_accessor :name
55
- end
55
+ def set_author(author)
56
+ @author = author
57
+ end
58
+
59
+ def author
60
+ @author
61
+ end
62
+
63
+ def set_reviews(reviews)
64
+ @reviews = reviews; nil
65
+ end
66
+
67
+ def reviews
68
+ @reviews
69
+ end
56
70
 
71
+ def title=(t)
72
+ @title = t
73
+ end
74
+
75
+ attr_accessor :title, :user_id
76
+ end
57
77
 
58
78
  class ReeDaoLoadAggTest::User
59
79
  include ReeDto::EntityDSL
@@ -81,10 +101,18 @@ class ReeDaoLoadAggTest::User
81
101
  @passport
82
102
  end
83
103
 
104
+ def books
105
+ @books
106
+ end
107
+
108
+ contract(ArrayOf[ReeDaoLoadAggTest::Book] => nil)
109
+ def set_books(books)
110
+ @books = books; nil
111
+ end
112
+
84
113
  [
85
114
  :organization,
86
115
  :passport,
87
- :books,
88
116
  :movies,
89
117
  :videogames,
90
118
  :hobbies,
@@ -106,6 +134,45 @@ class ReeDaoLoadAggTest::User
106
134
  attr_accessor :name, :age, :organization_id
107
135
  end
108
136
 
137
+ class ReeDaoLoadAggTest::UserDto
138
+ include ReeDto::EntityDSL
139
+
140
+ properties(
141
+ id: Integer,
142
+ organization_id: Integer,
143
+ name: String,
144
+ full_name: String,
145
+ )
146
+
147
+ def set_organization(org)
148
+ @organization = org; nil
149
+ end
150
+
151
+ def organization
152
+ @organization
153
+ end
154
+ end
155
+
156
+ class ReeDaoLoadAggTest::Organization
157
+ include ReeDto::EntityDSL
158
+
159
+ properties(
160
+ id: Nilor[Integer],
161
+ name: String
162
+ )
163
+
164
+ contract(Array[ReeDaoLoadAggTest::User] => nil)
165
+ def set_users(users)
166
+ @users = users; nil
167
+ end
168
+
169
+ def users
170
+ @users ||= []
171
+ end
172
+
173
+ attr_accessor :name
174
+ end
175
+
109
176
 
110
177
  class ReeDaoLoadAggTest::UserPassport
111
178
  include ReeDto::EntityDSL
@@ -189,42 +256,6 @@ class ReeDaoLoadAggTest::Dream
189
256
  )
190
257
  end
191
258
 
192
- class ReeDaoLoadAggTest::Book
193
- include ReeDto::EntityDSL
194
-
195
- properties(
196
- id: Nilor[Integer],
197
- user_id: Integer,
198
- title: Nilor[String]
199
- )
200
-
201
- def set_chapters(chapters)
202
- @chapters = chapters; nil
203
- end
204
-
205
- def chapters
206
- @chapters
207
- end
208
-
209
- def set_author(author)
210
- @author = author
211
- end
212
-
213
- def author
214
- @author
215
- end
216
-
217
- def set_reviews(reviews)
218
- @reviews = reviews; nil
219
- end
220
-
221
- def reviews
222
- @reviews
223
- end
224
-
225
- attr_accessor :title, :user_id
226
- end
227
-
228
259
  class ReeDaoLoadAggTest::Chapter
229
260
  include ReeDto::EntityDSL
230
261
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReeLib
4
- VERSION = "1.0.54"
4
+ VERSION = "1.0.56"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ree_lib
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.54
4
+ version: 1.0.56
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruslan Gatiyatov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-07-28 00:00:00.000000000 Z
11
+ date: 2023-07-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ree