auction_fun_core 0.8.7 → 0.8.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/.standard.yml +2 -0
  3. data/CHANGELOG.md +23 -0
  4. data/Procfile +1 -0
  5. data/README.md +34 -32
  6. data/Rakefile +1 -1
  7. data/i18n/en-US/contracts/contracts.en-US.yml +3 -0
  8. data/i18n/en-US/mail/application.en-US.yml +7 -0
  9. data/i18n/en-US/mail/auction_context/pre_auction/auction_start_reminder.en-US.yml +11 -0
  10. data/i18n/pt-BR/contracts/contracts.pt-BR.yml +3 -0
  11. data/i18n/pt-BR/mail/application.pt-BR.yml +7 -0
  12. data/i18n/pt-BR/mail/auction_context/pre_auction/auction_start_reminder.pt-BR.yml +11 -0
  13. data/lib/auction_fun_core/business/configuration.rb +31 -0
  14. data/lib/auction_fun_core/business/token_generator.rb +19 -1
  15. data/lib/auction_fun_core/contracts/application_contract.rb +9 -1
  16. data/lib/auction_fun_core/contracts/auction_context/create_contract.rb +35 -20
  17. data/lib/auction_fun_core/contracts/auction_context/post_auction/participant_contract.rb +23 -1
  18. data/lib/auction_fun_core/contracts/auction_context/post_auction/winner_contract.rb +22 -1
  19. data/lib/auction_fun_core/contracts/auction_context/pre_auction/auction_start_reminder_contract.rb +48 -0
  20. data/lib/auction_fun_core/contracts/auction_context/processor/finish/closed_contract.rb +19 -7
  21. data/lib/auction_fun_core/contracts/auction_context/processor/finish/penny_contract.rb +19 -7
  22. data/lib/auction_fun_core/contracts/auction_context/processor/finish/standard_contract.rb +19 -7
  23. data/lib/auction_fun_core/contracts/auction_context/processor/pause_contract.rb +16 -4
  24. data/lib/auction_fun_core/contracts/auction_context/processor/start_contract.rb +17 -5
  25. data/lib/auction_fun_core/contracts/auction_context/processor/unpause_contract.rb +16 -4
  26. data/lib/auction_fun_core/contracts/bid_context/create_bid_closed_contract.rb +20 -11
  27. data/lib/auction_fun_core/contracts/bid_context/create_bid_penny_contract.rb +18 -9
  28. data/lib/auction_fun_core/contracts/bid_context/create_bid_standard_contract.rb +19 -10
  29. data/lib/auction_fun_core/contracts/staff_context/authentication_contract.rb +18 -4
  30. data/lib/auction_fun_core/contracts/staff_context/registration_contract.rb +20 -8
  31. data/lib/auction_fun_core/contracts/user_context/authentication_contract.rb +18 -4
  32. data/lib/auction_fun_core/contracts/user_context/email_confirmation_contract.rb +17 -2
  33. data/lib/auction_fun_core/contracts/user_context/phone_confirmation_contract.rb +17 -2
  34. data/lib/auction_fun_core/contracts/user_context/registration_contract.rb +26 -8
  35. data/lib/auction_fun_core/entities/auction.rb +48 -4
  36. data/lib/auction_fun_core/entities/bid.rb +3 -2
  37. data/lib/auction_fun_core/entities/staff.rb +15 -2
  38. data/lib/auction_fun_core/entities/user.rb +31 -2
  39. data/lib/auction_fun_core/events/app.rb +8 -2
  40. data/lib/auction_fun_core/events/listener.rb +19 -16
  41. data/lib/auction_fun_core/operations/auction_context/create_operation.rb +25 -9
  42. data/lib/auction_fun_core/operations/auction_context/post_auction/participant_operation.rb +36 -3
  43. data/lib/auction_fun_core/operations/auction_context/post_auction/winner_operation.rb +36 -2
  44. data/lib/auction_fun_core/operations/auction_context/pre_auction/auction_start_reminder_operation.rb +96 -0
  45. data/lib/auction_fun_core/operations/auction_context/processor/finish/closed_operation.rb +82 -10
  46. data/lib/auction_fun_core/operations/auction_context/processor/finish/penny_operation.rb +81 -10
  47. data/lib/auction_fun_core/operations/auction_context/processor/finish/standard_operation.rb +81 -12
  48. data/lib/auction_fun_core/operations/auction_context/processor/pause_operation.rb +36 -1
  49. data/lib/auction_fun_core/operations/auction_context/processor/unpause_operation.rb +36 -1
  50. data/lib/auction_fun_core/relations/auctions.rb +178 -97
  51. data/lib/auction_fun_core/relations/bids.rb +18 -0
  52. data/lib/auction_fun_core/repos/auction_context/auction_repository.rb +40 -11
  53. data/lib/auction_fun_core/repos/bid_context/bid_repository.rb +27 -5
  54. data/lib/auction_fun_core/repos/staff_context/staff_repository.rb +63 -21
  55. data/lib/auction_fun_core/repos/user_context/user_repository.rb +69 -25
  56. data/lib/auction_fun_core/services/mail/auction_context/post_auction/participant_mailer.rb +7 -1
  57. data/lib/auction_fun_core/services/mail/auction_context/post_auction/winner_mailer.rb +7 -1
  58. data/lib/auction_fun_core/services/mail/auction_context/pre_auction/auction_start_reminder_mailer.rb +35 -0
  59. data/lib/auction_fun_core/services/mail/templates/auction_context/post_auction/participant.html.erb +1 -1
  60. data/lib/auction_fun_core/services/mail/templates/auction_context/post_auction/winner.html.erb +1 -1
  61. data/lib/auction_fun_core/services/mail/templates/auction_context/pre_auction/auction_start_reminder.html.erb +192 -0
  62. data/lib/auction_fun_core/services/mail/user_context/registration_mailer.rb +6 -0
  63. data/lib/auction_fun_core/version.rb +1 -1
  64. data/lib/auction_fun_core/workers/application_job.rb +10 -0
  65. data/lib/auction_fun_core/workers/operations/auction_context/post_auction/participant_operation_job.rb +7 -2
  66. data/lib/auction_fun_core/workers/operations/auction_context/post_auction/winner_operation_job.rb +6 -2
  67. data/lib/auction_fun_core/workers/operations/auction_context/pre_auction/auction_start_reminder_operation_job.rb +44 -0
  68. data/lib/auction_fun_core/workers/operations/auction_context/processor/finish/closed_operation_job.rb +6 -3
  69. data/lib/auction_fun_core/workers/operations/auction_context/processor/finish/penny_operation_job.rb +6 -3
  70. data/lib/auction_fun_core/workers/operations/auction_context/processor/finish/standard_operation_job.rb +6 -2
  71. data/lib/auction_fun_core/workers/operations/auction_context/processor/start_operation_job.rb +6 -3
  72. data/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/participant_mailer_job.rb +12 -7
  73. data/lib/auction_fun_core/workers/services/mail/auction_context/post_auction/winner_mailer_job.rb +11 -5
  74. data/lib/auction_fun_core/workers/services/mail/auction_context/pre_auction/auction_start_reminder_mailer_job.rb +48 -0
  75. data/lib/auction_fun_core/workers/services/mail/user_context/registration_mailer_job.rb +8 -6
  76. data/system/providers/background_job.rb +6 -0
  77. metadata +10 -2
