Skip to content
Snippets Groups Projects
Commit d3829774 authored by Aleksei Lipniagov's avatar Aleksei Lipniagov Committed by Adam Hegyi
Browse files

Use Arel-native nulls order

Remove Database.nulls_order implementation with Arel-native
implementation of the same funcion.
parent 98284cbb
No related branches found
No related tags found
No related merge requests found
Showing
with 70 additions and 62 deletions
Loading
Loading
@@ -18,7 +18,7 @@ class AgentToken < ApplicationRecord
validates :description, length: { maximum: 1024 }
validates :name, presence: true, length: { maximum: 255 }
 
scope :order_last_used_at_desc, -> { order(::Gitlab::Database.nulls_last_order('last_used_at', 'DESC')) }
scope :order_last_used_at_desc, -> { order(arel_table[:last_used_at].desc.nulls_last) }
scope :with_status, -> (status) { where(status: status) }
 
enum status: {
Loading
Loading
Loading
Loading
@@ -318,12 +318,16 @@ def order_due_date_and_labels_priority(direction = 'ASC', excluded_labels: [])
# 2. We can't ORDER BY a column that isn't in the GROUP BY and doesn't
# have an aggregate function applied, so we do a useless MIN() instead.
#
milestones_due_date = 'MIN(milestones.due_date)'
milestones_due_date = Milestone.arel_table[:due_date].minimum
milestones_due_date_with_direction = direction == 'ASC' ? milestones_due_date.asc : milestones_due_date.desc
highest_priority_arel = Arel.sql('highest_priority')
highest_priority_arel_with_direction = direction == 'ASC' ? highest_priority_arel.asc : highest_priority_arel.desc
 
order_milestone_due_asc
.order_labels_priority(excluded_labels: excluded_labels, extra_select_columns: [milestones_due_date])
.reorder(Gitlab::Database.nulls_last_order(milestones_due_date, direction),
Gitlab::Database.nulls_last_order('highest_priority', direction))
.reorder(milestones_due_date_with_direction.nulls_last,
highest_priority_arel_with_direction.nulls_last)
end
 
def order_labels_priority(direction = 'ASC', excluded_labels: [], extra_select_columns: [], with_cte: false)
Loading
Loading
@@ -341,12 +345,15 @@ def order_labels_priority(direction = 'ASC', excluded_labels: [], extra_select_c
 
extra_select_columns.unshift("highest_priorities.label_priority as highest_priority")
 
highest_priority_arel = Arel.sql('highest_priority')
highest_priority_arel_with_direction = direction == 'ASC' ? highest_priority_arel.asc : highest_priority_arel.desc
select(issuable_columns)
.select(extra_select_columns)
.from("#{table_name}")
.joins("JOIN LATERAL(#{highest_priority}) as highest_priorities ON TRUE")
.group(group_columns)
.reorder(Gitlab::Database.nulls_last_order('highest_priority', direction))
.reorder(highest_priority_arel_with_direction.nulls_last)
end
 
def with_label(title, sort = nil)
Loading
Loading
Loading
Loading
@@ -66,10 +66,10 @@ class Environment < ApplicationRecord
scope :stopped, -> { with_state(:stopped) }
 
scope :order_by_last_deployed_at, -> do
order(Gitlab::Database.nulls_first_order("(#{max_deployment_id_sql})", 'ASC'))
order(Arel::Nodes::Grouping.new(max_deployment_id_query).asc.nulls_first)
end
scope :order_by_last_deployed_at_desc, -> do
order(Gitlab::Database.nulls_last_order("(#{max_deployment_id_sql})", 'DESC'))
order(Arel::Nodes::Grouping.new(max_deployment_id_query).desc.nulls_last)
end
scope :order_by_name, -> { order('environments.name ASC') }
 
Loading
Loading
@@ -151,10 +151,11 @@ def self.for_id_and_slug(id, slug)
find_by(id: id, slug: slug)
end
 
def self.max_deployment_id_sql
Deployment.select(Deployment.arel_table[:id].maximum)
.where(Deployment.arel_table[:environment_id].eq(arel_table[:id]))
.to_sql
def self.max_deployment_id_query
Arel.sql(
Deployment.select(Deployment.arel_table[:id].maximum)
.where(Deployment.arel_table[:environment_id].eq(arel_table[:id])).to_sql
)
end
 
def self.pluck_names
Loading
Loading
Loading
Loading
@@ -118,15 +118,15 @@ def most_recent
 
scope :not_authored_by, ->(user) { where.not(author_id: user) }
 
scope :order_due_date_asc, -> { reorder(::Gitlab::Database.nulls_last_order('due_date', 'ASC')) }
scope :order_due_date_desc, -> { reorder(::Gitlab::Database.nulls_last_order('due_date', 'DESC')) }
scope :order_due_date_asc, -> { reorder(arel_table[:due_date].asc.nulls_last) }
scope :order_due_date_desc, -> { reorder(arel_table[:due_date].desc.nulls_last) }
scope :order_closest_future_date, -> { reorder(Arel.sql('CASE WHEN issues.due_date >= CURRENT_DATE THEN 0 ELSE 1 END ASC, ABS(CURRENT_DATE - issues.due_date) ASC')) }
scope :order_closed_date_desc, -> { reorder(closed_at: :desc) }
scope :order_created_at_desc, -> { reorder(created_at: :desc) }
scope :order_severity_asc, -> { includes(:issuable_severity).order('issuable_severities.severity ASC NULLS FIRST') }
scope :order_severity_desc, -> { includes(:issuable_severity).order('issuable_severities.severity DESC NULLS LAST') }
scope :order_escalation_status_asc, -> { includes(:incident_management_issuable_escalation_status).order(::Gitlab::Database.nulls_last_order('incident_management_issuable_escalation_status.status')) }
scope :order_escalation_status_desc, -> { includes(:incident_management_issuable_escalation_status).order(::Gitlab::Database.nulls_last_order('incident_management_issuable_escalation_status.status', 'DESC')) }
scope :order_escalation_status_asc, -> { includes(:incident_management_issuable_escalation_status).order(IncidentManagement::IssuableEscalationStatus.arel_table[:status].asc.nulls_last).references(:incident_management_issuable_escalation_status) }
scope :order_escalation_status_desc, -> { includes(:incident_management_issuable_escalation_status).order(IncidentManagement::IssuableEscalationStatus.arel_table[:status].desc.nulls_last).references(:incident_management_issuable_escalation_status) }
 
scope :preload_associated_models, -> { preload(:assignees, :labels, project: :namespace) }
scope :with_web_entity_associations, -> { preload(:author, project: [:project_feature, :route, namespace: :route]) }
Loading
Loading
@@ -344,8 +344,8 @@ def self.column_order_relative_position
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
attribute_name: 'relative_position',
column_expression: arel_table[:relative_position],
order_expression: Gitlab::Database.nulls_last_order('issues.relative_position', 'ASC'),
reversed_order_expression: Gitlab::Database.nulls_last_order('issues.relative_position', 'DESC'),
order_expression: Issue.arel_table[:relative_position].asc.nulls_last,
reversed_order_expression: Issue.arel_table[:relative_position].desc.nulls_last,
order_direction: :asc,
nullable: :nulls_last,
distinct: false
Loading
Loading
Loading
Loading
@@ -49,7 +49,7 @@ class Key < ApplicationRecord
 
scope :preload_users, -> { preload(:user) }
scope :for_user, -> (user) { where(user: user) }
scope :order_last_used_at_desc, -> { reorder(::Gitlab::Database.nulls_last_order('last_used_at', 'DESC')) }
scope :order_last_used_at_desc, -> { reorder(arel_table[:last_used_at].desc.nulls_last) }
 
# Date is set specifically in this scope to improve query time.
scope :expired_today_and_not_notified, -> { where(["date(expires_at AT TIME ZONE 'UTC') = CURRENT_DATE AND expiry_notification_delivered_at IS NULL"]) }
Loading
Loading
Loading
Loading
@@ -178,14 +178,14 @@ class Member < ApplicationRecord
unscoped.from(distinct_members, :members)
end
 
scope :order_name_asc, -> { left_join_users.reorder(Gitlab::Database.nulls_last_order('users.name', 'ASC')) }
scope :order_name_desc, -> { left_join_users.reorder(Gitlab::Database.nulls_last_order('users.name', 'DESC')) }
scope :order_recent_sign_in, -> { left_join_users.reorder(Gitlab::Database.nulls_last_order('users.last_sign_in_at', 'DESC')) }
scope :order_oldest_sign_in, -> { left_join_users.reorder(Gitlab::Database.nulls_last_order('users.last_sign_in_at', 'ASC')) }
scope :order_recent_last_activity, -> { left_join_users.reorder(Gitlab::Database.nulls_last_order('users.last_activity_on', 'DESC')) }
scope :order_oldest_last_activity, -> { left_join_users.reorder(Gitlab::Database.nulls_first_order('users.last_activity_on', 'ASC')) }
scope :order_recent_created_user, -> { left_join_users.reorder(Gitlab::Database.nulls_last_order('users.created_at', 'DESC')) }
scope :order_oldest_created_user, -> { left_join_users.reorder(Gitlab::Database.nulls_first_order('users.created_at', 'ASC')) }
scope :order_name_asc, -> { left_join_users.reorder(User.arel_table[:name].asc.nulls_last) }
scope :order_name_desc, -> { left_join_users.reorder(User.arel_table[:name].desc.nulls_last) }
scope :order_recent_sign_in, -> { left_join_users.reorder(User.arel_table[:last_sign_in_at].desc.nulls_last) }
scope :order_oldest_sign_in, -> { left_join_users.reorder(User.arel_table[:last_sign_in_at].asc.nulls_last) }
scope :order_recent_last_activity, -> { left_join_users.reorder(User.arel_table[:last_activity_on].desc.nulls_last) }
scope :order_oldest_last_activity, -> { left_join_users.reorder(User.arel_table[:last_activity_on].asc.nulls_first) }
scope :order_recent_created_user, -> { left_join_users.reorder(User.arel_table[:created_at].desc.nulls_last) }
scope :order_oldest_created_user, -> { left_join_users.reorder(User.arel_table[:created_at].asc.nulls_first) }
 
scope :on_project_and_ancestors, ->(project) { where(source: [project] + project.ancestors) }
 
Loading
Loading
Loading
Loading
@@ -329,15 +329,15 @@ def public_merge_status
end
scope :by_target_branch, ->(branch_name) { where(target_branch: branch_name) }
scope :order_by_metric, ->(metric, direction) do
reverse_direction = { 'ASC' => 'DESC', 'DESC' => 'ASC' }
reversed_direction = reverse_direction[direction] || raise("Unknown sort direction was given: #{direction}")
column_expression = MergeRequest::Metrics.arel_table[metric]
column_expression_with_direction = direction == 'ASC' ? column_expression.asc : column_expression.desc
 
order = Gitlab::Pagination::Keyset::Order.build([
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
attribute_name: "merge_request_metrics_#{metric}",
column_expression: MergeRequest::Metrics.arel_table[metric],
order_expression: Gitlab::Database.nulls_last_order("merge_request_metrics.#{metric}", direction),
reversed_order_expression: Gitlab::Database.nulls_first_order("merge_request_metrics.#{metric}", reversed_direction),
column_expression: column_expression,
order_expression: column_expression_with_direction.nulls_last,
reversed_order_expression: column_expression_with_direction.reverse.nulls_first,
order_direction: direction,
nullable: :nulls_last,
distinct: false,
Loading
Loading
Loading
Loading
@@ -31,7 +31,7 @@ class Predefined
end
 
scope :order_by_name_asc, -> { order(Arel::Nodes::Ascending.new(arel_table[:title].lower)) }
scope :reorder_by_due_date_asc, -> { reorder(Gitlab::Database.nulls_last_order('due_date', 'ASC')) }
scope :reorder_by_due_date_asc, -> { reorder(arel_table[:due_date].asc.nulls_last) }
scope :with_api_entity_associations, -> { preload(project: [:project_feature, :route, namespace: :route]) }
scope :order_by_dates_and_title, -> { order(due_date: :asc, start_date: :asc, title: :asc) }
 
Loading
Loading
@@ -116,15 +116,15 @@ def self.sort_by_attribute(method)
when 'due_date_asc'
reorder_by_due_date_asc
when 'due_date_desc'
reorder(Gitlab::Database.nulls_last_order('due_date', 'DESC'))
reorder(arel_table[:due_date].desc.nulls_last)
when 'name_asc'
reorder(Arel::Nodes::Ascending.new(arel_table[:title].lower))
when 'name_desc'
reorder(Arel::Nodes::Descending.new(arel_table[:title].lower))
when 'start_date_asc'
reorder(Gitlab::Database.nulls_last_order('start_date', 'ASC'))
reorder(arel_table[:start_date].asc.nulls_last)
when 'start_date_desc'
reorder(Gitlab::Database.nulls_last_order('start_date', 'DESC'))
reorder(arel_table[:start_date].desc.nulls_last)
else
order_by(method)
end
Loading
Loading
Loading
Loading
@@ -132,7 +132,7 @@ class Namespace < ApplicationRecord
 
scope :user_namespaces, -> { where(type: Namespaces::UserNamespace.sti_name) }
scope :without_project_namespaces, -> { where(Namespace.arel_table[:type].not_eq(Namespaces::ProjectNamespace.sti_name)) }
scope :sort_by_type, -> { order(Gitlab::Database.nulls_first_order(:type)) }
scope :sort_by_type, -> { order(arel_table[:type].asc.nulls_first) }
scope :include_route, -> { includes(:route) }
scope :by_parent, -> (parent) { where(parent_id: parent) }
scope :filter_by_path, -> (query) { where('lower(path) = :query', query: query.downcase) }
Loading
Loading
Loading
Loading
@@ -228,8 +228,8 @@ def self.sort_by_attribute(method)
 
def self.keyset_pagination_order(join_class:, column_name:, direction: :asc)
join_table = join_class.table_name
asc_order_expression = Gitlab::Database.nulls_last_order("#{join_table}.#{column_name}", :asc)
desc_order_expression = Gitlab::Database.nulls_first_order("#{join_table}.#{column_name}", :desc)
asc_order_expression = join_class.arel_table[column_name].asc.nulls_last
desc_order_expression = join_class.arel_table[column_name].desc.nulls_first
order_direction = direction == :asc ? asc_order_expression : desc_order_expression
reverse_order_direction = direction == :asc ? desc_order_expression : asc_order_expression
arel_order_classes = ::Gitlab::Pagination::Keyset::ColumnOrderDefinition::AREL_ORDER_CLASSES.invert
Loading
Loading
Loading
Loading
@@ -148,10 +148,10 @@ def order_by_labels_priority
target_type_column: "todos.target_type",
target_column: "todos.target_id",
project_column: "todos.project_id"
).to_sql
).arel.as('highest_priority')
 
select("#{table_name}.*, (#{highest_priority}) AS highest_priority")
.order(Gitlab::Database.nulls_last_order('highest_priority', 'ASC'))
select(arel_table[Arel.star], highest_priority)
.order(Arel.sql('highest_priority').asc.nulls_last)
.order('todos.created_at')
end
 
Loading
Loading
Loading
Loading
@@ -470,10 +470,10 @@ def blocked?
.where('keys.user_id = users.id')
.expiring_soon_and_not_notified)
end
scope :order_recent_sign_in, -> { reorder(Gitlab::Database.nulls_last_order('current_sign_in_at', 'DESC')) }
scope :order_oldest_sign_in, -> { reorder(Gitlab::Database.nulls_last_order('current_sign_in_at', 'ASC')) }
scope :order_recent_last_activity, -> { reorder(Gitlab::Database.nulls_last_order('last_activity_on', 'DESC')) }
scope :order_oldest_last_activity, -> { reorder(Gitlab::Database.nulls_first_order('last_activity_on', 'ASC')) }
scope :order_recent_sign_in, -> { reorder(arel_table[:current_sign_in_at].desc.nulls_last) }
scope :order_oldest_sign_in, -> { reorder(arel_table[:current_sign_in_at].asc.nulls_last) }
scope :order_recent_last_activity, -> { reorder(arel_table[:last_activity_on].desc.nulls_last) }
scope :order_oldest_last_activity, -> { reorder(arel_table[:last_activity_on].asc.nulls_first) }
scope :by_id_and_login, ->(id, login) { where(id: id).where('username = LOWER(:login) OR email = LOWER(:login)', login: login) }
scope :dormant, -> { with_state(:active).human_or_service_user.where('last_activity_on <= ?', MINIMUM_INACTIVE_DAYS.day.ago.to_date) }
scope :with_no_activity, -> { with_state(:active).human_or_service_user.where(last_activity_on: nil) }
Loading
Loading
Loading
Loading
@@ -166,7 +166,7 @@ These order objects can be defined in the model classes as normal ActiveRecord s
Consider the following scope:
 
```ruby
scope = Issue.where(project_id: 10).order(Gitlab::Database.nulls_last_order('relative_position', 'DESC'))
scope = Issue.where(project_id: 10).order(Issue.arel_table[:relative_position].desc.nulls_last)
# SELECT "issues".* FROM "issues" WHERE "issues"."project_id" = 10 ORDER BY relative_position DESC NULLS LAST
 
scope.keyset_paginate # raises: Gitlab::Pagination::Keyset::UnsupportedScopeOrder: The order on the scope does not support keyset pagination
Loading
Loading
@@ -190,8 +190,8 @@ order = Gitlab::Pagination::Keyset::Order.build([
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
attribute_name: 'relative_position',
column_expression: Issue.arel_table[:relative_position],
order_expression: Gitlab::Database.nulls_last_order('relative_position', 'DESC'),
reversed_order_expression: Gitlab::Database.nulls_first_order('relative_position', 'ASC'),
order_expression: Issue.arel_table[:relative_position].desc.nulls_last,
reversed_order_expression: Issue.arel_table[:relative_position].asc.nulls_first,
nullable: :nulls_last,
order_direction: :desc,
distinct: false
Loading
Loading
Loading
Loading
@@ -168,7 +168,7 @@ def left_join_repository_state
end
 
def last_repository_updated_at_asc
Gitlab::Database.nulls_last_order('projects.last_repository_updated_at', 'ASC')
Project.arel_table[:last_repository_updated_at].asc.nulls_last
end
 
# rubocop: disable CodeReuse/ActiveRecord
Loading
Loading
Loading
Loading
@@ -59,7 +59,7 @@ def replicator_class
attr_accessor :custom_max_retry_wait_time
 
scope :failed, -> { with_state(:failed) }
scope :needs_sync_again, -> { failed.retry_due.order(Gitlab::Database.nulls_first_order(:retry_at)) }
scope :needs_sync_again, -> { failed.retry_due.order(arel_table[:retry_at].asc.nulls_first) }
scope :never_attempted_sync, -> { pending.where(last_synced_at: nil) }
scope :ordered, -> { order(:id) }
scope :pending, -> { with_state(:pending) }
Loading
Loading
Loading
Loading
@@ -65,7 +65,7 @@ def verification_state_value(state_string)
# query.
#
def verification_pending_batch(batch_size:)
relation = verification_pending.order(Gitlab::Database.nulls_first_order(:verified_at)).limit(batch_size)
relation = verification_pending.order(verification_arel_table[:verified_at].asc.nulls_first).limit(batch_size)
 
start_verification_batch(relation)
end
Loading
Loading
@@ -76,7 +76,7 @@ def verification_pending_batch(batch_size:)
# query.
#
def verification_failed_batch(batch_size:)
relation = verification_failed.verification_retry_due.order(Gitlab::Database.nulls_first_order(:verification_retry_at)).limit(batch_size)
relation = verification_failed.verification_retry_due.order(verification_arel_table[:verification_retry_at].asc.nulls_first).limit(batch_size)
 
start_verification_batch(relation)
end
Loading
Loading
Loading
Loading
@@ -139,7 +139,7 @@ def close
end
 
scope :order_relative_position_on_board, ->(board_id) do
reorder(::Gitlab::Database.nulls_last_order('boards_epic_board_positions.relative_position', 'ASC'), 'epics.id DESC')
reorder(::Boards::EpicBoardPosition.arel_table[:relative_position].asc.nulls_last, 'epics.id DESC')
end
 
scope :without_board_position, ->(board_id) do
Loading
Loading
@@ -359,14 +359,15 @@ def issue_metadata_for_epics(epic_ids:, limit:)
end
 
def keyset_pagination_for(column_name:, direction: 'ASC')
reverse_direction = direction == 'ASC' ? 'DESC' : 'ASC'
column_expression = ::Epic.arel_table[column_name]
column_expression_with_direction = direction == 'ASC' ? column_expression.asc : column_expression.desc
 
::Gitlab::Pagination::Keyset::Order.build([
::Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
attribute_name: column_name.to_s,
column_expression: ::Epic.arel_table[column_name],
order_expression: ::Gitlab::Database.nulls_last_order(column_name, direction),
reversed_order_expression: ::Gitlab::Database.nulls_last_order(column_name, reverse_direction),
column_expression: column_expression,
order_expression: column_expression_with_direction.nulls_last,
reversed_order_expression: column_expression_with_direction.reverse.nulls_last,
order_direction: direction,
distinct: false,
nullable: :nulls_last
Loading
Loading
Loading
Loading
@@ -23,8 +23,8 @@ module Issue
 
scope :order_blocking_issues_asc, -> { reorder(blocking_issues_count: :asc) }
scope :order_blocking_issues_desc, -> { reorder(blocking_issues_count: :desc) }
scope :order_weight_desc, -> { reorder ::Gitlab::Database.nulls_last_order('weight', 'DESC') }
scope :order_weight_asc, -> { reorder ::Gitlab::Database.nulls_last_order('weight') }
scope :order_weight_desc, -> { reorder(arel_table[:weight].desc.nulls_last) }
scope :order_weight_asc, -> { reorder(arel_table[:weight].asc.nulls_last) }
scope :order_status_page_published_first, -> { includes(:status_page_published_incident).order('status_page_published_incidents.id ASC NULLS LAST') }
scope :order_status_page_published_last, -> { includes(:status_page_published_incident).order('status_page_published_incidents.id ASC NULLS FIRST') }
scope :order_sla_due_at_asc, -> { includes(:issuable_sla).order('issuable_slas.due_at ASC NULLS LAST') }
Loading
Loading
Loading
Loading
@@ -59,8 +59,7 @@ def applicable_to_branch(branch)
accepts_nested_attributes_for :approval_rules, allow_destroy: true
 
scope :order_review_time_desc, -> do
joins(:metrics)
.reorder(::Gitlab::Database.nulls_last_order(::MergeRequest::Metrics.review_time_field))
joins(:metrics).reorder(::MergeRequest::Metrics.review_time_field.asc.nulls_last)
end
 
scope :with_code_review_api_entity_associations, -> do
Loading
Loading
Loading
Loading
@@ -43,7 +43,7 @@ class << self
include Delay
 
def find_registries_needs_sync_again(batch_size:, except_ids: [])
super.order(Gitlab::Database.nulls_first_order(:last_synced_at))
super.order(arel_table[:last_synced_at].asc.nulls_first)
end
 
def delete_for_model_ids(container_repository_ids)
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment