HabitatMap/AirCasting

View on GitHub
app/services/api/to_active_sessions_json.rb

Summary

Maintainability
A
1 hr
Test Coverage
class Api::ToActiveSessionsJson
  def initialize(form:)
    @form = form
  end

  def call
    return Failure.new(form.errors) if form.invalid?
    result = data[:is_indoor] ? build_json_output(true) : build_json_output
    Success.new(result)
  end

  private

  attr_reader :form

  def data
    # dry-struct allows for missing key using `meta(omittable: true)`
    # This `form` has such a key named `is_indoor`. Unfortunately, when
    # `is_indoor` in `nil` if accessed with `form.to_h[:is_indoor]`, the
    # library raises. The solutions are:
    #   - Using `form.is_indoor`; this in not viable at the moment cause
    #     the code that is accessing the struct (Session.filter_) is used
    #     by other callers that are passing a vanilla Ruby hash.
    #   - Passing a vanilla Ruby hash with `form.to_h.to_h`
    form.to_h.to_h
  end

  # this was changed from a mysql query to active record to work with postgres, but it might perform worse
  # this should be tested in terms of performance and actual queries generated vs. old mysql implementation
  def build_json_output(anonymous = false)
    sessions = formatted_sessions
    streams = Stream.where(session_id: sessions.pluck('sessions.id'))
    selected_sensor_streams =
      streams.select do |stream|
        Sensor.sensor_name(data[:sensor_name]).include? stream.sensor_name
                                       .downcase
      end

    sessions_array =
      sessions.map do |session|
        related_stream =
          selected_sensor_streams.find do |stream|
            stream.session_id == session.id
          end
        last_average_value =
          StreamDailyAveragesRepository.new.last_average_value(
            related_stream.id,
          )

      {
        'id' => session.id,
        'uuid' => session.uuid,
        'end_time_local' => session.end_time_local.strftime('%Y-%m-%dT%H:%M:%S.%LZ'),
        'start_time_local' => session.start_time_local.strftime('%Y-%m-%dT%H:%M:%S.%LZ'),
        'last_measurement_value' => related_stream&.average_value&.round,
        'is_indoor' => session.is_indoor,
        'latitude' => session.latitude,
        'longitude' => session.longitude,
        'title' => session.title,
        'username' => anonymous ? 'anonymous' : session.user.username,
        'is_active' => session.is_active,
        'streams' => {
          related_stream.sensor_name => {
            'measurement_short_type' => related_stream.measurement_short_type,
            'sensor_name' => related_stream.sensor_name,
            'unit_symbol' => related_stream.unit_symbol,
            'id' => related_stream.id,
            'stream_daily_average' => last_average_value&.round || 'no data',
          }
        }
      }
      end

    {
      'fetchableSessionsCount' => sessions.length,
      'sessions' => sessions_array,
    }
  end

  def formatted_sessions
    sessions.select(
      [
        'sessions.id',
        'sessions.uuid',
        'sessions.title',
        'sessions.start_time_local',
        'sessions.end_time_local',
        '(SELECT average_value FROM streams WHERE streams.session_id = sessions.id LIMIT 1)',
        'sessions.is_indoor',
        'sessions.latitude',
        'sessions.longitude',
        'users.username',
        'sessions.user_id',
        'sessions.last_measurement_at',
      ],
    )
  end

  def sessions
    @sessions ||= FixedSession.active.filter_(data)
  end
end