From 4c867daabbc38e94563cbb8de72da945c5e88125 Mon Sep 17 00:00:00 2001 From: cryptogopher Date: Sat, 22 Mar 2025 14:14:42 +0100 Subject: [PATCH] Patch ActiveRecord with PR 54658 --- config/initializers/core_ext.rb | 11 +++++++++++ .../relation/update_and_delete_cte_support.rb | 3 +++ .../arel/crud_cte_update_and_delete.rb | 11 +++++++++++ .../delete_statement_cte_update_and_delete.rb | 16 ++++++++++++++++ .../update_statement_cte_update_and_delete.rb | 16 ++++++++++++++++ .../select_manager_cte_update_and_delete.rb | 5 +++++ ...statement_methods_cte_update_and_delete.rb | 6 ++++++ .../visitors/to_sql_cte_update_and_delete.rb | 19 +++++++++++++++++++ 8 files changed, 87 insertions(+) create mode 100644 lib/core_ext/active_record/relation/update_and_delete_cte_support.rb create mode 100644 lib/core_ext/arel/crud_cte_update_and_delete.rb create mode 100644 lib/core_ext/arel/nodes/delete_statement_cte_update_and_delete.rb create mode 100644 lib/core_ext/arel/nodes/update_statement_cte_update_and_delete.rb create mode 100644 lib/core_ext/arel/select_manager_cte_update_and_delete.rb create mode 100644 lib/core_ext/arel/tree_manager/statement_methods_cte_update_and_delete.rb create mode 100644 lib/core_ext/arel/visitors/to_sql_cte_update_and_delete.rb diff --git a/config/initializers/core_ext.rb b/config/initializers/core_ext.rb index 90b09b8..e73da73 100644 --- a/config/initializers/core_ext.rb +++ b/config/initializers/core_ext.rb @@ -11,4 +11,15 @@ end ActiveSupport.on_load :active_record do ActiveModel::Validations::NumericalityValidator .prepend CoreExt::ActiveModel::Validations::NumericalityValidatesPrecisionAndScale + + # Temporary patch for https://github.com/rails/rails/pull/54658 + Arel::TreeManager::StatementMethods + .prepend CoreExt::Arel::TreeManager::StatementMethodsCteUpdateAndDelete + Arel::Nodes::DeleteStatement + .prepend CoreExt::Arel::Nodes::DeleteStatementCteUpdateAndDelete + Arel::Nodes::UpdateStatement + .prepend CoreExt::Arel::Nodes::UpdateStatementCteUpdateAndDelete + Arel::Visitors::ToSql.prepend CoreExt::Arel::Visitors::ToSqlCteUpdateAndDelete + Arel::Crud.prepend CoreExt::Arel::CrudCteUpdateAndDelete + Arel::SelectManager.prepend CoreExt::Arel::SelectManagerCteUpdateAndDelete end diff --git a/lib/core_ext/active_record/relation/update_and_delete_cte_support.rb b/lib/core_ext/active_record/relation/update_and_delete_cte_support.rb new file mode 100644 index 0000000..facd8c7 --- /dev/null +++ b/lib/core_ext/active_record/relation/update_and_delete_cte_support.rb @@ -0,0 +1,3 @@ +module CoreExt::ActiveRecord::Relation::UpdateAndDeleteCteSupport + INVALID_METHODS_FOR_UPDATE_AND_DELETE_ALL = [:distinct] +end diff --git a/lib/core_ext/arel/crud_cte_update_and_delete.rb b/lib/core_ext/arel/crud_cte_update_and_delete.rb new file mode 100644 index 0000000..34926b3 --- /dev/null +++ b/lib/core_ext/arel/crud_cte_update_and_delete.rb @@ -0,0 +1,11 @@ +module CoreExt::Arel::CrudCteUpdateAndDelete + def compile_update(...) + um = super + um.with = subqueries + end + + def compile_delete(...) + dm = super + dm.with = subqueries + end +end diff --git a/lib/core_ext/arel/nodes/delete_statement_cte_update_and_delete.rb b/lib/core_ext/arel/nodes/delete_statement_cte_update_and_delete.rb new file mode 100644 index 0000000..b7e07b2 --- /dev/null +++ b/lib/core_ext/arel/nodes/delete_statement_cte_update_and_delete.rb @@ -0,0 +1,16 @@ +module CoreExt::Arel::Nodes::DeleteStatementCteUpdateAndDelete + attr_accessor :with + + def initialize(...) + super + @with = nil + end + + def hash + [self.class, @relation, @wheres, @orders, @limit, @offset, @key, @with].hash + end + + def eql?(other) + eql?(other) && self.with == other.with + end +end diff --git a/lib/core_ext/arel/nodes/update_statement_cte_update_and_delete.rb b/lib/core_ext/arel/nodes/update_statement_cte_update_and_delete.rb new file mode 100644 index 0000000..2cb4531 --- /dev/null +++ b/lib/core_ext/arel/nodes/update_statement_cte_update_and_delete.rb @@ -0,0 +1,16 @@ +module CoreExt::Arel::Nodes::UpdateStatementCteUpdateAndDelete + attr_accessor :with + + def initialize(...) + super + @with = nil + end + + def hash + [self.class, @relation, @wheres, @orders, @limit, @offset, @key, @with].hash + end + + def eql?(other) + eql?(other) && self.with == other.with + end +end diff --git a/lib/core_ext/arel/select_manager_cte_update_and_delete.rb b/lib/core_ext/arel/select_manager_cte_update_and_delete.rb new file mode 100644 index 0000000..6f5635f --- /dev/null +++ b/lib/core_ext/arel/select_manager_cte_update_and_delete.rb @@ -0,0 +1,5 @@ +module CoreExt::Arel::SelectManagerCteUpdateAndDelete + def subqueries + @ast.with + end +end diff --git a/lib/core_ext/arel/tree_manager/statement_methods_cte_update_and_delete.rb b/lib/core_ext/arel/tree_manager/statement_methods_cte_update_and_delete.rb new file mode 100644 index 0000000..4b38b29 --- /dev/null +++ b/lib/core_ext/arel/tree_manager/statement_methods_cte_update_and_delete.rb @@ -0,0 +1,6 @@ +module CoreExt::Arel::TreeManager::StatementMethodsCteUpdateAndDelete + def with=(expr) + @ast.with = expr + self + end +end diff --git a/lib/core_ext/arel/visitors/to_sql_cte_update_and_delete.rb b/lib/core_ext/arel/visitors/to_sql_cte_update_and_delete.rb new file mode 100644 index 0000000..2e44c45 --- /dev/null +++ b/lib/core_ext/arel/visitors/to_sql_cte_update_and_delete.rb @@ -0,0 +1,19 @@ +module CoreExt::Arel::Visitors::ToSqlCteUpdateAndDelete + def visit_Arel_Nodes_DeleteStatement(o, collector) + if o.with + collector = visit o.with, collector + collector << " " + end + + super + end + + def visit_Arel_Nodes_UpdateStatement(o, collector) + if o.with + collector = visit o.with, collector + collector << " " + end + + super + end +end