Accept scalars, varargs, and arrays in where_display_id_in

Splat with a depth-1 flatten lets callers pass scalars, varargs, or a
pre-built array interchangeably. `Array(values)` would have been
misleading here — `Array([[1, "a"], 2])` leaves the inner array
intact and `map(&:to_s)` stringifies it as `"[1, \"a\"]"`, which
then misclassifies through the semantic-id branch. Bounded `flatten(1)`
absorbs the (scalar) and ([scalar, scalar]) shapes that production
code already uses while leaving deeper nesting alone, so the same
pathology produces no match rather than silently working.

Refs https://github.com/opf/openproject/pull/23202#discussion_r3235337043
This commit is contained in:
Kabiru Mwenja
2026-05-13 18:26:23 +03:00
parent 41cdfc8b77
commit c24e3cfab0
2 changed files with 11 additions and 5 deletions
@@ -111,11 +111,12 @@ module WorkPackage::SemanticIdentifier::FinderMethods
# semantic strings may be freely mixed; unknown values produce no match
# rather than poisoning the rest of the set.
#
# @param values [Array<String, Integer>, String, Integer] one or many
# display ids. A bare String/Integer is wrapped via Array() so callers
# can pass `where_display_id_in("PROJ-1")` and get a one-element relation.
def where_display_id_in(values)
values = Array(values).map(&:to_s)
# @param values [String, Integer, Array<String, Integer>] one or more
# display ids. Pass scalars (`where_display_id_in("PROJ-1")`), varargs
# (`where_display_id_in("PROJ-1", "PROJ-2")`), or a pre-built array
# (`where_display_id_in(ids)`) interchangeably.
def where_display_id_in(*values)
values = values.flatten(1).compact.map(&:to_s)
return none if values.empty?
semantic, numeric = values.partition { semantic_id?(it) }
@@ -394,6 +394,11 @@ RSpec.describe WorkPackage::SemanticIdentifier do
expect(WorkPackage.where_display_id_in("MYPROJ-1")).to contain_exactly(work_package)
end
it "accepts identifiers as varargs" do
expect(WorkPackage.where_display_id_in("MYPROJ-1", "MYPROJ-2"))
.to contain_exactly(work_package, work_package2)
end
it "resolves a single numeric string" do
expect(WorkPackage.where_display_id_in([work_package.id.to_s])).to contain_exactly(work_package)
end