Class: MergeRequest::DiffCommitUser
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- MergeRequest::DiffCommitUser
- Defined in:
- app/models/merge_request/diff_commit_user.rb
Constant Summary
Constants inherited from ApplicationRecord
Constants included from ResetOnUnionError
ResetOnUnionError::MAX_RESET_PERIOD
Class Method Summary collapse
-
.bulk_find(pairs) ⇒ Object
Finds many (name, email) pairs in bulk.
-
.bulk_find_or_create(pairs) ⇒ Object
Finds or creates rows for the given pairs of names and Emails.
-
.find_or_create(name, email) ⇒ Object
Creates a new row, or returns an existing one if a row already exists.
-
.prepare(value) ⇒ Object
Prepares a value to be inserted into a column in the table ‘merge_request_diff_commit_users`.
Methods inherited from ApplicationRecord
cached_column_list, #create_or_load_association, declarative_enum, default_select_columns, id_in, id_not_in, iid_in, pluck_primary_key, primary_key_in, #readable_by?, safe_ensure_unique, safe_find_or_create_by, safe_find_or_create_by!, #to_ability_name, underscore, where_exists, where_not_exists, with_fast_read_statement_timeout, without_order
Methods included from SensitiveSerializableHash
Class Method Details
.bulk_find(pairs) ⇒ Object
Finds many (name, email) pairs in bulk.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'app/models/merge_request/diff_commit_user.rb', line 30 def self.bulk_find(pairs) queries = {} rows = [] pairs.each do |(name, email)| queries[[name, email]] = where(name: name, email: email).to_sql end # We may end up having to query many users. To ensure we don't hit any # query size limits, we get a fixed number of users at a time. queries.values.each_slice(1_000).map do |slice| rows.concat(from("(#{slice.join("\nUNION ALL\n")}) #{table_name}").to_a) end rows end |
.bulk_find_or_create(pairs) ⇒ Object
Finds or creates rows for the given pairs of names and Emails.
The ‘names_and_emails` argument must be an Array/Set of tuples like so:
[
[name, email],
[name, email],
...
]
This method expects that the names and Emails have already been trimmed to at most 512 characters.
The return value is a Hash that maps these tuples to instances of this model.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'app/models/merge_request/diff_commit_user.rb', line 62 def self.bulk_find_or_create(pairs) mapping = {} create = [] # Over time, fewer new rows need to be created. We take advantage of that # here by first finding all rows that already exist, using a limited number # of queries (in most cases only one query will be needed). bulk_find(pairs).each do |row| mapping[[row.name, row.email]] = row end pairs.each do |(name, email)| create << { name: name, email: email } unless mapping[[name, email]] end return mapping if create.empty? # Sometimes we may need to insert new users into the table. We do this in # bulk, so we only need one INSERT for all missing users. insert_all(create, returning: %w[id name email]).each do |row| mapping[[row['name'], row['email']]] = new(id: row['id'], name: row['name'], email: row['email']) end # It's possible for (name, email) pairs to be inserted concurrently, # resulting in the above insert not returning anything. Here we get any # remaining users that were created concurrently. bulk_find(pairs.reject { |pair| mapping.key?(pair) }).each do |row| mapping[[row.name, row.email]] = row end mapping end |
.find_or_create(name, email) ⇒ Object
Creates a new row, or returns an existing one if a row already exists.
23 24 25 26 27 |
# File 'app/models/merge_request/diff_commit_user.rb', line 23 def self.find_or_create(name, email) find_or_create_by!(name: name, email: email) rescue ActiveRecord::RecordNotUnique retry end |
.prepare(value) ⇒ Object
Prepares a value to be inserted into a column in the table ‘merge_request_diff_commit_users`. Values in this table are limited to 512 characters.
We treat empty strings as NULL values, as there’s no point in (for example) storing a row where both the name and Email are an empty string. In addition, if we treated them differently we could end up with two rows: one where field X is NULL, and one where field X is an empty string. This is redundant, so we avoid storing such data.
18 19 20 |
# File 'app/models/merge_request/diff_commit_user.rb', line 18 def self.prepare(value) value.present? ? value[0..511] : nil end |