Created
November 27, 2020 13:50
-
-
Save tbilous/677b78b513cc028a19062fc56fe6df82 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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