ree_lib 1.0.64 → 1.0.65

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: 58dcd5d4f8eeefdbea1dc995ea2e76734a8dccc6a913354085453ca9a0ddd72e
4
- data.tar.gz: 1d29d9be3027f3d57e3502e6269ac3cd455e50e5ecdf4b17ea73877b15379423
3
+ metadata.gz: e6a080727db9b2998d5e983aa2e024fd73833e6b98deb2f75eb8ac8309af1c6b
4
+ data.tar.gz: b96cc24d1df8586e8159e96c7545017ecab7009a01bd5b9a2b9c759fb1beeddd
5
5
  SHA512:
6
- metadata.gz: 35b733d5bcaf9f7f837d212c7279c77044f29e11b5e48d0480a879180497f77805b3aa0bf5e17a8b2b1aa991f769a1452fad291d6895436d8d1eca6e9a6a4fb6
7
- data.tar.gz: '08ec8fe4b53aceff584a515ca820484e59bfa387ae3d5f9c9d21fcdf73afa018d777882f40cab8e6f835fc5eb80ca941977f211614aa0005e10ebcea9fc333c9'
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.64)
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,8 +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
8
+ link :underscore, from: :ree_string
7
9
 
8
10
  attr_reader :parent, :parent_dao_name, :list, :global_opts
9
11
 
@@ -21,8 +23,8 @@ module ReeDao
21
23
  Ksplat[RestKeys => Any],
22
24
  Optblock => Array
23
25
  )
24
- def load(assoc_type, assoc_name, **opts, &block)
25
- 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)
26
28
  end
27
29
 
28
30
  def handle_field(field_proc)
@@ -35,19 +37,30 @@ module ReeDao
35
37
  Ksplat[RestKeys => Any],
36
38
  Optblock => Nilor[Array]
37
39
  )
38
- def load_association(assoc_type, assoc_name, **opts, &block)
39
- opts[:autoload_children] ||= false
40
+ def load_association(assoc_type, assoc_name, **__opts, &block)
41
+ __opts[:autoload_children] ||= false
40
42
 
41
43
  assoc_index = load_association_by_type(
42
44
  assoc_type,
43
45
  assoc_name,
44
- **opts
46
+ **__opts
45
47
  )
46
48
 
47
- dao = find_dao(assoc_name, parent, opts[:scope])
48
- dao_name = dao.first_source_table
49
+ dao = find_dao(assoc_name, parent, __opts[:scope])
49
50
 
50
- 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?
51
64
 
52
65
  list
53
66
  end
@@ -57,17 +70,17 @@ module ReeDao
57
70
  Symbol,
58
71
  Ksplat[RestKeys => Any] => Any
59
72
  )
60
- def load_association_by_type(type, assoc_name, **opts)
73
+ def load_association_by_type(type, assoc_name, **__opts)
61
74
  case type
62
75
  when :belongs_to
63
76
  one_to_one(
64
77
  parent_dao_name,
65
78
  assoc_name,
66
79
  list,
67
- scope: opts[:scope],
68
- primary_key: opts[:primary_key],
69
- foreign_key: opts[:foreign_key],
70
- setter: opts[:setter],
80
+ scope: __opts[:scope],
81
+ primary_key: __opts[:primary_key],
82
+ foreign_key: __opts[:foreign_key],
83
+ setter: __opts[:setter],
71
84
  reverse: false
72
85
  )
73
86
  when :has_one
@@ -75,11 +88,11 @@ module ReeDao
75
88
  parent_dao_name,
76
89
  assoc_name,
77
90
  list,
78
- scope: opts[:scope],
79
- primary_key: opts[:primary_key],
80
- foreign_key: opts[:foreign_key],
81
- to_dto: opts[:to_dto],
82
- 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],
83
96
  reverse: true
84
97
  )
85
98
  when :has_many
@@ -87,11 +100,11 @@ module ReeDao
87
100
  parent_dao_name,
88
101
  assoc_name,
89
102
  list,
90
- scope: opts[:scope],
91
- primary_key: opts[:primary_key],
92
- foreign_key: opts[:foreign_key],
93
- to_dto: opts[:to_dto],
94
- 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]
95
108
  )
96
109
  end
97
110
  end
@@ -124,9 +137,9 @@ module ReeDao
124
137
  autoload_children,
125
138
  **global_opts
126
139
  ).instance_exec(assoc_list, &block)
127
- 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|
128
141
  Thread.new do
129
- association.load(assoc_type, assoc_name, **opts, &block)
142
+ association.load(assoc_type, assoc_name, **__opts, &block)
130
143
  end
131
144
  end.map(&:join)
132
145
 
@@ -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
@@ -290,7 +306,11 @@ module ReeDao
290
306
  key = if reverse.nil?
291
307
  primary_key
292
308
  else
293
- reverse ? primary_key : "#{assoc_name}_id"
309
+ if reverse
310
+ primary_key
311
+ else
312
+ foreign_key ? foreign_key : "#{assoc_name}_id"
313
+ end
294
314
  end
295
315
 
296
316
  value = association_index[item.send(key)]
@@ -330,6 +350,7 @@ module ReeDao
330
350
  return dao_from_name if dao_from_name
331
351
 
332
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)
333
354
 
334
355
  table_name = scope.first_source_table
335
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
@@ -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) }
@@ -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.64"
4
+ VERSION = "1.0.65"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ree_lib
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.64
4
+ version: 1.0.65
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruslan Gatiyatov