ree_lib 1.0.63 → 1.0.65

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bf0b2d37f1b4dab2dd798faa601db7969c49479c02eb39ee67a1a7344231b887
4
- data.tar.gz: aabcce88a49279d7d1d970e59056a43b866edd4d81d0a64cb553c0142b9da4c2
3
+ metadata.gz: e6a080727db9b2998d5e983aa2e024fd73833e6b98deb2f75eb8ac8309af1c6b
4
+ data.tar.gz: b96cc24d1df8586e8159e96c7545017ecab7009a01bd5b9a2b9c759fb1beeddd
5
5
  SHA512:
6
- metadata.gz: f9bd4b78d0c104dccaee61ac1ab1979596c2d90c9006c0e939cb26c8984401d7e724edfff81f4ff106b9a5d153ab1a687bf3d1bb963ecefa1929839e81a0183c
7
- data.tar.gz: cbe3d31611bf98d43bd5cced27d68689bf739e04a87c023e96ede58b9ea500319ec907e2df6ce55f17ff752bc34c4c0e727ab34ed721b51130e251657d6764b3
6
+ metadata.gz: c1a8e3c1d0471a58cb3dd4602a83a8da2f30498e4af39f9ade709a256592d8f3a6ef6c58a14a8fff1c3f865d9508c49e5673d4bbbe8d0ddbe95fa5dd37074695
7
+ data.tar.gz: 34e1a0221ad4040a469082111c63687903e6e5d6a89d25c8ada10f742efbd6774e0e8bc729c251670a5ef293b4917dfebe3c701be6155f84241a4a651d952b9c
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ree_lib (1.0.63)
4
+ ree_lib (1.0.65)
5
5
  binding_of_caller (~> 1.0.0)
6
6
  i18n (~> 1.12.0)
7
7
  loofah (~> 2.18.0)
@@ -2,9 +2,10 @@ module ReeDao
2
2
  class Association
3
3
  include Ree::LinkDSL
4
4
 
5
+ link :demodulize, from: :ree_string
5
6
  link :group_by, from: :ree_array
6
7
  link :index_by, from: :ree_array
7
- link :transform_values, from: :ree_hash
8
+ link :underscore, from: :ree_string
8
9
 
9
10
  attr_reader :parent, :parent_dao_name, :list, :global_opts
10
11
 
@@ -22,8 +23,8 @@ module ReeDao
22
23
  Ksplat[RestKeys => Any],
23
24
  Optblock => Array
24
25
  )
25
- def load(assoc_type, assoc_name, **opts, &block)
26
- load_association(assoc_type, assoc_name, **opts, &block)
26
+ def load(assoc_type, assoc_name, **__opts, &block)
27
+ load_association(assoc_type, assoc_name, **__opts, &block)
27
28
  end
28
29
 
29
30
  def handle_field(field_proc)
@@ -36,19 +37,30 @@ module ReeDao
36
37
  Ksplat[RestKeys => Any],
37
38
  Optblock => Nilor[Array]
38
39
  )
39
- def load_association(assoc_type, assoc_name, **opts, &block)
40
- opts[:autoload_children] ||= false
40
+ def load_association(assoc_type, assoc_name, **__opts, &block)
41
+ __opts[:autoload_children] ||= false
41
42
 
42
43
  assoc_index = load_association_by_type(
43
44
  assoc_type,
44
45
  assoc_name,
45
- **opts
46
+ **__opts
46
47
  )
47
48
 
48
- dao = find_dao(assoc_name, parent, opts[:scope])
49
- dao_name = dao.first_source_table
49
+ dao = find_dao(assoc_name, parent, __opts[:scope])
50
50
 
51
- process_block(assoc_index, opts[:autoload_children], opts[:to_dto], dao_name, &block) if block_given?
51
+ dao_name = if dao
52
+ dao.first_source_table
53
+ elsif __opts[:scope].is_a?(Array)
54
+ name = underscore(demodulize(__opts[:scope].first.class.name))
55
+
56
+ if name.end_with?("s")
57
+ "#{name}es"
58
+ else
59
+ "#{name}s"
60
+ end
61
+ end
62
+
63
+ process_block(assoc_index, __opts[:autoload_children], __opts[:to_dto], dao_name, &block) if block_given?
52
64
 
53
65
  list
54
66
  end
@@ -58,17 +70,17 @@ module ReeDao
58
70
  Symbol,
59
71
  Ksplat[RestKeys => Any] => Any
60
72
  )
61
- def load_association_by_type(type, assoc_name, **opts)
73
+ def load_association_by_type(type, assoc_name, **__opts)
62
74
  case type
63
75
  when :belongs_to
64
76
  one_to_one(
65
77
  parent_dao_name,
66
78
  assoc_name,
67
79
  list,
68
- scope: opts[:scope],
69
- primary_key: opts[:primary_key],
70
- foreign_key: opts[:foreign_key],
71
- setter: opts[:setter],
80
+ scope: __opts[:scope],
81
+ primary_key: __opts[:primary_key],
82
+ foreign_key: __opts[:foreign_key],
83
+ setter: __opts[:setter],
72
84
  reverse: false
73
85
  )
74
86
  when :has_one
@@ -76,11 +88,11 @@ module ReeDao
76
88
  parent_dao_name,
77
89
  assoc_name,
78
90
  list,
79
- scope: opts[:scope],
80
- primary_key: opts[:primary_key],
81
- foreign_key: opts[:foreign_key],
82
- to_dto: opts[:to_dto],
83
- setter: opts[:setter],
91
+ scope: __opts[:scope],
92
+ primary_key: __opts[:primary_key],
93
+ foreign_key: __opts[:foreign_key],
94
+ to_dto: __opts[:to_dto],
95
+ setter: __opts[:setter],
84
96
  reverse: true
85
97
  )
86
98
  when :has_many
@@ -88,11 +100,11 @@ module ReeDao
88
100
  parent_dao_name,
89
101
  assoc_name,
90
102
  list,
91
- scope: opts[:scope],
92
- primary_key: opts[:primary_key],
93
- foreign_key: opts[:foreign_key],
94
- to_dto: opts[:to_dto],
95
- setter: opts[:setter]
103
+ scope: __opts[:scope],
104
+ primary_key: __opts[:primary_key],
105
+ foreign_key: __opts[:foreign_key],
106
+ to_dto: __opts[:to_dto],
107
+ setter: __opts[:setter]
96
108
  )
97
109
  end
98
110
  end
@@ -125,9 +137,9 @@ module ReeDao
125
137
  autoload_children,
126
138
  **global_opts
127
139
  ).instance_exec(assoc_list, &block)
128
- threads[:association_threads].map do |association, assoc_type, assoc_name, opts, block|
140
+ threads[:association_threads].map do |association, assoc_type, assoc_name, __opts, block|
129
141
  Thread.new do
130
- association.load(assoc_type, assoc_name, **opts, &block)
142
+ association.load(assoc_type, assoc_name, **__opts, &block)
131
143
  end
132
144
  end.map(&:join)
133
145
 
@@ -163,12 +175,14 @@ module ReeDao
163
175
  assoc_dao = find_dao(assoc_name, parent, scope)
164
176
 
165
177
  if reverse
178
+ # has_one
166
179
  if !foreign_key
167
180
  foreign_key = "#{parent_assoc_name.to_s.gsub(/s$/,'')}_id".to_sym
168
181
  end
169
182
 
170
183
  root_ids = list.map(&:id).uniq
171
184
  else
185
+ # belongs_to
172
186
  if !foreign_key
173
187
  foreign_key = :"#{assoc_name}_id"
174
188
  end
@@ -182,7 +196,6 @@ module ReeDao
182
196
  items = add_scopes(scope, global_opts[assoc_name])
183
197
  end
184
198
 
185
-
186
199
  assoc = index_by(items) { _1.send(reverse ? foreign_key : :id) }
187
200
 
188
201
  populate_association(
@@ -192,6 +205,7 @@ module ReeDao
192
205
  setter: setter,
193
206
  reverse: reverse,
194
207
  primary_key: primary_key,
208
+ foreign_key: foreign_key,
195
209
  to_dto: to_dto
196
210
  )
197
211
 
@@ -243,6 +257,7 @@ module ReeDao
243
257
  assoc_name,
244
258
  setter: setter,
245
259
  primary_key: primary_key,
260
+ foreign_key: foreign_key,
246
261
  to_dto: to_dto,
247
262
  multiple: true
248
263
  )
@@ -256,13 +271,14 @@ module ReeDao
256
271
  Symbol,
257
272
  Kwargs[
258
273
  primary_key: Nilor[Symbol],
274
+ foreign_key: Nilor[Symbol],
259
275
  reverse: Nilor[Bool],
260
276
  setter: Nilor[Or[Symbol, Proc]],
261
277
  to_dto: Nilor[Proc],
262
278
  multiple: Bool
263
279
  ] => Any
264
280
  )
265
- def populate_association(list, association_index, assoc_name, primary_key: nil, reverse: nil, setter: nil, to_dto: nil, multiple: false)
281
+ def populate_association(list, association_index, assoc_name, primary_key: nil, foreign_key: nil, reverse: nil, setter: nil, to_dto: nil, multiple: false)
266
282
  assoc_setter = if setter
267
283
  setter
268
284
  else
@@ -272,11 +288,13 @@ module ReeDao
272
288
  list.each do |item|
273
289
  if setter && setter.is_a?(Proc)
274
290
  if to_dto
275
- assoc_index = transform_values(association_index) do |key, value|
291
+ assoc_index = {}
292
+
293
+ association_index.each do |key, value|
276
294
  if value.is_a?(Array)
277
- value.map { to_dto.call(_1) }
295
+ assoc_index[key] = value.map { to_dto.call(_1) }
278
296
  else
279
- to_dto.call(value)
297
+ assoc_index[key] = to_dto.call(value)
280
298
  end
281
299
  end
282
300
 
@@ -288,7 +306,11 @@ module ReeDao
288
306
  key = if reverse.nil?
289
307
  primary_key
290
308
  else
291
- reverse ? primary_key : "#{assoc_name}_id"
309
+ if reverse
310
+ primary_key
311
+ else
312
+ foreign_key ? foreign_key : "#{assoc_name}_id"
313
+ end
292
314
  end
293
315
 
294
316
  value = association_index[item.send(key)]
@@ -328,6 +350,7 @@ module ReeDao
328
350
  return dao_from_name if dao_from_name
329
351
 
330
352
  raise ArgumentError, "can't find DAO for :#{assoc_name}, provide correct scope or association name" if scope.nil?
353
+ return nil if scope.is_a?(Array)
331
354
 
332
355
  table_name = scope.first_source_table
333
356
  dao_from_scope = parent.instance_variable_get("@#{table_name}")
@@ -14,8 +14,13 @@ module ReeDao
14
14
  @parent_dao_name = parent_dao_name
15
15
  @autoload_children = autoload_children
16
16
 
17
- raise ArgumentError.new("you can't use both :only and :except arguments at the same time") if @only && @except
17
+ if @only && @except
18
+ shared_keys = @only.intersection(@except)
18
19
 
20
+ if shared_keys.size > 0
21
+ raise ArgumentError.new("you can't use both :only and :except for #{shared_keys.map { "\"#{_1}\"" }.join(", ")} keys")
22
+ end
23
+ end
19
24
 
20
25
  if !self.class.sync_mode?
21
26
  @assoc_threads = []
@@ -40,8 +45,8 @@ module ReeDao
40
45
  Nilor[Proc, Sequel::Dataset],
41
46
  Optblock => Any
42
47
  )
43
- def belongs_to(assoc_name, opts = nil, &block)
44
- association(__method__, assoc_name, opts, &block)
48
+ def belongs_to(assoc_name, __opts = nil, &block)
49
+ association(__method__, assoc_name, __opts, &block)
45
50
  end
46
51
 
47
52
  contract(
@@ -49,8 +54,8 @@ module ReeDao
49
54
  Nilor[Proc, Sequel::Dataset],
50
55
  Optblock => Any
51
56
  )
52
- def has_one(assoc_name, opts = nil, &block)
53
- association(__method__, assoc_name, opts, &block)
57
+ def has_one(assoc_name, __opts = nil, &block)
58
+ association(__method__, assoc_name, __opts, &block)
54
59
  end
55
60
 
56
61
  contract(
@@ -58,8 +63,8 @@ module ReeDao
58
63
  Nilor[Proc, Sequel::Dataset],
59
64
  Optblock => Any
60
65
  )
61
- def has_many(assoc_name, opts = nil, &block)
62
- association(__method__, assoc_name, opts, &block)
66
+ def has_many(assoc_name, __opts = nil, &block)
67
+ association(__method__, assoc_name, __opts, &block)
63
68
  end
64
69
 
65
70
  contract(Symbol, Proc => Any)
@@ -80,16 +85,16 @@ module ReeDao
80
85
  Nilor[Proc, Sequel::Dataset],
81
86
  Optblock => Any
82
87
  )
83
- def association(assoc_type, assoc_name, opts, &block)
88
+ def association(assoc_type, assoc_name, __opts, &block)
84
89
  if self.class.sync_mode?
85
90
  return if association_is_not_included?(assoc_name) || list.empty?
86
91
 
87
92
  association = Association.new(self, parent_dao_name, list, **global_opts)
88
93
 
89
94
  if assoc_type == :field
90
- association.handle_field(assoc_name, opts)
95
+ association.handle_field(assoc_name, __opts)
91
96
  else
92
- association.load(assoc_type, assoc_name, **get_assoc_opts(opts), &block)
97
+ association.load(assoc_type, assoc_name, **get_assoc_opts(__opts), &block)
93
98
  end
94
99
  else
95
100
  if association_is_not_included?(assoc_name) || list.empty?
@@ -99,7 +104,7 @@ module ReeDao
99
104
  association = Association.new(self, parent_dao_name, list, **global_opts)
100
105
 
101
106
  if assoc_type == :field
102
- field_proc = opts
107
+ field_proc = __opts
103
108
  {
104
109
  association_threads: @assoc_threads,
105
110
  field_threads: @field_threads << [
@@ -109,7 +114,7 @@ module ReeDao
109
114
  else
110
115
  {
111
116
  association_threads: @assoc_threads << [
112
- association, assoc_type, assoc_name, get_assoc_opts(opts), block
117
+ association, assoc_type, assoc_name, get_assoc_opts(__opts), block
113
118
  ],
114
119
  field_threads: @field_threads
115
120
  }
@@ -125,7 +130,10 @@ module ReeDao
125
130
  return false if only && only.include?(assoc_name)
126
131
 
127
132
  if only && !only.include?(assoc_name)
128
- return false if autoload_children
133
+ if autoload_children
134
+ return true if except && except.include?(assoc_name)
135
+ return false
136
+ end
129
137
  return true
130
138
  end
131
139
  end
@@ -251,7 +251,9 @@ RSpec.describe :load_agg do
251
251
 
252
252
  _users = []
253
253
  st_time = Time.now
254
+
254
255
  puts "Seeding #{NUM_OF_USERS} users..."
256
+
255
257
  NUM_OF_USERS.times do
256
258
  u = ReeDaoLoadAggTest::User.new(
257
259
  name: Faker::Name.name,
@@ -105,7 +105,7 @@ RSpec.describe :load_agg do
105
105
  has_one :author
106
106
  has_many :chapters
107
107
 
108
- has_many :reviews do |reviews_list|
108
+ has_many :reviews, -> { reviews_opts } do |reviews_list|
109
109
  has_one :review_author
110
110
 
111
111
  field :review_calculatetable_field, -> { some_method(reviews_list) }
@@ -130,8 +130,8 @@ RSpec.describe :load_agg do
130
130
  end
131
131
 
132
132
  def some_method(list)
133
- puts list.map(&:id)
134
- puts list.map { _1.class.name }
133
+ # puts list.map(&:id)
134
+ # puts list.map { _1.class.name }
135
135
  end
136
136
 
137
137
  def passport_opts
@@ -146,6 +146,10 @@ RSpec.describe :load_agg do
146
146
  scope: books.where(title: "1984")
147
147
  }
148
148
  end
149
+
150
+ def reviews_opts
151
+ { autoload_children: true }
152
+ end
149
153
  end
150
154
 
151
155
  class ReeDaoLoadAggTest::UsersAggWithDto
@@ -353,6 +357,24 @@ RSpec.describe :load_agg do
353
357
  end
354
358
  end
355
359
 
360
+ class ReeDaoLoadAggTest::UsersAggOnlyExceptKeys
361
+ include ReeDao::AggregateDSL
362
+
363
+ aggregate :users_agg_only_except_keys do
364
+ link :users, from: :ree_dao_load_agg_test
365
+ link :organizations, from: :ree_dao_load_agg_test
366
+ link :books, from: :ree_dao_load_agg_test
367
+ link :load_agg, from: :ree_dao
368
+ end
369
+
370
+ def call(ids_or_scope, **opts)
371
+ load_agg(users, ids_or_scope, **opts) do
372
+ belongs_to :organization
373
+ has_many :books
374
+ end
375
+ end
376
+ end
377
+
356
378
  let(:users_agg) { ReeDaoLoadAggTest::UsersAgg.new }
357
379
  let(:users_agg_block) { ReeDaoLoadAggTest::UsersAggBlockTest.new }
358
380
  let(:users_agg_scope_method) { ReeDaoLoadAggTest::UsersAggScopeMethodTest.new }
@@ -361,6 +383,7 @@ RSpec.describe :load_agg do
361
383
  let(:users_agg_without_dao) { ReeDaoLoadAggTest::UsersAggWithoutDao.new }
362
384
  let(:users_agg_with_dto) { ReeDaoLoadAggTest::UsersAggWithDto.new }
363
385
  let(:users_agg_only_dataset) { ReeDaoLoadAggTest::UsersAggOnlyDataset.new }
386
+ let(:user_agg_only_except_keys) { ReeDaoLoadAggTest::UsersAggOnlyExceptCase.new }
364
387
  let(:organizations) { ReeDaoLoadAggTest::Organizations.new }
365
388
  let(:users) { ReeDaoLoadAggTest::Users.new }
366
389
  let(:user_passports) { ReeDaoLoadAggTest::UserPassports.new }
@@ -385,6 +408,69 @@ RSpec.describe :load_agg do
385
408
  }.to raise_error(ArgumentError)
386
409
  }