@@ -12,7 +12,21 @@ module AuctionFunCore
12
12
  include Import["repos.auction_context.auction_repository"]
13
13
  include Import["contracts.auction_context.processor.unpause_contract"]
14
14
 
15
- # @todo Add custom doc
15
+ ##
16
+ # Executes the unpause operation with the provided attributes.
17
+ #
18
+ # @param attributes [Hash] The attributes for the unpause operation.
19
+ # @option attributes auction_id [Integer] The ID of the auction.
20
+ # @yield [Dry::Matcher::Evaluator] The block to handle the result of the operation.
21
+ # @return [Dry::Matcher::Evaluator] The result of the operation.
22
+ #
23
+ # @example
24
+ # attributes = { auction_id: 123 }
25
+ #
26
+ # AuctionFunCore::Operations::AuctionContext::Processor::UnpauseOperation.call(attributes) do |result|
27
+ # result.success { |auction| puts "Unpaused auction sucessfully! #{auction.to_h}" }
28
+ # result.failure { |failure| puts "Failed to unpause auction: #{failure.errors.to_h}"}
29
+ # end
16
30
  def self.call(attributes, &block)
17
31
  operation = new.call(attributes)
18
32
 
@@ -21,6 +35,27 @@ module AuctionFunCore
21
35
  Dry::Matcher::ResultMatcher.call(operation, &block)
