Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Queryable#group_count functionality #778

Merged
merged 1 commit into from
Jan 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions spec/avram/queryable_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -856,6 +856,96 @@ describe Avram::Queryable do
end
end

describe "#group_count" do
context "when no records exist" do
it "0 grouped columns returns { [] => 0 }" do
query = UserQuery.new

query.group_count.should eq({[] of String => 0})
end

# Return an empty set when grouped, which mirrors
# postgresql handling of empty aggregated results
it "1 grouped columns returns { [] => 0 }" do
query = UserQuery.new.group(&.name)

query.group_count.should eq({} of Array(PG::PGValue) => Int64)
end

it "2 grouped columns returns { [] => 0 }" do
query = UserQuery.new.group(&.name)

query.group_count.should eq({} of Array(PG::PGValue) => Int64)
end
end

context "when 1 record exists" do
before_each do
UserFactory.create do |user|
user.age(32)
user.name("Taylor")
end
end

it "0 grouped columns returns { [] => 1 }" do
query = UserQuery.new

query.group_count.should eq({[] of String => 1})
end

it "1 grouped column (age) returns grouping" do
query = UserQuery.new.group &.age

query.group_count.should eq({[32] => 1})
end

it "2 grouped columns (age, name) returns grouping" do
query = UserQuery.new.group(&.age).group(&.name)

query.group_count.should eq({[32, "Taylor"] => 1})
end
end

context "when matrix [32, Daniel] [32, Taylor] [32, Taylor] [44, Shakira]" do
grepsedawk marked this conversation as resolved.
Show resolved Hide resolved
before_each do
UserFactory.create do |user|
user.age(32)
user.name("Daniel")
end
UserFactory.create do |user|
user.age(32)
user.name("Taylor")
end
UserFactory.create do |user|
user.age(32)
user.name("Taylor")
end
UserFactory.create do |user|
user.age(44)
user.name("Shakira")
end
end

it "0 grouped columns returns { [] => 4 }" do
query = UserQuery.new

query.group_count.should eq({[] of String => 4})
end

it "1 grouped columns (age) returns grouping" do
query = UserQuery.new.group &.age

query.group_count.should eq({[32] => 3, [44] => 1})
end

it "1 grouped columns (age, name) returns grouping" do
query = UserQuery.new.group(&.age).group(&.name)

query.group_count.should eq({[32, "Daniel"] => 1, [32, "Taylor"] => 2, [44, "Shakira"] => 1})
end
end
end

describe "#not" do
context "with an argument" do
it "negates the given where condition as 'equal'" do
Expand Down
5 changes: 5 additions & 0 deletions src/avram/query_builder.cr
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,11 @@ class Avram::QueryBuilder
.map(&.split('.').last)
end

def select_direct(selection : Array(ColumnName))
grepsedawk marked this conversation as resolved.
Show resolved Hide resolved
@selections = selection.join(", ")
self
end

def select(selection : Array(ColumnName))
@selections = selection.join(", ") { |column| "#{@table}.#{column}" }
self
Expand Down
16 changes: 16 additions & 0 deletions src/avram/queryable.cr
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,22 @@ module Avram::Queryable(T)
end
end

# Remove when PG::PGValue matches rs.read possibilities
alias PGValue = Bool | Float32 | Float64 | Int16 | Int32 | Int64 | PG::Numeric | String | Time | UUID | Nil

def group_count : Hash(Array(PGValue), Int64)
database.query_all(
query.select_direct(query.groups + ["COUNT(*)"]).statement,
args: query.args,
queryable: schema_class.name,
) do |rs|
{
query.groups.map { rs.read PGValue },
rs.read Int64,
}
grepsedawk marked this conversation as resolved.
Show resolved Hide resolved
end.to_h
end

def each
results.each do |result|
yield result
Expand Down