387
410
 
411
+ it {
412
+ organizations.delete_all
413
+ users.delete_all
414
+ user_passports.delete_all
415
+ books.delete_all
416
+ chapters.delete_all
417
+
418
+ organization = ReeDaoLoadAggTest::Organization.new(name: "Test Org")
419
+ organizations.put(organization)
420
+
421
+ user_1 = ReeDaoLoadAggTest::User.new(name: "John", age: 33, organization_id: organization.id)
422
+ user_2 = ReeDaoLoadAggTest::User.new(name: "Sam", age: 21, organization_id: organization.id)
423
+ users.put(user_1)
424
+ users.put(user_2)
425
+
426
+ passport_1 = ReeDaoLoadAggTest::UserPassport.new(user_id: user_1.id, info: "some info")
427
+ user_passports.put(passport_1)
428
+ user_passports.put(ReeDaoLoadAggTest::UserPassport.new(user_id: user_2.id, info: "another info"))
429
+
430
+ book_1 = ReeDaoLoadAggTest::Book.new(user_id: user_1.id, title: "1984")
431
+ book_2 = ReeDaoLoadAggTest::Book.new(user_id: user_1.id, title: "1408")
432
+
433
+ books.put(book_1)
434
+ books.put(book_2)
435
+
436
+ chapter = ReeDaoLoadAggTest::Chapter.new(book_id: book_1.id, title: "beginning")
437
+ chapters.put(chapter)
438
+ chapters.put(ReeDaoLoadAggTest::Chapter.new(book_id: book_1.id, title: "interlude"))
439
+ chapters.put(ReeDaoLoadAggTest::Chapter.new(book_id: book_1.id, title: "tragic ending"))
440
+ chapters.put(ReeDaoLoadAggTest::Chapter.new(book_id: book_2.id, title: "beginning"))
441
+ chapters.put(ReeDaoLoadAggTest::Chapter.new(book_id: book_2.id, title: "ending"))
442
+
443
+
444
+ authors.put(ReeDaoLoadAggTest::Author.new(book_id: book_1.id, name: "George Orwell"))
445
+ review = ReeDaoLoadAggTest::Review.new(book_id: book_1.id, rating: 10)
446
+ reviews.put(review)
447
+ reviews.put(ReeDaoLoadAggTest::Review.new(book_id: book_1.id, rating: 7))
448
+ review_authors.put(ReeDaoLoadAggTest::ReviewAuthor.new(review_id: review.id, name: "John Review"))
449
+
450
+ res = users_agg.call(
451
+ users.all,
452
+ only: [:books, :reviews],
453
+ except: [:review_author]
454
+ )
455
+
456
+ expect(res.first.books.first.reviews.first.review_author).to eq(nil)
457
+ }
458
+
459
+ it {
460
+ organizations.delete_all
461
+ users.delete_all
462
+
463
+ organization = ReeDaoLoadAggTest::Organization.new(name: "Test Org")
464
+ organizations.put(organization)
465
+
466
+ user = ReeDaoLoadAggTest::User.new(name: "John", age: 33, organization_id: organization.id)
467
+ users.put(user)
468
+
469
+ expect {
470
+ users_agg_without_dao.call(users.all, only: [:books], except: [:books])
471
+ }.to raise_error(ArgumentError, "you can't use both :only and :except for \"books\" keys")
472
+ }
473
+
388
474
  it {
389
475
  organizations.delete_all
390
476
  users.delete_all
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReeLib
4
- VERSION = "1.0.63"
4
+ VERSION = "1.0.65"
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.63
4
+ version: 1.0.65
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-31 00:00:00.000000000 Z
11
+ date: 2023-08-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ree