22
36
  end
23
37
 
38
+ ##
39
+ # Performs the unpause of an auction.
40
+ #
41
+ # @param attributes [Hash] The attributes for the unpause operation.
42
+ # @option attributes auction_id [Integer] The ID of the auction.
43
+ # @return [Dry::Monads::Result::Success, Dry::Monads::Result::Failure] The result of the operation.
44
+ #
45
+ # @example
46
+ # attributes = { auction_id: 123 }
47
+ #
48
+ # operation = AuctionFunCore::Operations::AuctionContext::Processor::UnpauseOperation.call(attributes)
49
+ #
50
+ # if operation.success?
51
+ # auction = operation.success
52
+ # puts "Unpaused auction sucessfully! #{auction.to_h}"
53
+ # end
54
+ #
55
+ # if operation.failure?
56
+ # failure = operation.failure
57
+ # puts "Failed to unpause auction: #{failure.errors.to_h}"
58
+ # end
24
59
  def call(attributes)
25
60
  attrs = yield validate(attributes)
26
61
 
@@ -40,12 +40,30 @@ module AuctionFunCore
40
40
  struct_namespace Entities
41
41
  auto_struct(true)
42
42
 
43
+ # Retrieves a paginated list of auctions along with related information.
44
+ # By default, it retrieves the first page with 10 auctions per page and includes information for the top 3 bidders.
45
+ #
46
+ # @param page [Integer] The page number to retrieve (default is 1).
47
+ # @param per_page [Integer] The number of auctions per page (default is 10).
48
+ # @param options [Hash] Additional options for customization (default is {bidders_count: 3}).
49
+ # @option options [Integer] :bidders_count The number of top bidders to include in the result (default is 3).
50
+ # @return [Array<Hash>] An array of hashes representing the auctions and related information.
51
+ # @example Retrieve the first page of auctions with 10 per page and include information for the top 3 bidders
52
+ # all_auctions = all
53
+ #
54
+ # @example Retrieve the second page of auctions with 5 per page and include information for the top 5 bidders
55
+ # all_auctions = all(2, 5, { bidders_count: 5 })
56
+ #
57
+ # @example Retrieve the third page of auctions with 15 per page and include information for the top 2 bidders
58
+ # all_auctions = all(3, 15, { bidders_count: 2 })
59
+ #
60
+ # @raise [RuntimeError] if either `page` or `per_page` argument is not an integer.
43
61
  def all(page = 1, per_page = 10, options = {bidders_count: 3})
44
62
  raise "Invalid argument" unless page.is_a?(Integer) && per_page.is_a?(Integer)
45
63
 
46
64
  offset = ((page - 1) * per_page)
47
65
 
