af83/chouette-core

View on GitHub
app/graphql/lazy_loading/lines.rb

Summary

Maintainability
A
2 hrs
Test Coverage
module LazyLoading
  class Lines
    def initialize(query_ctx, stop_area_id)
      @stop_area_id = stop_area_id
      # Initialize the loading state for this query or get the previously-initiated state
      @lazy_state = query_ctx[:lazy_find_liness] ||= {
        pending_ids: Set.new,
        loaded_ids: {},
      }
      # Register this ID to be loaded later:
      @lazy_state[:pending_ids] << stop_area_id
    end

    # Return the loaded record, hitting the database if needed
    def lines
      # Check if the record was already loaded:
      loaded_records = @lazy_state[:loaded_ids][@stop_area_id]
      if loaded_records
        # The pending IDs were already loaded so return the result of that previous load
        loaded_records
      else
        # The record hasn't been loaded yet, so hit the database with all pending IDs
        pending_ids = @lazy_state[:pending_ids].to_a
        lines = Chouette::Line.joins(:routes => [:stop_points => :stop_area])
          .where(:stop_areas => {:id => pending_ids})
          .select('lines.*', 'stop_areas.id as stop_area_id')

        # Fill and clean the map
        lines.each do |line|
          @lazy_state[:loaded_ids][line.stop_area_id] ||= []
          @lazy_state[:loaded_ids][line.stop_area_id] << line
        end
        @lazy_state[:pending_ids].clear
        @lazy_state[:loaded_ids].transform_values! { |v| v.uniq } # The request returns the same stop multiple times

        # Now, get the matching lines from the loaded result:
        @lazy_state[:loaded_ids][@stop_area_id]
      end
    end
  end
end