diff options
author | Andreas Brandl <abrandl@gitlab.com> | 2018-02-19 20:28:11 +0300 |
---|---|---|
committer | Andreas Brandl <abrandl@gitlab.com> | 2018-02-20 20:07:39 +0300 |
commit | c2ae4a6399903c30686aa8e8e6ed52fcd8d8214c (patch) | |
tree | b41dab2f75a9d9d684917cd586ba877eee5fa551 /app/finders | |
parent | df7d65a7aa213834b25f9480d6debc22c6315630 (diff) |
Use DISTINCT ON and translate to MySQL.
Realized window functions are not available in older MySQL versions
either.
Falling back to DISTINCT ON for postgresql and a convoluted translation
for MySQL.
Diffstat (limited to 'app/finders')
-rw-r--r-- | app/finders/members_finder.rb | 50 |
1 files changed, 34 insertions, 16 deletions
diff --git a/app/finders/members_finder.rb b/app/finders/members_finder.rb index fc6ca463a90..271d846b269 100644 --- a/app/finders/members_finder.rb +++ b/app/finders/members_finder.rb @@ -17,22 +17,7 @@ class MembersFinder union = Gitlab::SQL::Union.new([project_members, group_members], remove_duplicates: false) - # We're interested in a list of members without duplicates by user_id. - # We prefer project members over group members, project members should go first. - # - # We could have used a DISTINCT ON here, but MySQL does not support this. - sql = <<-SQL - SELECT member_numbered.* - FROM ( - SELECT - member_union.*, - ROW_NUMBER() OVER ( - PARTITION BY user_id ORDER BY CASE WHEN type = 'ProjectMember' THEN 1 WHEN type = 'GroupMember' THEN 2 ELSE 3 END - ) AS row_number - FROM (#{union.to_sql}) AS member_union - ) AS member_numbered - WHERE row_number = 1 - SQL + sql = distinct_on(union) Member.from("(#{sql}) AS #{Member.table_name}") else @@ -43,4 +28,37 @@ class MembersFinder def can?(*args) Ability.allowed?(*args) end + + private + + def distinct_on(union) + # We're interested in a list of members without duplicates by user_id. + # We prefer project members over group members, project members should go first. + if Gitlab::Database.postgresql? + <<~SQL + SELECT DISTINCT ON (user_id, invite_email) member_union.* + FROM (#{union.to_sql}) AS member_union + ORDER BY + user_id, invite_email, + CASE WHEN type = 'ProjectMember' THEN 1 WHEN type = 'GroupMember' THEN 2 ELSE 3 END + SQL + else + # Older versions of MySQL do not support window functions (and DISTINCT ON is postgres-specific). + <<~SQL + SELECT t1.* + FROM (#{union.to_sql}) AS t1 + JOIN ( + SELECT + COALESCE(user_id, -1) AS user_id, + COALESCE(invite_email, 'NULL') AS invite_email, + MIN(CASE WHEN type = 'ProjectMember' THEN 1 WHEN type = 'GroupMember' THEN 2 ELSE 3 END) AS type_number + FROM + (#{union.to_sql}) AS t3 + GROUP BY COALESCE(user_id, -1), COALESCE(invite_email, 'NULL') + ) AS t2 ON COALESCE(t1.user_id, -1) = t2.user_id + AND COALESCE(t1.invite_email, 'NULL') = t2.invite_email + AND CASE WHEN t1.type = 'ProjectMember' THEN 1 WHEN t1.type = 'GroupMember' THEN 2 ELSE 3 END = t2.type_number + SQL + end + end end |