Class: ApiMaker::CollectionLoader

Inherits:
ApplicationService show all
Defined in:
app/services/api_maker/collection_loader.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from ApplicationService

#api_maker_json

Constructor Details

#initialize(ability:, api_maker_args:, collection:, locals: nil, params: {}) ⇒ CollectionLoader

Returns a new instance of CollectionLoader.



4
5
6
7
8
9
10
# File 'app/services/api_maker/collection_loader.rb', line 4

def initialize(ability:, api_maker_args:, collection:, locals: nil, params: {})
  @ability = ability
  @api_maker_args = api_maker_args
  @collection = collection
  @locals = locals || api_maker_args&.dig(:locals) || {}
  @params = params
end

Instance Attribute Details

#abilityObject (readonly)

Returns the value of attribute ability.



2
3
4
# File 'app/services/api_maker/collection_loader.rb', line 2

def ability
  @ability
end

#api_maker_argsObject (readonly)

Returns the value of attribute api_maker_args.



2
3
4
# File 'app/services/api_maker/collection_loader.rb', line 2

def api_maker_args
  @api_maker_args
end

#collectionObject (readonly)

Returns the value of attribute collection.



2
3
4
# File 'app/services/api_maker/collection_loader.rb', line 2

def collection
  @collection
end

#localsObject (readonly)

Returns the value of attribute locals.



2
3
4
# File 'app/services/api_maker/collection_loader.rb', line 2

def locals
  @locals
end

#paramsObject (readonly)

Returns the value of attribute params.



2
3
4
# File 'app/services/api_maker/collection_loader.rb', line 2

def params
  @params
end

Instance Method Details

#collection_from_query(collection) ⇒ Object



35
36
37
38
39
40
41
42
43
# File 'app/services/api_maker/collection_loader.rb', line 35

def collection_from_query(collection)
  ApiMaker::CollectionSerializer.new(
    ability: ability,
    api_maker_args: api_maker_args,
    collection: collection,
    locals: locals,
    query_params: params
  ).result
end

#distinct_queryObject



45
46
47
# File 'app/services/api_maker/collection_loader.rb', line 45

def distinct_query
  @query = @query.distinct if params[:distinct]
end

#filter_custom_accessible_by(collection) ⇒ Object



29
30
31
32
33
# File 'app/services/api_maker/collection_loader.rb', line 29

def filter_custom_accessible_by(collection)
  return collection if params[:accessible_by].blank?

  collection.accessible_by(ability, params[:accessible_by].to_sym)
end

#group_queryObject



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'app/services/api_maker/collection_loader.rb', line 49

def group_query
  return if params[:group_by].blank?

  params[:group_by].each do |group_by|
    if group_by.is_a?(Array)
      raise "Expected table and column but array length was wrong: #{group_by.length}" unless group_by.length == 2

      resource_class = group_by[0]
      column_name = group_by[1]
      model_class = resource_class.model_class
      raise "Not a valid column name: #{column_name}" unless model_class.column_names.include?(column_name)

      arel_column = model_class.arel_table[column_name]
    else
      arel_column = collection.klass.arel_table[group_by]
      raise "Not a valid column name: #{group_by}" unless collection.klass.column_names.include?(group_by)
    end

    @query = @query.group(arel_column)
  end
end

#include_pagination_data(response, collection) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'app/services/api_maker/collection_loader.rb', line 75

def include_pagination_data(response, collection)
  return if params[:page].blank?

  countable_collection = collection.except(:distinct).except(:group).except(:select).except(:order)

  Rails.logger.debug { "API maker: CollectionLoader total pages for #{model_class.name}" }
  total_pages = countable_collection.total_pages

  Rails.logger.debug { "API maker: CollectionLoader total count for #{model_class.name}" }
  total_count = countable_collection.try(:total_count) || countable_collection.total_entries

  response[:meta] = {
    currentPage: collection.current_page,
    perPage: collection.try(:per_page) || collection.limit_value,
    totalCount: total_count,
    totalPages: total_pages
  }
end

#limit_queryObject



71
72
73
# File 'app/services/api_maker/collection_loader.rb', line 71

def limit_query
  @query = @query.limit(params[:limit]) if params[:limit].present?
end

#manage_through_relationshipObject



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'app/services/api_maker/collection_loader.rb', line 94

def manage_through_relationship
  return if params[:through].blank?

  through_model_class = params[:through][:model].safe_constantize
  through_model = through_model_class.accessible_by(ability).find_by(through_model_class.primary_key => params[:through][:id])

  return if through_model.nil?

  reflection = through_model_class.reflections.fetch(params[:through][:reflection])
  association = ActiveRecord::Associations::Association.new(through_model, reflection)

  query_through = association.scope
  query_through = query_through.accessible_by(ability)

  filter_custom_accessible_by(query_through)
end

#model_classObject



111
112
113
# File 'app/services/api_maker/collection_loader.rb', line 111

def model_class
  @model_class ||= collection.klass
end

#performObject



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'app/services/api_maker/collection_loader.rb', line 12

def perform
  set_query

  if params[:count]
    count = @query.count
    count = count.length if count.is_a?(Hash)

    succeed!(count: count)
  else
    collection = collection_from_query(@query)
    response = collection.as_json
    include_pagination_data(response, @query)

    succeed!(response)
  end
end

#set_queryObject



115
116
117
118
119
120
121
122
123
124
# File 'app/services/api_maker/collection_loader.rb', line 115

def set_query
  @query = manage_through_relationship || collection
  group_query
  distinct_query
  @query = @query.ransack(params[:q]).result
  limit_query
  @query = @query.page(params[:page]) if params[:page].present?
  @query = @query.per_page(params[:per]) if params[:per].present?
  @query = filter_custom_accessible_by(@query)
end