Skip to content

Instantly share code, notes, and snippets.

@tbilous
Created November 27, 2020 13:50
Show Gist options
  • Select an option

  • Save tbilous/677b78b513cc028a19062fc56fe6df82 to your computer and use it in GitHub Desktop.

Select an option

Save tbilous/677b78b513cc028a19062fc56fe6df82 to your computer and use it in GitHub Desktop.
module Streaks
class Drives
MINIMUM_RATING_FOR_STREAK = 5
ACTIVE_STREAK_MINIMUM_AMOUNT = 3
def initialize user
@user = user
end
def calculate
streaks = ['star_rating_turn', 'star_rating_brake', 'star_rating_accel', 'star_rating_speeding', 'star_rating_phone_motion'].map do |field|
best_streak = highest_streak(@user.id, field, ">=", MINIMUM_RATING_FOR_STREAK)
current_streak = current_streak(@user, field, ">=", MINIMUM_RATING_FOR_STREAK)
is_active = current_streak >= ACTIVE_STREAK_MINIMUM_AMOUNT
{
title: field,
best_streak: best_streak,
current_streak: current_streak,
is_active: is_active,
icon_name: get_icon_name(field, is_active)
}
end
streaks.sort_by{|s| [s[:current_streak], s[:best_streak]]}.reverse
end
private
def highest_streak user_id, field, condition, amount
sql = "SELECT count(*) AS seq_len
FROM (
SELECT row_number() OVER (ORDER BY end_time) - d2.row_number AS grp
FROM drives d1
JOIN (
SELECT id, row_number() OVER (ORDER BY end_time)
FROM drives
WHERE user_id = #{user_id}
AND driving = true
AND counted = true
) d2
ON d1.id = d2.id
WHERE d1.#{field} #{condition} #{amount}
AND d1.user_id = #{user_id}
AND driving = true
AND counted = true
) d3
GROUP BY grp
ORDER BY seq_len DESC
LIMIT 1;"
ActiveRecord::Base.connection.execute(sql).values.flatten[0] || 0
end
def current_streak user, field, condition, amount
if (last_failed_end_time = user.drives.user_drove.order(:end_time).where("#{field} #{opposite_method(condition)} #{amount}").last.try(:end_time))
user.drives.user_drove.order(:end_time).where("#{field} #{condition} #{amount} AND end_time >= ?", last_failed_end_time).count
else
user.drives.user_drove.order(:end_time).where("#{field} #{condition} #{amount}").count
end
end
def get_icon_name type, is_active
case type
when 'star_rating_turn'
return "streaks/cornering#{is_active ? '' : 'Inactive'}.png"
when 'star_rating_brake'
return "streaks/braking#{is_active ? '' : 'Inactive'}.png"
when 'star_rating_accel'
return "streaks/acceleration#{is_active ? '' : 'Inactive'}.png"
when 'star_rating_speeding'
return "streaks/speeding#{is_active ? '' : 'Inactive'}.png"
when 'star_rating_phone_motion'
return "streaks/phone#{is_active ? '' : 'Inactive'}.png"
end
end
def opposite_method method
case method
when "<"
return ">="
when "<="
return ">"
when ">="
return "<"
when ">"
return "<="
else
raise "Not a supported method"
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment