Files
redux-scraper/app/models/telegram_bot_log.rb
2025-08-05 05:05:21 +00:00

92 lines
2.8 KiB
Ruby

# typed: strict
class TelegramBotLog < ReduxApplicationRecord
self.table_name = "telegram_bot_logs"
# Association to processed image blob
belongs_to :processed_image,
foreign_key: :processed_image_sha256,
class_name: "::BlobFile",
optional: true
# Status enum for tracking request outcomes
enum :status,
{
success: "success",
error: "error",
no_results: "no_results",
invalid_image: "invalid_image",
},
prefix: true
# Validations
validates :telegram_user_id, presence: true
validates :telegram_chat_id, presence: true
validates :request_timestamp, presence: true
validates :status, presence: true
validates :search_results_count,
presence: true,
numericality: {
greater_than_or_equal_to: 0,
}
validates :download_time, numericality: { greater_than: 0 }, allow_nil: true
validates :image_processing_time,
numericality: {
greater_than: 0,
},
allow_nil: true
validates :fingerprint_computation_time,
numericality: {
greater_than: 0,
},
allow_nil: true
validates :search_computation_time,
numericality: {
greater_than: 0,
},
allow_nil: true
validates :total_request_time,
numericality: {
greater_than: 0,
},
allow_nil: true
validates :processed_image_sha256, length: { is: 32 }, allow_nil: true
# Scopes for common queries
scope :for_user,
->(telegram_user_id) { where(telegram_user_id: telegram_user_id) }
scope :successful, -> { where(status: :success) }
scope :with_results, -> { where("search_results_count > 0") }
scope :recent, -> { order(request_timestamp: :desc) }
scope :by_date_range,
->(start_date, end_date) do
where(request_timestamp: start_date..end_date)
end
# Helper methods
sig { returns(String) }
def user_display_name
if telegram_first_name.present? && telegram_last_name.present?
"#{telegram_first_name} #{telegram_last_name}"
elsif telegram_first_name.present?
T.must(telegram_first_name)
elsif telegram_username.present?
"@#{telegram_username}"
else
"User #{telegram_user_id}"
end
end
sig { returns(T::Boolean) }
def has_performance_metrics?
download_time.present? && fingerprint_computation_time.present? &&
search_computation_time.present? && total_request_time.present?
end
sig { returns(T::Boolean) }
def has_complete_performance_metrics?
download_time.present? && image_processing_time.present? &&
fingerprint_computation_time.present? &&
search_computation_time.present? && total_request_time.present?
end
end