Skip to content

Commit

Permalink
fix: Ambiguous SQL ID
Browse files Browse the repository at this point in the history
  • Loading branch information
Quentinchampenois committed Dec 15, 2023
1 parent b4d1f45 commit 04a1c7f
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 0 deletions.
1 change: 1 addition & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class Application < Rails::Application
config.after_initialize do
require "extends/controllers/decidim/devise/sessions_controller_extends"
require "extends/controllers/decidim/editor_images_controller_extends"
require "extends/models/decidim/budgets/project_extend"
require "extends/services/decidim/iframe_disabler_extends"

Decidim::GraphiQL::Rails.config.tap do |config|
Expand Down
19 changes: 19 additions & 0 deletions lib/extends/models/decidim/budgets/project_extend.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

require "active_support/concern"
module ProjectExtends
extend ActiveSupport::Concern

included do
def self.ordered_ids(ids)
# Make sure each ID in the matching text has a "," character as their
# delimiter. Otherwise e.g. ID 2 would match ID "26" in the original
# array. This is why we search for match ",2," instead to get the actual
# position for ID 2.
concat_ids = connection.quote(",#{ids.join(",")},")
order(Arel.sql("position(concat(',', decidim_budgets_projects.id::text, ',') in #{concat_ids})"))
end
end
end

Decidim::Budgets::Project.include(ProjectExtends)
113 changes: 113 additions & 0 deletions spec/models/decidim/budgets/project_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# frozen_string_literal: true

require "spec_helper"

module Decidim::Budgets
describe Project do
subject { project }

let(:project) { create(:project) }

include_examples "has reference"
include_examples "resourceable"

it { is_expected.to be_valid }
it { is_expected.to be_versioned }

context "without a budget" do
let(:project) { build(:project, budget: nil) }

it { is_expected.not_to be_valid }
end

context "when the scope is from another organization" do
let(:scope) { create(:scope) }
let(:project) { build(:project, scope: scope) }

it { is_expected.not_to be_valid }
end

context "when the category is from another organization" do
let(:category) { create(:category) }
let(:project) { build(:project, category: category) }

it { is_expected.not_to be_valid }
end

describe ".ordered_ids" do
let(:budget) { create(:budget, total_budget: 1_000_000) }
let(:category) { create(:category, participatory_space: budget.participatory_space) }
let(:projects) { create_list(:project, 50, budget: budget, budget_amount: 100_000, category: category) }
let(:test_ids) do
first = described_class.where(budget: budget).order(:id).pluck(:id)[0..3]
ids = described_class.where(budget: budget).pluck(:id).shuffle

# Put the first items at the end of the IDs array in order to get
# possibly "conflicting" matches for them at earlier array positions.
# As we have 50 projects, we should have IDs starting with 1, 2, 3 and 4
# which is why we put the first 4 items at the end.
(ids - first) + first
end

before do
# Reset the project IDs to start from 1 in order to get possibly
# "conflicting" ID sequences for the `.ordered_ids` call. In the past,
# e.g. IDs such as "2", and "23" (containing "2") would have caused the
# wrong order in case "23" comes first in the ordered IDs list.
ActiveRecord::Base.connection.reset_pk_sequence!(described_class.table_name)

# Create the projects after the sequence has been reset
projects
end

it "returns the correctly ordered projects" do
expect(described_class.ordered_ids(test_ids).pluck(:id)).to eq(test_ids)
end

it "returns the correctly ordered projects after filtering by category" do
expect(described_class.with_any_category([category.id]).ordered_ids(test_ids).pluck(:id)).to eq(test_ids)
end
end

describe "#orders_count" do
let(:project) { create(:project, budget_amount: 75_000_000) }
let(:order) { create(:order, budget: project.budget) }
let(:unfinished_order) { create(:order, budget: project.budget) }
let!(:line_item) { create(:line_item, project: project, order: order) }
let!(:line_item1) { create(:line_item, project: project, order: unfinished_order) }

it "return number of finished orders for this project" do
order.reload.update!(checked_out_at: Time.current)
expect(project.confirmed_orders_count).to eq(1)
end
end

describe "#users_to_notify_on_comment_created" do
let!(:follows) { create_list(:follow, 3, followable: subject) }

it "returns the followers" do
expect(subject.users_to_notify_on_comment_created).to match_array(follows.map(&:user))
end
end

describe "#selected?" do
let(:project) { create(:project, selected_at: selected_at) }

context "when selected_at is blank" do
let(:selected_at) { nil }

it "returns true" do
expect(project.selected?).to be false
end
end

context "when selected_at is present" do
let(:selected_at) { Time.current }

it "returns true" do
expect(project.selected?).to be true
end
end
end
end
end

0 comments on commit 04a1c7f

Please sign in to comment.