Class: Gitlab::Pagination::Keyset::ColumnConditionBuilder
- Inherits:
-
Object
- Object
- Gitlab::Pagination::Keyset::ColumnConditionBuilder
- Defined in:
- lib/gitlab/pagination/keyset/column_condition_builder.rb
Instance Method Summary collapse
-
#initialize(column, value) ⇒ ColumnConditionBuilder
constructor
This class builds the WHERE conditions for the keyset pagination library.
- #where_conditions(current_conditions) ⇒ Object
Constructor Details
#initialize(column, value) ⇒ ColumnConditionBuilder
This class builds the WHERE conditions for the keyset pagination library. It produces WHERE conditions for one column at a time.
Requisite 1: Only the last column (columns.last) is non-nullable and distinct. Requisite 2: Only one column is distinct and non-nullable.
Scenario: We want to order by columns named X, Y and Z and build the conditions
used in the WHERE clause of a pagination query using a set of cursor values.
X is the column definition for a nullable column
Y is the column definition for a non-nullable but not distinct column
Z is the column definition for a distinct, non-nullable column used as a tie breaker.
Then the method is initially invoked with these arguments:
columns = [ColumnDefinition for X, ColumnDefinition for Y, ColumnDefinition for Z]
values = { X: x, Y: y, Z: z } => these represent cursor values for pagination
(x could be nil since X is nullable)
current_conditions is initialized to [] to store the result during the iteration calls
invoked within the Order#build_where_values method.
The elements of current_conditions are instances of Arel::Nodes and -
will be concatenated using OR or UNION to be used in the WHERE clause.
Example: Let's say we want to build WHERE clause conditions for
ORDER BY X DESC NULLS LAST, Y ASC, Z DESC
Iteration 1:
columns = [X, Y, Z]
At the end, current_conditions should be:
[(Z < z)]
Iteration 2:
columns = [X, Y]
At the end, current_conditions should be:
[(Y > y) OR (Y = y AND Z < z)]
Iteration 3:
columns = [X]
At the end, current_conditions should be:
[((X IS NOT NULL AND Y > y) OR (X IS NOT NULL AND Y = y AND Z < z))
OR
((x IS NULL) OR (X IS NULL))]
Parameters:
- columns: instance of ColumnOrderDefinition
- value: cursor value for the column
53 54 55 56 |
# File 'lib/gitlab/pagination/keyset/column_condition_builder.rb', line 53 def initialize(column, value) @column = column @value = value end |
Instance Method Details
#where_conditions(current_conditions) ⇒ Object
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/gitlab/pagination/keyset/column_condition_builder.rb', line 58 def where_conditions(current_conditions) return not_nullable_conditions(current_conditions) if column.not_nullable? return nulls_first_conditions(current_conditions) if column.nulls_first? # Here we are dealing with the case of column_definition.nulls_last? # Suppose ORDER BY X DESC NULLS FIRST, Y ASC, Z DESC is the ordering clause # and we already have built the conditions for columns Y and Z. # # We first need a set of conditions to use when x (the value for X) is NULL: # null_conds = [ # (x IS NULL AND X IS NULL AND Y<y), # (x IS NULL AND X IS NULL AND Y=y AND Z<z), null_conds = current_conditions.map do |conditional| Arel::Nodes::And.new([value_is_null, column_is_null, conditional]) end # We then need a set of conditions to use when m has an actual value: # non_null_conds = [ # (x IS NOT NULL AND X IS NULL), # (x IS NOT NULL AND X < x) # (x IS NOT NULL AND X = x AND Y > y), # (x IS NOT NULL AND X = x AND Y = y AND Z < z), tie_breaking_conds = current_conditions.map do |conditional| Arel::Nodes::And.new([column_equals_to_value, conditional]) end non_null_conds = [column_is_null, compare_column_with_value, *tie_breaking_conds].map do |conditional| Arel::Nodes::And.new([value_is_not_null, conditional]) end [*null_conds, *non_null_conds] end |