48
- read("
66
+ sql = <<-SQL
49
67
  SELECT a.id, a.title, a.description, a.kind, a.status, a.started_at, a.finished_at, a.stopwatch, a.initial_bid_cents,
50
68
  (SELECT COUNT(*) FROM (SELECT * FROM bids WHERE bids.auction_id = a.id) dt) AS total_bids,
51
69
  CASE
@@ -69,17 +87,37 @@ module AuctionFunCore
69
87
  WHEN a.kind = 'closed' THEN
70
88
  json_build_object('minimal', (a.initial_bid_cents + (a.initial_bid_cents * 0.10))::int)
71
89
  END as bids
72
- FROM auctions as a
73
- LEFT JOIN LATERAL (SELECT * FROM bids WHERE auction_id = a.id ORDER BY value_cents DESC LIMIT #{options[:bidders_count]}) as bi ON a.id = bi.auction_id
74
- LEFT JOIN users ON bi.user_id = users.id AND bi.auction_id = a.id
75
- GROUP BY a.id
76
- LIMIT #{per_page} OFFSET #{offset}")
90
+ FROM auctions as a
91
+ LEFT JOIN LATERAL (SELECT * FROM bids WHERE auction_id = a.id ORDER BY value_cents DESC LIMIT #{options[:bidders_count]}) as bi ON a.id = bi.auction_id
92
+ LEFT JOIN users ON bi.user_id = users.id AND bi.auction_id = a.id
93
+ GROUP BY a.id
94
+ LIMIT #{per_page} OFFSET #{offset}
95
+ SQL
96
+
97
+ read(sql)
77
98
  end
78
99
 
100
+ # Retrieves detailed information about a specific auction.
101
+ #
102
+ # @param auction_id [Integer] The ID of the auction to retrieve information for.
103
+ # @param options [Hash] Additional options for customization (default is {bidders_count: 3}).
104
+ # @option options [Integer] :bidders_count The number of top bidders to include in the result (default is 3).
105
+ # @return [Hash] A hash representing the auction and related information.
106
+ #
107
+ # @example Retrieve information for auction with ID 123
108
+ # auction_info = info(123)
109
+ #
110
+ # @example Retrieve information for auction with ID 456 and include information for the top 5 bidders
111
+ # auction_info = info(456, { bidders_count: 5 })
112
+ #
113
+ # @example Retrieve information for auction with ID 789 and include information for the top 2 bidders
114
+ # auction_info = info(789, { bidders_count: 2 })
115
+ #
116
+ # @raise [RuntimeError] if `auction_id` argument is not an integer.
79
117
  def info(auction_id, options = {bidders_count: 3})
80
118
  raise "Invalid argument" unless auction_id.is_a?(Integer)
81
119
 
82
- read("
120
+ sql = <<-SQL
83
121
  SELECT a.id, a.title, a.description, a.kind, a.status, a.started_at, a.finished_at, a.stopwatch, a.initial_bid_cents,
84
122
  (SELECT COUNT(*) FROM (SELECT * FROM bids WHERE bids.auction_id = #{auction_id}) dt) AS total_bids,
85
123
  CASE
@@ -103,11 +141,14 @@ module AuctionFunCore
103
141
  WHEN a.kind = 'closed' THEN
104
142
  json_build_object('minimal', (a.initial_bid_cents + (a.initial_bid_cents * 0.10))::int)
105
143
  END as bids
106
- FROM auctions as a
107
- LEFT JOIN LATERAL (SELECT * FROM bids WHERE auction_id = a.id ORDER BY value_cents DESC LIMIT #{options[:bidders_count]}) as bi ON a.id = bi.auction_id AND a.id = #{auction_id}
108
- LEFT JOIN users ON bi.user_id = users.id AND bi.auction_id = a.id
109
- WHERE a.id = #{auction_id}
110
- GROUP BY a.id")
144
+ FROM auctions as a
145
+ LEFT JOIN LATERAL (SELECT * FROM bids WHERE auction_id = a.id ORDER BY value_cents DESC LIMIT #{options[:bidders_count]}) as bi ON a.id = bi.auction_id AND a.id = #{auction_id}
146
+ LEFT JOIN users ON bi.user_id = users.id AND bi.auction_id = a.id
147
+ WHERE a.id = #{auction_id}
148
+ GROUP BY a.id
149
+ SQL
150
+
151
+ read(sql)
111
152
  end
112
153
 
113
154
  # Retrieves the standard auction winner and other participating bidders for a specified auction.
@@ -125,22 +166,26 @@ module AuctionFunCore
125
166
  def load_standard_auction_winners_and_participants(auction_id)
126
167
  raise "Invalid argument" unless auction_id.is_a?(Integer)
127
168
 
128
- read("SELECT a.id, a.kind, a.status, w.user_id AS winner_id, COALESCE(COUNT(b.id), 0) AS total_bids,
129
- COALESCE(
130
- ARRAY_REMOVE(ARRAY_AGG(DISTINCT b.user_id ORDER BY b.user_id), w.user_id), ARRAY[]::INT[]
131
- ) AS participant_ids
132
- FROM auctions a
133
- LEFT JOIN bids b ON a.id = b.auction_id
134
- LEFT JOIN (
135
- SELECT auction_id, user_id, MAX(value_cents) AS value_cents
136
- FROM bids
137
- WHERE auction_id = #{auction_id}
138
- GROUP BY auction_id, user_id
139
- ORDER BY value_cents DESC
140
- LIMIT 1
141
- ) AS w ON a.id = w.auction_id
142
- WHERE a.id = #{auction_id}
143
- GROUP BY a.id, w.user_id")
169
+ sql = <<-SQL
170
+ SELECT a.id, a.kind, a.status, w.user_id AS winner_id, COALESCE(COUNT(b.id), 0) AS total_bids,
171
+ COALESCE(
172
+ ARRAY_REMOVE(ARRAY_AGG(DISTINCT b.user_id ORDER BY b.user_id), w.user_id), ARRAY[]::INT[]
173
+ ) AS participant_ids
174
+ FROM auctions a
175
+ LEFT JOIN bids b ON a.id = b.auction_id
176
+ LEFT JOIN (
177
+ SELECT auction_id, user_id, MAX(value_cents) AS value_cents
178
+ FROM bids
179
+ WHERE auction_id = #{auction_id}
180
+ GROUP BY auction_id, user_id
181
+ ORDER BY value_cents DESC
182
+ LIMIT 1
183
+ ) AS w ON a.id = w.auction_id
184
+ WHERE a.id = #{auction_id}
185
+ GROUP BY a.id, w.user_id
186
+ SQL
187
+
188
+ read(sql)
144
189
  end
145
190
 
146
191
  # Retrieves the penny auction winner and other participating bidders for a specified auction.
@@ -158,21 +203,25 @@ module AuctionFunCore
158
203
  def load_penny_auction_winners_and_participants(auction_id)
159
204
  raise "Invalid argument" unless auction_id.is_a?(Integer)
160
205
 
161
- read("SELECT a.id, a.kind, a.status, w.user_id AS winner_id, COALESCE(COUNT(b.id), 0) AS total_bids,
162
- COALESCE(
163
- ARRAY_REMOVE(ARRAY_AGG(DISTINCT b.user_id ORDER BY b.user_id), w.user_id), ARRAY[]::INT[]
164
- ) AS participant_ids
165
- FROM auctions a
166
- LEFT JOIN bids b ON a.id = b.auction_id
167
- LEFT JOIN (
168
- SELECT auction_id, user_id
169
- FROM bids
170
- WHERE auction_id = #{auction_id}
171
- ORDER BY bids.created_at DESC
172
- LIMIT 1
173
- ) AS w ON a.id = w.auction_id
174
- WHERE a.id = #{auction_id}
175
- GROUP BY a.id, w.user_id")
206
+ sql = <<-SQL
207
+ SELECT a.id, a.kind, a.status, w.user_id AS winner_id, COALESCE(COUNT(b.id), 0) AS total_bids,
208
+ COALESCE(
209
+ ARRAY_REMOVE(ARRAY_AGG(DISTINCT b.user_id ORDER BY b.user_id), w.user_id), ARRAY[]::INT[]
210
+ ) AS participant_ids
211
+ FROM auctions a
212
+ LEFT JOIN bids b ON a.id = b.auction_id
213
+ LEFT JOIN (
214
+ SELECT auction_id, user_id
215
+ FROM bids
216
+ WHERE auction_id = #{auction_id}
217
+ ORDER BY bids.created_at DESC
218
+ LIMIT 1
219
+ ) AS w ON a.id = w.auction_id
220
+ WHERE a.id = #{auction_id}
221
+ GROUP BY a.id, w.user_id
222
+ SQL
223
+
224
+ read(sql)
176
225
  end
177
226
 
178
227
  # Retrieves the closed auction winner and other participating bidders for a specified auction.
@@ -190,70 +239,102 @@ module AuctionFunCore
190
239
  def load_closed_auction_winners_and_participants(auction_id)
191
240
  raise "Invalid argument" unless auction_id.is_a?(Integer)
192
241
 
193
- read("SELECT a.id, a.kind, a.status, w.user_id AS winner_id, COALESCE(COUNT(b.id), 0) AS total_bids,
194
- COALESCE(
195
- ARRAY_REMOVE(ARRAY_AGG(DISTINCT b.user_id ORDER BY b.user_id), w.user_id), ARRAY[]::INT[]
196
- ) AS participant_ids
197
- FROM auctions a
198
- LEFT JOIN bids b ON a.id = b.auction_id
199
- LEFT JOIN (
200
- SELECT auction_id, user_id, MAX(value_cents) AS value_cents
201
- FROM bids
202
- WHERE auction_id = #{auction_id}
203
- GROUP BY auction_id, user_id
204
- ORDER BY value_cents DESC
205
- LIMIT 1
206
- ) AS w ON a.id = w.auction_id
207
- WHERE a.id = #{auction_id}
208
- GROUP BY a.id, w.user_id")
242
+ sql = <<-SQL
243
+ SELECT a.id, a.kind, a.status, w.user_id AS winner_id, COALESCE(COUNT(b.id), 0) AS total_bids,
244
+ COALESCE(
245
+ ARRAY_REMOVE(ARRAY_AGG(DISTINCT b.user_id ORDER BY b.user_id), w.user_id), ARRAY[]::INT[]
246
+ ) AS participant_ids
247
+ FROM auctions a
248
+ LEFT JOIN bids b ON a.id = b.auction_id
249
+ LEFT JOIN (
250
+ SELECT auction_id, user_id, MAX(value_cents) AS value_cents
251
+ FROM bids
252
+ WHERE auction_id = #{auction_id}
253
+ GROUP BY auction_id, user_id
254
+ ORDER BY value_cents DESC
255
+ LIMIT 1
256
+ ) AS w ON a.id = w.auction_id
257
+ WHERE a.id = #{auction_id}
258
+ GROUP BY a.id, w.user_id
259
+ SQL
260
+
261
+ read(sql)
209
262
  end
210
263
 
264
+ # Loads statistics for the winner of a specific auction.
265
+ #
266
+ # @param auction_id [Integer] The ID of the auction to load statistics for.
267
+ # @param winner_id [Integer] The ID of the winner to load statistics for.
268
+ # @return [Hash] A hash representing the statistics for the winner of the auction.
269
+ #
270
+ # @example Load statistics for the winner of auction with ID 123 and winner with ID 456
271
+ # winner_stats = load_winner_statistics(123, 456)
272
+ #
273
+ # @raise [RuntimeError] if either `auction_id` or `winner_id` arguments are not integers.
211
274
  def load_winner_statistics(auction_id, winner_id)
212
275
  raise "Invalid argument" unless auction_id.is_a?(Integer) && winner_id.is_a?(Integer)
213
276
 
214
- read("SELECT a.id, COUNT(b.id) AS auction_total_bids, MAX(b.value_cents) AS winner_bid,
215
- date(a.finished_at) as auction_date,
216
- (SELECT COUNT(*) FROM bids b2
217
- WHERE b2.auction_id = #{auction_id}
218
- AND b2.user_id = #{winner_id}
219
- ) AS winner_total_bids
220
- FROM auctions a
221
- LEFT JOIN bids b ON a.id = b.auction_id AND a.id = #{auction_id}
222
- LEFT JOIN users u ON u.id = b.user_id AND u.id = #{winner_id}
223
- LEFT JOIN (
224
- SELECT auction_id, user_id, MAX(value_cents) AS value_cents
225
- FROM bids
226
- WHERE auction_id = #{auction_id}
227
- GROUP BY auction_id, user_id
228
- ORDER BY value_cents DESC
229
- LIMIT 1
230
- ) AS w ON a.id = w.auction_id
231
- WHERE a.id = #{auction_id}
232
- GROUP BY a.id")
277
+ sql = <<-SQL
278
+ SELECT a.id, COUNT(b.id) AS auction_total_bids, MAX(b.value_cents) AS winner_bid,
279
+ date(a.finished_at) as auction_date,
280
+ (SELECT COUNT(*) FROM bids b2
281
+ WHERE b2.auction_id = #{auction_id}
282
+ AND b2.user_id = #{winner_id}
283
+ ) AS winner_total_bids
284
+ FROM auctions a
285
+ LEFT JOIN bids b ON a.id = b.auction_id AND a.id = #{auction_id}
286
+ LEFT JOIN users u ON u.id = b.user_id AND u.id = #{winner_id}
287
+ LEFT JOIN (
288
+ SELECT auction_id, user_id, MAX(value_cents) AS value_cents
289
+ FROM bids
290
+ WHERE auction_id = #{auction_id}
291
+ GROUP BY auction_id, user_id
292
+ ORDER BY value_cents DESC
293
+ LIMIT 1
294
+ ) AS w ON a.id = w.auction_id
295
+ WHERE a.id = #{auction_id}
296
+ GROUP BY a.id
297
+ SQL
298
+
299
+ read(sql)
233
300
  end
234
301
 
302
+ # Loads statistics for a participant in a specific auction.
303
+ #
304
+ # @param auction_id [Integer] The ID of the auction to load statistics for.
305
+ # @param participant_id [Integer] The ID of the participant to load statistics for.
306
+ # @return [Hash] A hash representing the statistics for the participant in the auction.
307
+ #
308
+ # @example Load statistics for the participant with ID 456 in auction with ID 123
309
+ # participant_stats = load_participant_statistics(123, 456)
310
+ #
311
+ # @raise [RuntimeError] if either `auction_id` or `participant_id` arguments are not integers.
235
312
  def load_participant_statistics(auction_id, participant_id)
236
313
  raise "Invalid argument" unless auction_id.is_a?(Integer) && participant_id.is_a?(Integer)
237
314
 
238
- read("SELECT a.id, COUNT(b.id) AS auction_total_bids, MAX(b.value_cents) AS winner_bid,
239
- date(a.finished_at) as auction_date,
240
- (SELECT COUNT(*) FROM bids b2
241
- WHERE b2.auction_id = #{auction_id}
242
- AND b2.user_id = #{participant_id}
243
- ) AS winner_total_bids
244
- FROM auctions a
245
- LEFT JOIN bids b ON a.id = b.auction_id AND a.id = #{auction_id}
246
- LEFT JOIN users u ON u.id = b.user_id AND u.id = #{participant_id}
247
- LEFT JOIN (
248
- SELECT auction_id, user_id, MAX(value_cents) AS value_cents
249
- FROM bids
250
- WHERE auction_id = #{auction_id}
251
- GROUP BY auction_id, user_id
252
- ORDER BY value_cents DESC
253
- LIMIT 1
254
- ) AS w ON a.id = w.auction_id
255
- WHERE a.id = #{auction_id}
256
- GROUP BY a.id")
315
+ sql = <<-SQL
316
+ SELECT a.id, COUNT(b.id) AS auction_total_bids, MAX(b.value_cents) AS winner_bid,
317
+ date(a.finished_at) as auction_date,
318
+ (SELECT COUNT(*) FROM bids b2
319
+ WHERE b2.auction_id = #{auction_id}
320
+ AND b2.user_id = #{participant_id}
321
+ ) AS winner_total_bids
322
+ FROM auctions a
323
+ LEFT JOIN bids b ON a.id = b.auction_id AND a.id = #{auction_id}
324
+ LEFT JOIN users u ON u.id = b.user_id AND u.id = #{participant_id}
325
+ LEFT JOIN (
326
+ SELECT auction_id, user_id, MAX(value_cents) AS value_cents
327
+ FROM bids
328
+ WHERE auction_id = #{auction_id}
329
+ GROUP BY auction_id, user_id
330
+ ORDER BY value_cents DESC
331
+ LIMIT 1
332
+ ) AS w ON a.id = w.auction_id
333
+ WHERE a.id = #{auction_id}
334
+ GROUP BY a.id
335
+ SQL
336
+
337
+ read(sql)
257
338
  end
258
339
  end
259
340
  end
@@ -23,6 +23,24 @@ module AuctionFunCore
23
23
 
24
24
  struct_namespace Entities
25
25
  auto_struct(true)
26
+
27
+ # Retrieves a list of unique user IDs who have placed bids in a specified auction.
28
+ # A participant in an auction is defined as a user who has placed one or more bids.
29
+ #
30
+ # @param auction_id [Integer] the ID of the auction.
31
+ # @return [Array<Integer>] Returns an array of unique user IDs who have participated in the auction.
32
+ # @raise [RuntimeError] Raises an error if the auction_id is not an integer.
33
+ def participants(auction_id)
34
+ raise "Invalid argument" unless auction_id.is_a?(Integer)
35
+
36
+ sql = <<-SQL
37
+ SELECT COALESCE(ARRAY_AGG(DISTINCT user_id), ARRAY[]::INT[]) AS participant_ids
38
+ FROM bids
39
+ WHERE auction_id = #{auction_id}
40
+ SQL
41
+
42
+ read(sql)
43
+ end
26
44
  end
27
45
  end
28
46
  end
@@ -3,7 +3,30 @@
3
3
  module AuctionFunCore
4
4
  module Repos
5
5
  module AuctionContext
6
- # SQL repository for auctions.
6
+ # Repository for handling repository operations related to auctions.
7
+ #
8
+ # This repository provides methods to interact with auction data in the database,
9
+ # including creating, updating, deleting, and retrieving auctions.
10
+ #
11
+ # @example
12
+ # auction_repo = AuctionFunCore::Repos::AuctionContext::AuctionRepository.new
13
+ #
14
+ # # Retrieve all auctions
15
+ # all_auctions = auction_repo.all
16
+ #
17
+ # # Get the total number of auctions
18
+ # total_auctions = auction_repo.count
19
+ #
20
+ # # Find an auction by its ID
21
+ # auction = auction_repo.by_id(123)
22
+ #
23
+ # # Find an auction by its ID and raise an error if not found
24
+ # auction = auction_repo.by_id!(123)
25
+ #
26
+ # @see AuctionFunCore::Entities::Auction Struct representing auction data
27
+ # @see https://rom-rb.org/learn/sql/3.3/queries/
28
+ # @see https://api.rom-rb.org/rom-sql/ROM/SQL/Relation/Reading
29
+ #
7
30
  class AuctionRepository < ROM::Repository[:auctions]
8
31
  include Import["container"]
9
32
 
@@ -11,28 +34,34 @@ module AuctionFunCore
11
34
  commands :create, update: :by_pk, delete: :by_pk
12
35
 
13
36
  # Returns all auctions in the database.
14
- # @return [Array<ROM::Struct::Auction>, []]
37
+ # @return [Array<ROM::Struct::Auction>]
15
38
  def all
16
39
  auctions.to_a
17
40
  end
18
41
 
19
- # Returns the total number of auctions in database.
20
- # @return [Integer]
42
+ # Returns the total number of auctions in the database.
43
+ #
44
+ # @return [Integer] Total number of auctions.
45
+ #
21
46
  def count
22
47
  auctions.count
23
48
  end
24
49
 
25
- # Search auction in database by primary key.
26
- # @param id [Integer] Auction ID
27
- # @return [ROM::Struct::Auction, nil]
50
+ # Retrieves an auction from the database by its primary key.
51
+ #
52
+ # @param id [Integer] The ID of the auction to retrieve.
53
+ # @return [ROM::Struct::Auction, nil] The retrieved auction, or nil if not found.
54
+ #
28
55
  def by_id(id)
29
56
  auctions.by_pk(id).one
30
57
  end
31
58
 
32
- # Search auction in database by primary key.
33
- # @param id [Integer] Auction ID
34
- # @raise [ROM::TupleCountMismatchError] if not found on database
35
- # @return [ROM::Struct::Auction]
59
+ # Retrieves an auction from the database by its primary key, raising an error if not found.
60
+ #
61
+ # @param id [Integer] The ID of the auction to retrieve.
62
+ # @raise [ROM::TupleCountMismatchError] if the auction is not found.
63
+ # @return [ROM::Struct::Auction] The retrieved auction.
64
+ #
36
65
  def by_id!(id)
37
66
  auctions.by_pk(id).one!
38
67
  end
@@ -3,21 +3,43 @@
3
3
  module AuctionFunCore
4
4
  module Repos
5
5
  module BidContext
6
- # SQL repository for bids.
6
+ # Repository for handling repository operations related to bids.
7
+ #
8
+ # This repository provides methods to interact with bid data in the database,
9
+ # including creating, updating, deleting, and retrieving bids.
10
+ #
11
+ # @example
12
+ # bid_repo = AuctionFunCore::Repos::BidContext::BidRepository.new
13
+ #
14
+ # # Get the total number of bids
15
+ # total_bids = bid_repo.count
16
+ #
17
+ # # Checks if a bid exists based on the provided conditions.
18
+ # bid_repo.exists?(id: 123)
19
+ #
20
+ # @see AuctionFunCore::Entities::Bid Struct representing bid data
21
+ # @see https://rom-rb.org/learn/sql/3.3/queries/
22
+ # @see https://api.rom-rb.org/rom-sql/ROM/SQL/Relation/Reading
23
+ #
7
24
  class BidRepository < ROM::Repository[:bids]
8
25
  include Import["container"]
9
26
 
10
27
  struct_namespace Entities
11
28
  commands :create, update: :by_pk, delete: :by_pk
12
29
 
13
- # Returns the total number of bids in database.
14
- # @return [Integer]
30
+ # Returns the total number of bids in the database.
31
+ #
32
+ # @return [Integer] Total number of bids.
33
+ #
15
34
  def count
16
35
  bids.count
17
36
  end
18
37
 
19
- # @param conditions [Hash] DSL Dataset
20
- # @return [Boolean]
38
+ # Checks if a bid exists based on the provided conditions.
39
+ #
40
+ # @param conditions [Hash] The conditions to check (DSL Dataset).
41
+ # @return [Boolean] true if a bid exists that matches the conditions, otherwise false.
42
+ #
21
43
  def exists?(conditions)
22
44
  bids.exist?(conditions)
23
45
  end