diff --git a/app/jobs/active_auctions_ai_sorting_job.rb b/app/jobs/active_auctions_ai_sorting_job.rb index fa92134bc..ac2c859c2 100644 --- a/app/jobs/active_auctions_ai_sorting_job.rb +++ b/app/jobs/active_auctions_ai_sorting_job.rb @@ -4,7 +4,7 @@ class ActiveAuctionsAiSortingJob < ApplicationJob def perform return unless self.class.needs_to_run? - auctions_list = Auction.active + auctions_list = Auction.active_with_offers_count ai_response = fetch_ai_response(auctions_list) process_ai_response(ai_response) rescue OpenAI::Error => e @@ -51,12 +51,24 @@ def chat_parameters(auctions_list) model: model, messages: [ { role: 'system', content: system_message }, - { role: 'user', content: auctions_list.pluck(:id, :domain_name).to_s }, + { role: 'user', content: format(auctions_list) }, { role: 'user', content: 'Response in JSON format: [{id:, domain_name:, ai_score:}]' } ] } end + def format(auctions_list) + auctions_list.map do |a| + sliced = a.attributes.slice('id', 'domain_name') + if a.platform != 'english' + sliced.merge!({ last_offer: 0, offers_count: 0 }) + else + sliced.merge!({ last_offer: a.cents, offers_count: a.offers_count }) + end + sliced + end.to_json + end + def update_auctions_with_ai_scores(ai_scores) update_values = ai_scores.map { |score| "WHEN #{score[:id]} THEN #{score[:ai_score]}" }.join(' ') update_ids = ai_scores.pluck(:id).join(',') diff --git a/app/models/auction.rb b/app/models/auction.rb index b9cbd08fc..fc20babdc 100644 --- a/app/models/auction.rb +++ b/app/models/auction.rb @@ -1,6 +1,6 @@ -# rubocop:disable Metrics -class Auction < ApplicationRecord +class Auction < ApplicationRecord # rubocop:disable Metrics include Presentable + include SqlQueriable include Searchable include PgSearch::Model @@ -227,58 +227,4 @@ def users_price def maximum_bids Money.new(offers.maximum(:cents), Setting.find_by(code: 'auction_currency').retrieve) end - - def self.with_user_offers(user_id) - Auction.from(with_user_offers_query(user_id)) - end - - def self.with_user_offers_query(user_id) - sql = <<~SQL - (WITH offers_subquery AS ( - SELECT * - FROM offers - WHERE user_id = ? - ) - SELECT DISTINCT - auctions.*, - offers_subquery.cents AS users_offer_cents, - offers_subquery.id AS users_offer_id, - offers_subquery.uuid AS users_offer_uuid - FROM auctions - LEFT JOIN offers_subquery on auctions.id = offers_subquery.auction_id) AS auctions - SQL - - ActiveRecord::Base.sanitize_sql([sql, user_id]) - end - - def self.with_highest_offers - Auction.from(with_highest_offers_query) - end - - def self.with_highest_offers_query - sql = <<~SQL - (WITH offers_subquery AS ( - SELECT DISTINCT on (uuid) offers.* - FROM (SELECT auction_id, - max(cents) over (PARTITION BY auction_id) as max_price, - min(created_at) over (PARTITION BY auction_id, cents) as min_time - FROM offers - ) AS highest_offers - INNER JOIN offers - ON - offers.cents = highest_offers.max_price AND - offers.created_at = highest_offers.min_time AND - offers.auction_id = highest_offers.auction_id) - SELECT DISTINCT - auctions.*, - offers_subquery.cents AS highest_offer_cents, - offers_subquery.id AS highest_offer_id, - offers_subquery.uuid AS highest_offer_uuid, - (SELECT COUNT(*) FROM offers where offers.auction_id = auctions.id) AS number_of_offers - FROM auctions - LEFT JOIN offers_subquery on auctions.id = offers_subquery.auction_id) AS auctions - SQL - - sql - end end diff --git a/app/models/auction/searchable.rb b/app/models/concerns/auction/searchable.rb similarity index 72% rename from app/models/auction/searchable.rb rename to app/models/concerns/auction/searchable.rb index b3b0a278f..4d1f8262a 100644 --- a/app/models/auction/searchable.rb +++ b/app/models/concerns/auction/searchable.rb @@ -1,9 +1,10 @@ -# rubocop:disable Metrics +# frozen_string_literal: true + module Auction::Searchable extend ActiveSupport::Concern - BLIND = '0'.freeze - ENGLISH = '1'.freeze + BLIND = '0' + ENGLISH = '1' included do scope :active, -> { where('starts_at <= ? AND ends_at >= ?', Time.now.utc, Time.now.utc) } @@ -99,49 +100,5 @@ def search(params = {}, current_user = nil) query.order("#{is_from_admin ? sort_admin_column : sort_column} #{sort_direction} NULLS LAST") end end - - def with_max_offer_cents_for_english_auction(user = nil) - if user - joins(<<-SQL - LEFT JOIN ( - SELECT auction_id, MAX(cents) AS max_offer_cents - FROM offers - WHERE auction_id IN ( - SELECT id FROM auctions WHERE platform = 1 - UNION - SELECT auction_id FROM offers WHERE user_id = #{user.id} AND auction_id IN (SELECT id FROM auctions WHERE platform IS NULL OR platform = 0) - ) - GROUP BY auction_id - ) AS offers_subquery ON auctions.id = offers_subquery.auction_id - SQL - ) - else - joins(<<-SQL - LEFT JOIN ( - SELECT auction_id, MAX(cents) AS max_offer_cents - FROM offers - WHERE auction_id IN (SELECT id FROM auctions WHERE platform = 1) - GROUP BY auction_id - ) AS offers_subquery ON auctions.id = offers_subquery.auction_id - SQL - ) - end - end - - def sorted_by_winning_offer_username - joins(<<-SQL - LEFT JOIN ( - SELECT offers.auction_id, offers.username - FROM offers - WHERE offers.cents = ( - SELECT MAX(offers_inner.cents) - FROM offers AS offers_inner - WHERE offers_inner.auction_id = offers.auction_id - ) - GROUP BY offers.auction_id, offers.username - ) AS offers_subquery ON auctions.id = offers_subquery.auction_id - SQL - ) - end end end diff --git a/app/models/concerns/auction/sql_queriable.rb b/app/models/concerns/auction/sql_queriable.rb new file mode 100644 index 000000000..63c049eb3 --- /dev/null +++ b/app/models/concerns/auction/sql_queriable.rb @@ -0,0 +1,125 @@ +# frozen_string_literal: true + +module Auction::SqlQueriable # rubocop:disable Metrics/ModuleLength + extend ActiveSupport::Concern + + class_methods do + def with_user_offers(user_id) + Auction.from(with_user_offers_query(user_id)) + end + + def with_user_offers_query(user_id) + sql = <<~SQL + (WITH offers_subquery AS ( + SELECT * + FROM offers + WHERE user_id = ? + ) + SELECT DISTINCT + auctions.*, + offers_subquery.cents AS users_offer_cents, + offers_subquery.id AS users_offer_id, + offers_subquery.uuid AS users_offer_uuid + FROM auctions + LEFT JOIN offers_subquery on auctions.id = offers_subquery.auction_id) AS auctions + SQL + + ActiveRecord::Base.sanitize_sql([sql, user_id]) + end + + def with_highest_offers + Auction.from(with_highest_offers_query) + end + + def with_highest_offers_query + <<~SQL + (WITH offers_subquery AS ( + SELECT DISTINCT on (uuid) offers.* + FROM (SELECT auction_id, + max(cents) over (PARTITION BY auction_id) as max_price, + min(created_at) over (PARTITION BY auction_id, cents) as min_time + FROM offers + ) AS highest_offers + INNER JOIN offers + ON + offers.cents = highest_offers.max_price AND + offers.created_at = highest_offers.min_time AND + offers.auction_id = highest_offers.auction_id) + SELECT DISTINCT + auctions.*, + offers_subquery.cents AS highest_offer_cents, + offers_subquery.id AS highest_offer_id, + offers_subquery.uuid AS highest_offer_uuid, + (SELECT COUNT(*) FROM offers where offers.auction_id = auctions.id) AS number_of_offers + FROM auctions + LEFT JOIN offers_subquery on auctions.id = offers_subquery.auction_id) AS auctions + SQL + end + + def active_with_offers_count + Auction.active.from(with_offers_count_query) + end + + def with_offers_count_query + <<~SQL + (SELECT + auctions.*, + offers.cents, + recent_offers.offers_count + FROM auctions + LEFT JOIN ( + SELECT auction_id, + MAX(updated_at) as last_updated_at, + COUNT(*) as offers_count + FROM offers + GROUP BY auction_id + ) AS recent_offers ON auctions.id = recent_offers.auction_id + LEFT JOIN offers ON auctions.id = offers.auction_id AND offers.updated_at = recent_offers.last_updated_at) AS auctions + SQL + end + + def with_max_offer_cents_for_english_auction(user = nil) + if user + joins(<<-SQL + LEFT JOIN ( + SELECT auction_id, MAX(cents) AS max_offer_cents + FROM offers + WHERE auction_id IN ( + SELECT id FROM auctions WHERE platform = 1 + UNION + SELECT auction_id FROM offers WHERE user_id = #{user.id} AND auction_id IN (SELECT id FROM auctions WHERE platform IS NULL OR platform = 0) + ) + GROUP BY auction_id + ) AS offers_subquery ON auctions.id = offers_subquery.auction_id + SQL + ) + else + joins(<<-SQL + LEFT JOIN ( + SELECT auction_id, MAX(cents) AS max_offer_cents + FROM offers + WHERE auction_id IN (SELECT id FROM auctions WHERE platform = 1) + GROUP BY auction_id + ) AS offers_subquery ON auctions.id = offers_subquery.auction_id + SQL + ) + end + end + + def sorted_by_winning_offer_username + joins(<<-SQL + LEFT JOIN ( + SELECT offers.auction_id, offers.username + FROM offers + WHERE offers.cents = ( + SELECT MAX(offers_inner.cents) + FROM offers AS offers_inner + WHERE offers_inner.auction_id = offers.auction_id + ) + GROUP BY offers.auction_id, offers.username + ) AS offers_subquery ON auctions.id = offers_subquery.auction_id + SQL + ) + end + end +end diff --git a/app/views/auctions/_auction.html.erb b/app/views/auctions/_auction.html.erb index da47b39a7..de914cc42 100644 --- a/app/views/auctions/_auction.html.erb +++ b/app/views/auctions/_auction.html.erb @@ -17,7 +17,7 @@ <% if auction.platform == 'blind' || auction.platform.nil? %> <%= t('auctions.your_current_price') %>: <%= number_with_precision(auction.users_price, precision: 2, separator: ",") %> <% else %> - <%= t('auctions.your_current_price') %>: + <%= t('auctions.current_price') %>: <%= number_with_precision(english_auction_presenter.maximum_bids, precision: 2, separator: ",") %> <% end %>