Skip to content

Commit

Permalink
Improve handling of boolean type casts
Browse files Browse the repository at this point in the history
Edited By: Lukas Fittl <[email protected]>
  • Loading branch information
himanshu-pro authored and lfittl committed Dec 27, 2020
1 parent 36ad3cc commit 5f947fc
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 5 deletions.
28 changes: 24 additions & 4 deletions lib/pg_query/deparse.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1268,10 +1268,30 @@ def deparse_update(node)
output.join(' ')
end

def deparse_typecast(node) # rubocop:disable Metrics/CyclomaticComplexity
if deparse_item(node['typeName']) == 'boolean' || deparse_item(node['typeName']) == 'bool'
return 'true' if deparse_item(node['arg']) == "'t'" || deparse_item(node['arg']) == 'true'
return 'false' if deparse_item(node['arg']) == "'f'" || deparse_item(node['arg']) == 'false'
# Builds a properly-qualified reference to a built-in Postgres type.
#
# Inspired by SystemTypeName in Postgres' gram.y, but without node name
# and locations, to simplify comparison.
def make_system_type_name(name)
{
'names' => [
{ 'String' => { 'str' => 'pg_catalog' } },
{ 'String' => { 'str' => name } }
],
'typemod' => -1
}
end

def make_string(str)
{ 'String' => { 'str' => str } }
end

def deparse_typecast(node)
# Handle "bool" or "false" in the statement, which is represented as a typecast
# (other boolean casts should be represented as a cast, i.e. don't need special handling)
if node['arg'][A_CONST] && node['typeName'][TYPE_NAME].slice('names', 'typemod') == make_system_type_name('bool')
return 'true' if node['arg'][A_CONST]['val'] == make_string('t')
return 'false' if node['arg'][A_CONST]['val'] == make_string('f')
end

context = true if node['arg']['A_Expr']
Expand Down
21 changes: 20 additions & 1 deletion spec/lib/pg_query/deparse_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -595,11 +595,30 @@
it { is_expected.to eq query }
end

context 'boolean' do
context 'boolean column reference' do
let(:query) { "SELECT \"table_field\"::bool, \"table_field\"::boolean FROM \"t\"" }

it { is_expected.to eq query }
end

context 'boolean bool value cast' do
let(:query) { "SELECT true, false" }

it { is_expected.to eq query }
end

context 'boolean string value cast' do
let(:query) { "SELECT 't'::boolean, 'f'::boolean" }

# The AST is identical to the more common "SELECT true" case, which is why we return the short-form in that case
it { is_expected.to eq "SELECT true, false" }
end

context 'boolean integer value cast' do
let(:query) { "SELECT 1::boolean, 0::boolean" }

it { is_expected.to eq query }
end
end

context 'param ref' do
Expand Down

0 comments on commit 5f947fc

Please sign in to comment.