diff --git a/changelog.yml b/changelog.yml index 17937e1f..51e8f412 100644 --- a/changelog.yml +++ b/changelog.yml @@ -12,6 +12,11 @@ #402) (@solnic)" - "[internal] `Gateway#command` is now used to instantiate sql-specific commands (via #402) (@solnic)" +- version: 3.6.3 + summary: + date: 2024-05-06 + fixed: + - "Fix using `.filter` with a block for aggregate functions (@flash-gordon)" - version: 3.6.2 summary: date: 2024-01-09 diff --git a/lib/rom/sql/projection_dsl.rb b/lib/rom/sql/projection_dsl.rb index b97cbdf3..7215f682 100644 --- a/lib/rom/sql/projection_dsl.rb +++ b/lib/rom/sql/projection_dsl.rb @@ -37,7 +37,7 @@ def `(value) # # @api public def function(name, *attrs) - ::ROM::SQL::Function.new(::ROM::Types::Any, schema: schema).public_send(name, *attrs) + ::ROM::SQL::Function.new(::ROM::Types::Any).meta(schema: schema).public_send(name, *attrs) end alias_method :f, :function @@ -57,7 +57,7 @@ def method_missing(meth, *args, &block) if type if args.empty? - ::ROM::SQL::Function.new(type, schema: schema) + ::ROM::SQL::Function.new(type).meta(schema: schema) else ::ROM::SQL::Attribute[type].value(args[0]) end diff --git a/lib/rom/sql/restriction_dsl.rb b/lib/rom/sql/restriction_dsl.rb index 63790346..c3d4b6a2 100644 --- a/lib/rom/sql/restriction_dsl.rb +++ b/lib/rom/sql/restriction_dsl.rb @@ -27,7 +27,7 @@ def method_missing(meth, *args, &block) type = type(meth) if type - ::ROM::SQL::Function.new(type) + ::ROM::SQL::Function.new(type).meta(schema: schema) else ::Sequel::VIRTUAL_ROW.__send__(meth, *args, &block) end diff --git a/spec/unit/projection_dsl_spec.rb b/spec/unit/projection_dsl_spec.rb index 08878f13..8ae5f3c3 100644 --- a/spec/unit/projection_dsl_spec.rb +++ b/spec/unit/projection_dsl_spec.rb @@ -79,6 +79,14 @@ expect(literals).to eql([%(IF(("id" > 0), "id", NULL) AS "id")]) end + it "supports functions with filter clause using blocks" do + literals = dsl + .call { function(:count, :id).filter { id > 0 }.as(:count) } + .map { |attr| attr.sql_literal(ds) } + + expect(literals).to eql([%(COUNT("id") FILTER (WHERE ("id" > 0)) AS "count")]) + end + it "supports functions with arg being a qualified attribute" do literals = dsl .call { integer.count(id.qualified).as(:count) } @@ -130,17 +138,25 @@ end it "responds to methods matching type identifiers" do - expect(dsl.integer).to eql(ROM::SQL::Types::Integer) - expect(dsl.string).to eql(ROM::SQL::Types::String) - expect(dsl.bool).to eql(ROM::SQL::Types::Bool) + expect(dsl.integer).to eql(ROM::SQL::Function.new( + ROM::SQL::Types::Integer + ).meta(schema: schema)) + expect(dsl.string).to eql(ROM::SQL::Function.new( + ROM::SQL::Types::String + ).meta(schema: schema)) + expect(dsl.bool).to eql(ROM::SQL::Function.new( + ROM::SQL::Types::Bool + ).meta(schema: schema)) end it "responds to methods matching type names" do - expect(dsl.DateTime).to eql(ROM::SQL::Types::DateTime) + expect(dsl.DateTime).to eql( + ROM::SQL::Function.new(ROM::SQL::Types::DateTime).meta(schema: schema) + ) end it "returns sql functions with return type specified" do - function = ROM::SQL::Function.new(ROM::SQL::Types::String).upper(schema[:name]) + function = ROM::SQL::Function.new(ROM::SQL::Types::String).meta(schema: schema).upper(schema[:name]) expect(dsl.string.upper(schema[:name])).to eql(function) end diff --git a/spec/unit/restriction_dsl_spec.rb b/spec/unit/restriction_dsl_spec.rb index d9347079..bb941eb1 100644 --- a/spec/unit/restriction_dsl_spec.rb +++ b/spec/unit/restriction_dsl_spec.rb @@ -21,6 +21,12 @@ it "evaluates the block and returns an SQL expression" do expect(conn[:users].literal(dsl.call { count(id) >= 3 })).to eql("(count(`id`) >= 3)") end + + it "supports using blocks in filter clause" do + expect(conn[:users].literal(dsl.call { integer.count(id).filter { id > 0 } >= 3 })).to eql( + "(COUNT(`id`) FILTER (WHERE (`id` > 0)) >= 3)" + ) + end end describe "#method_missing" do