auction_fun_core 0.8.7 → 0.8.9

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.
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