Class: ParamsReady::Pagination::CursorBuilder::Cursor

Inherits:
Object
  • Object
show all
Defined in:
lib/params_ready/pagination/cursor.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(select_list, arel_table, context) ⇒ Cursor

Returns a new instance of Cursor.



77
78
79
80
81
82
83
84
85
86
87
# File 'lib/params_ready/pagination/cursor.rb', line 77

def initialize(select_list, arel_table, context)
  @hash = select_list_to_hash(select_list)
  @selectors, @literals = select_list.partition { |attr| attr.is_a? Selector }
  @arel_table = arel_table
  @context = context
  names = column_names(@selectors)
  @cte_ref = Arel::Table.new(cte_reference(names))
  @cte_def = cte_definition(@cte_ref, names)

  freeze
end

Instance Attribute Details

#cteObject (readonly)

Returns the value of attribute cte.



75
76
77
# File 'lib/params_ready/pagination/cursor.rb', line 75

def cte
  @cte
end

#literalsObject (readonly)

Returns the value of attribute literals.



75
76
77
# File 'lib/params_ready/pagination/cursor.rb', line 75

def literals
  @literals
end

#select_listObject (readonly)

Returns the value of attribute select_list.



75
76
77
# File 'lib/params_ready/pagination/cursor.rb', line 75

def select_list
  @select_list
end

#selectorsObject (readonly)

Returns the value of attribute selectors.



75
76
77
# File 'lib/params_ready/pagination/cursor.rb', line 75

def selectors
  @selectors
end

Instance Method Details

#active_record_predicates(literals) ⇒ Object



121
122
123
124
125
126
127
# File 'lib/params_ready/pagination/cursor.rb', line 121

def active_record_predicates(literals)
  literals.select do |literal|
    literal.pk
  end.map do |literal|
    [literal.key, literal.value]
  end.to_h
end

#arel_predicates(literals, arel_table) ⇒ Object



129
130
131
132
133
134
135
136
137
138
# File 'lib/params_ready/pagination/cursor.rb', line 129

def arel_predicates(literals, arel_table)
  literals.reduce(nil) do |query, literal|
    next query unless literal.pk

    predicate = arel_table[literal.key].eq(literal.quoted)
    next predicate if query.nil?

    query.and(predicate)
  end
end

#column_expressions(selectors) ⇒ Object



144
145
146
147
148
# File 'lib/params_ready/pagination/cursor.rb', line 144

def column_expressions(selectors)
  selectors.map do |selector|
    selector.expression(@arel_table, @context)
  end
end

#column_names(selectors) ⇒ Object



140
141
142
# File 'lib/params_ready/pagination/cursor.rb', line 140

def column_names(selectors)
  selectors.lazy.map(&:key).map(&:to_s).force
end

#cte_definition(reference, names) ⇒ Object



155
156
157
158
159
160
161
162
163
# File 'lib/params_ready/pagination/cursor.rb', line 155

def cte_definition(reference, names)
  node = Arel::Nodes::SqlLiteral.new(names.join(', '))
  grouping = Arel::Nodes::Grouping.new(node)
  # The name must be literal, otherwise
  # it will be quoted by the visitor
  expression = "#{reference.name} #{grouping.to_sql}"

  Arel::Nodes::CteName.new(expression)
end

#cte_for_query(query, arel_table) ⇒ Object



110
111
112
113
114
115
116
117
118
119
# File 'lib/params_ready/pagination/cursor.rb', line 110

def cte_for_query(query, arel_table)
  return nil if selectors.empty?

  query = query.deep_dup
  expressions = column_expressions(selectors)
  query = query.where(arel_predicates(literals, arel_table))
               .project(*expressions)
  grouping = Arel::Nodes::Grouping.new(query)
  Arel::Nodes::As.new(@cte_def, grouping)
end

#cte_for_relation(relation) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
# File 'lib/params_ready/pagination/cursor.rb', line 98

def cte_for_relation(relation)
  return nil if selectors.empty?

  expressions = column_expressions(selectors)
  relation = relation.where(**active_record_predicates(literals))
                     .select(*expressions)
  select = Arel::Nodes::SqlLiteral.new(relation.to_sql)
  grouping = Arel::Nodes::Grouping.new(select)
  as = Arel::Nodes::As.new(@cte_def, grouping)
  Arel::Nodes::With.new([as])
end

#cte_reference(names) ⇒ Object



150
151
152
153
# File 'lib/params_ready/pagination/cursor.rb', line 150

def cte_reference(names)
  unsafe_name = "#{names.join('_')}_cte"
  Helpers::ArelBuilder.safe_name(unsafe_name)
end

#rvalue(key) ⇒ Object



165
166
167
# File 'lib/params_ready/pagination/cursor.rb', line 165

def rvalue(key)
  @hash[key].rvalue(@cte_ref)
end

#select_list_to_hash(select_list) ⇒ Object



89
90
91
92
93
94
95
96
# File 'lib/params_ready/pagination/cursor.rb', line 89

def select_list_to_hash(select_list)
  res = select_list.each_with_object({}) do |item, hash|
    raise ParamsReadyError, "Repeated key in select list: '#{item.key}'" if hash.key? item.key

    hash[item.key] = item
  end
  res.freeze
end