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 support for ORDER/GROUP BY, HAVING, and booleans in WHERE. #53

Merged
merged 1 commit into from
Jun 20, 2016
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
13 changes: 10 additions & 3 deletions lib/pg_query/parse.rb
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,16 @@ def load_tables_and_aliases! # rubocop:disable Metrics/CyclomaticComplexity
end
end

subselect_items += statement.values[0]['targetList'] if !statement.empty? && statement.values[0]['targetList']
subselect_items << statement.values[0]['whereClause'] if !statement.empty? && statement.values[0]['whereClause']
statement_value = statement.values[0]
unless statement.empty?
subselect_items.concat(statement_value['targetList']) if statement_value['targetList']
subselect_items << statement_value['whereClause'] if statement_value['whereClause']
subselect_items.concat(statement_value['sortClause'].collect { |h| h[SORT_BY]['node'] }) if statement_value['sortClause']
subselect_items.concat(statement_value['groupClause']) if statement_value['groupClause']
subselect_items << statement_value['havingClause'] if statement_value['havingClause']
end
end

# Find subselects in WHERE clause
next_item = subselect_items.shift
if next_item
case next_item.keys[0]
Expand All @@ -135,6 +140,8 @@ def load_tables_and_aliases! # rubocop:disable Metrics/CyclomaticComplexity
subselect_items << elem
end
end
when BOOL_EXPR
subselect_items.concat(next_item.values[0]['args'])
when RES_TARGET
subselect_items << next_item[RES_TARGET]['val']
when SUB_LINK
Expand Down
121 changes: 120 additions & 1 deletion spec/lib/parse_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@
end

# https://github.com/lfittl/pg_query/issues/38
it 'correctly finds nested tables' do
it 'correctly finds nested tables in select clause' do
query = described_class.parse("select u.email, (select count(*) from enrollments e where e.user_id = u.id) as num_enrollments from users u")
expect(query.warnings).to eq []
expect(query.tables).to eq ['users', 'enrollments']
Expand All @@ -627,6 +627,125 @@
expect(query.tables).to eq ['table_name']
end

it 'correctly finds nested tables in from clause' do
query = described_class.parse("select u.* from (select * from users) u")
expect(query.warnings).to eq []
expect(query.tables).to eq ['users']
end

it 'correctly finds nested tables in where clause' do
query = described_class.parse("select users.id from users where 1 = (select count(*) from user_roles)")
expect(query.warnings).to eq []
expect(query.tables).to eq ['users', 'user_roles']
end

it 'traverse boolean expressions in where clause' do
query = described_class.parse(<<-SQL)
select users.*
from users
where users.id IN (
select user_roles.user_id
from user_roles
) and (users.created_at between '2016-06-01' and '2016-06-30')
SQL
expect(query.warnings).to eq []
expect(query.tables).to eq ['users', 'user_roles']
end

it 'correctly finds nested tables in the order by clause' do
query = described_class.parse(<<-SQL)
select users.*
from users
order by (
select max(user_roles.role_id)
from user_roles
where user_roles.user_id = users.id
)
SQL
expect(query.warnings).to eq []
expect(query.tables).to eq ['users', 'user_roles']
end

it 'correctly finds nested tables in the order by clause with multiple entries' do
query = described_class.parse(<<-SQL)
select users.*
from users
order by (
select max(user_roles.role_id)
from user_roles
where user_roles.user_id = users.id
) asc, (
select max(user_logins.role_id)
from user_logins
where user_logins.user_id = users.id
) desc
SQL
expect(query.warnings).to eq []
expect(query.tables).to eq ['users', 'user_roles', 'user_logins']
end

it 'correctly finds nested tables in the group by clause' do
query = described_class.parse(<<-SQL)
select users.*
from users
group by (
select max(user_roles.role_id)
from user_roles
where user_roles.user_id = users.id
)
SQL
expect(query.warnings).to eq []
expect(query.tables).to eq ['users', 'user_roles']
end

it 'correctly finds nested tables in the group by clause with multiple entries' do
query = described_class.parse(<<-SQL)
select users.*
from users
group by (
select max(user_roles.role_id)
from user_roles
where user_roles.user_id = users.id
), (
select max(user_logins.role_id)
from user_logins
where user_logins.user_id = users.id
)
SQL
expect(query.warnings).to eq []
expect(query.tables).to eq ['users', 'user_roles', 'user_logins']
end

it 'correctly finds nested tables in the having clause' do
query = described_class.parse(<<-SQL)
select users.*
from users
group by users.id
having 1 > (
select count(user_roles.role_id)
from user_roles
where user_roles.user_id = users.id
)
SQL
expect(query.warnings).to eq []
expect(query.tables).to eq ['users', 'user_roles']
end

it 'correctly finds nested tables in the having clause with a boolean expression' do
query = described_class.parse(<<-SQL)
select users.*
from users
group by users.id
having true and 1 > (
select count(user_roles.role_id)
from user_roles
where user_roles.user_id = users.id
)
SQL
expect(query.warnings).to eq []
expect(query.tables).to eq ['users', 'user_roles']
end

it 'handles DROP TYPE' do
query = described_class.parse("DROP TYPE IF EXISTS repack.pk_something")
expect(query.warnings).to eq []
Expand Down