Skip to content

Commit

Permalink
Fixes #1038: type cast fails in select_min/max (#1040)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidepaolotua committed May 15, 2024
1 parent bc2ad7b commit 52e7521
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 4 deletions.
32 changes: 32 additions & 0 deletions spec/avram/queryable_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,22 @@ describe Avram::Queryable do
min.should eq 1
end

it "works with strings" do
UserFactory.create &.name("Third")
UserFactory.create &.name("Second")
UserFactory.create &.name("First")
min = UserQuery.new.name.select_min
min.should eq "First"
end

it "works with floats" do
UserFactory.create &.average_score(0.7)
UserFactory.create &.average_score(0.71)
UserFactory.create &.average_score(0.52)
min = UserQuery.new.average_score.select_min
min.should eq 0.52
end

it "works with chained where clauses" do
UserFactory.create &.age(2)
UserFactory.create &.age(1)
Expand Down Expand Up @@ -648,6 +664,22 @@ describe Avram::Queryable do
max.should eq 3
end

it "works with strings" do
UserFactory.create &.name("Third")
UserFactory.create &.name("Second")
UserFactory.create &.name("First")
max = UserQuery.new.name.select_max
max.should eq "Third"
end

it "works with floats" do
UserFactory.create &.average_score(0.7)
UserFactory.create &.average_score(0.71)
UserFactory.create &.average_score(0.52)
max = UserQuery.new.average_score.select_max
max.should eq 0.71
end

it "works with chained where clauses" do
UserFactory.create &.age(2)
UserFactory.create &.age(1)
Expand Down
20 changes: 16 additions & 4 deletions src/avram/criteria.cr
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,12 @@ class Avram::Criteria(T, V)
add_clause(Avram::Where::LessThanOrEqualTo.new(column, V.adapter.to_db!(value)))
end

def select_min : V?
rows.exec_scalar(&.select_min(column)).as(V?)
def select_min
to_expected_type(rows.exec_scalar(&.select_min(column)))
end

def select_max : V?
rows.exec_scalar(&.select_max(column)).as(V?)
def select_max
to_expected_type(rows.exec_scalar(&.select_max(column)))
end

def select_average : Float64?
Expand Down Expand Up @@ -187,6 +187,18 @@ class Avram::Criteria(T, V)
end
end

# :nodoc:
# given the value in input it casts it to the expected output type (e.g: an PG::Int becomes a Int)
private def to_expected_type(value)
value.as(V?)
end

# :nodoc:
# special case: PG::Numeric cannot be cast to float, so we need to explicitly call to_f on it
private def to_expected_type(value : PG::Numeric?)
value.try &.to_f64
end

macro define_function_criteria(name, output_type = V, sql_name = nil)
{% sql_name = sql_name ? sql_name.id : name.id.upcase %}
def {{name}}
Expand Down

0 comments on commit 52e7521

Please sign in to comment.