Class: ApiMaker::SelectColumnsOnCollection

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from ApplicationService

#api_maker_json

Constructor Details

#initialize(collection:, model_class: nil, select_attributes:, select_columns:, table_name: nil) ⇒ SelectColumnsOnCollection

Returns a new instance of SelectColumnsOnCollection.



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

def initialize(collection:, model_class: nil, select_attributes:, select_columns:, table_name: nil)
  raise "No collection was given" unless collection

  @collection = collection
  @model_class = model_class || collection.model
  @select_attributes = select_attributes&.dig(@model_class)
  @select_columns = select_columns
  @table_name = table_name || @model_class.table_name
end

Instance Attribute Details

#collectionObject (readonly)

Returns the value of attribute collection.



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

def collection
  @collection
end

#model_classObject (readonly)

Returns the value of attribute model_class.



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

def model_class
  @model_class
end

#select_attributesObject (readonly)

Returns the value of attribute select_attributes.



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

def select_attributes
  @select_attributes
end

#select_columnsObject (readonly)

Returns the value of attribute select_columns.



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

def select_columns
  @select_columns
end

#table_nameObject (readonly)

Returns the value of attribute table_name.



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

def table_name
  @table_name
end

Instance Method Details

#all_columns_to_selectObject

Selected attributes might require columns to be selected which is automatically resolved here



33
34
35
36
37
38
39
40
41
42
# File 'app/services/api_maker/select_columns_on_collection.rb', line 33

def all_columns_to_select
  required_columns = []

  select_attributes&.each_value do |attribute_args|
    requires_columns = attribute_args.dig(:args, :requires_columns)
    required_columns += requires_columns if requires_columns
  end

  (selected_columns + required_columns).map(&:to_s).uniq
end

#param_nameObject



44
45
46
# File 'app/services/api_maker/select_columns_on_collection.rb', line 44

def param_name
  @param_name ||= model_class.model_name.param_key
end

#performObject



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'app/services/api_maker/select_columns_on_collection.rb', line 14

def perform
  new_collection = collection
  return succeed! new_collection if new_collection.is_a?(Array)

  arel_table = Arel::Table.new(@table_name)

  if selected_columns
    all_columns_to_select.each do |column_name|
      validate_column_name!(column_name)
      new_collection = new_collection.select(arel_table[column_name])
    end
  else
    new_collection = prepend_table_wildcard(new_collection) unless table_wildcard_prepended?(new_collection)
  end

  succeed! new_collection
end

#prepend_table_wildcard(query) ⇒ Object

Prepends ‘table_name.*’ to the query. It needs to be pre-pended in case a ‘COUNT` or another aggregate function has been added to work with `DISTINCT`.



49
50
51
52
53
54
55
56
57
58
59
60
# File 'app/services/api_maker/select_columns_on_collection.rb', line 49

def prepend_table_wildcard(query)
  old_select = query.values[:select] || []
  old_select = old_select.keep_if { |select_statement| select_statement != select_table_wildcard_sql }

  query = query.except(:select).select(select_table_wildcard_sql)

  old_select.each do |select_statement|
    query = query.select(select_statement)
  end

  query
end

#select_table_wildcard_sqlObject



66
67
68
# File 'app/services/api_maker/select_columns_on_collection.rb', line 66

def select_table_wildcard_sql
  @select_table_wildcard_sql ||= "#{table_name}.*"
end

#selected_columnsObject



62
63
64
# File 'app/services/api_maker/select_columns_on_collection.rb', line 62

def selected_columns
  @selected_columns ||= select_columns&.dig(param_name)
end

#table_wildcard_prepended?(query) ⇒ Boolean

Returns:

  • (Boolean)


70
71
72
# File 'app/services/api_maker/select_columns_on_collection.rb', line 70

def table_wildcard_prepended?(query)
  query.values[:select]&.first == select_table_wildcard_sql
end

#validate_column_name!(column_name) ⇒ Object

Checks that the given column exists to avoid injections



75
76
77
# File 'app/services/api_maker/select_columns_on_collection.rb', line 75

def validate_column_name!(column_name)
  raise "Invalid column on #{model_class.name}: #{column_name}" unless model_class.columns_hash.key?(column_name.to_s)
end