summaryrefslogtreecommitdiff
path: root/lib/gitlab/database
diff options
context:
space:
mode:
authorTimothy Andrew <mail@timothyandrew.net>2016-09-20 18:13:11 +0530
committerTimothy Andrew <mail@timothyandrew.net>2016-09-20 18:13:11 +0530
commit71d4bf721be6cd57ab3480bc5efb11a91d6e1891 (patch)
tree81b567b59729128e38121f4bb7286383945aa99b /lib/gitlab/database
parent6f194e28e4fd8380432420b2b525b134ddb18a3d (diff)
downloadgitlab-ce-71d4bf721be6cd57ab3480bc5efb11a91d6e1891.tar.gz
Implement (some) comments from @DouweM's review.
- Move things common to `Issue` and `MergeRequest` into `Issuable` - Move more database-specific functions into `Gitlab::Database` - Indentation changes and other minor refactorings.
Diffstat (limited to 'lib/gitlab/database')
-rw-r--r--lib/gitlab/database/date_time.rb27
-rw-r--r--lib/gitlab/database/median.rb58
2 files changed, 64 insertions, 21 deletions
diff --git a/lib/gitlab/database/date_time.rb b/lib/gitlab/database/date_time.rb
new file mode 100644
index 00000000000..b6a89f715fd
--- /dev/null
+++ b/lib/gitlab/database/date_time.rb
@@ -0,0 +1,27 @@
+module Gitlab
+ module Database
+ module DateTime
+ # Find the first of the `end_time_attrs` that isn't `NULL`. Subtract from it
+ # the first of the `start_time_attrs` that isn't NULL. `SELECT` the resulting interval
+ # along with an alias specified by the `as` parameter.
+ #
+ # Note: For MySQL, the interval is returned in seconds.
+ # For PostgreSQL, the interval is returned as an INTERVAL type.
+ def subtract_datetimes(query_so_far, end_time_attrs, start_time_attrs, as)
+ diff_fn = if Gitlab::Database.postgresql?
+ Arel::Nodes::Subtraction.new(
+ Arel::Nodes::NamedFunction.new("COALESCE", Array.wrap(end_time_attrs)),
+ Arel::Nodes::NamedFunction.new("COALESCE", Array.wrap(start_time_attrs)))
+ elsif Gitlab::Database.mysql?
+ Arel::Nodes::NamedFunction.new(
+ "TIMESTAMPDIFF",
+ [Arel.sql('second'),
+ Arel::Nodes::NamedFunction.new("COALESCE", Array.wrap(start_time_attrs)),
+ Arel::Nodes::NamedFunction.new("COALESCE", Array.wrap(end_time_attrs))])
+ end
+
+ query_so_far.project(diff_fn.as(as))
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/median.rb b/lib/gitlab/database/median.rb
index 3ede0c6acd9..21b4c043655 100644
--- a/lib/gitlab/database/median.rb
+++ b/lib/gitlab/database/median.rb
@@ -3,13 +3,22 @@ module Gitlab
module Database
module Median
def median_datetime(arel_table, query_so_far, column_sym)
- case ActiveRecord::Base.connection.adapter_name
- when 'PostgreSQL'
+ if Gitlab::Database.postgresql?
pg_median_datetime(arel_table, query_so_far, column_sym)
- when 'Mysql2'
+ elsif Gitlab::Database.mysql?
mysql_median_datetime(arel_table, query_so_far, column_sym)
- else
- raise NotImplementedError, "We haven't implemented a database median strategy for your database type."
+ end
+ end
+
+ def extract_median(results)
+ result = results.compact.first
+
+ if Gitlab::Database.postgresql?
+ result = result.first.presence
+ median = result['median'] if result
+ median.to_f if median
+ elsif Gitlab::Database.mysql?
+ result.to_a.flatten.first
end
end
@@ -17,17 +26,23 @@ module Gitlab
query = arel_table.
from(arel_table.project(Arel.sql('*')).order(arel_table[column_sym]).as(arel_table.table_name)).
project(average([arel_table[column_sym]], 'median')).
- where(Arel::Nodes::Between.new(Arel.sql("(select @row_id := @row_id + 1)"),
- Arel::Nodes::And.new([Arel.sql('@ct/2.0'),
- Arel.sql('@ct/2.0 + 1')]))).
+ where(Arel::Nodes::Between.new(
+ Arel.sql("(select @row_id := @row_id + 1)"),
+ Arel::Nodes::And.new(
+ [Arel.sql('@ct/2.0'),
+ Arel.sql('@ct/2.0 + 1')]
+ )
+ )).
# Disallow negative values
where(arel_table[column_sym].gteq(0))
- [Arel.sql("CREATE TEMPORARY TABLE IF NOT EXISTS #{query_so_far.to_sql}"),
- Arel.sql("set @ct := (select count(1) from #{arel_table.table_name});"),
- Arel.sql("set @row_id := 0;"),
- query,
- Arel.sql("DROP TEMPORARY TABLE IF EXISTS #{arel_table.table_name};")]
+ [
+ Arel.sql("CREATE TEMPORARY TABLE IF NOT EXISTS #{query_so_far.to_sql}"),
+ Arel.sql("set @ct := (select count(1) from #{arel_table.table_name});"),
+ Arel.sql("set @row_id := 0;"),
+ query,
+ Arel.sql("DROP TEMPORARY TABLE IF EXISTS #{arel_table.table_name};")
+ ]
end
def pg_median_datetime(arel_table, query_so_far, column_sym)
@@ -42,14 +57,15 @@ module Gitlab
# 9 | 2 | 3
# 15 | 3 | 3
cte_table = Arel::Table.new("ordered_records")
- cte = Arel::Nodes::As.new(cte_table,
- arel_table.
- project(arel_table[column_sym].as(column_sym.to_s),
- Arel::Nodes::Over.new(Arel::Nodes::NamedFunction.new("row_number", []),
- Arel::Nodes::Window.new.order(arel_table[column_sym])).as('row_id'),
- arel_table.project("COUNT(1)").as('ct')).
- # Disallow negative values
- where(arel_table[column_sym].gteq(zero_interval)))
+ cte = Arel::Nodes::As.new(
+ cte_table,
+ arel_table.
+ project(arel_table[column_sym].as(column_sym.to_s),
+ Arel::Nodes::Over.new(Arel::Nodes::NamedFunction.new("row_number", []),
+ Arel::Nodes::Window.new.order(arel_table[column_sym])).as('row_id'),
+ arel_table.project("COUNT(1)").as('ct')).
+ # Disallow negative values
+ where(arel_table[column_sym].gteq(zero_interval)))
# From the CTE, select either the middle row or the middle two rows (this is accomplished
# by 'where cte.row_id between cte.ct / 2.0 AND cte.ct / 2.0 + 1'). Find the average of the