|
1 | 1 | # Finds or creates ApplicationGroups for the given application and group_ids.
|
2 | 2 | class FindOrCreateApplicationGroups
|
3 |
| - |
4 |
| - lev_routine |
| 3 | + lev_routine transaction: :read_committed |
5 | 4 |
|
6 | 5 | protected
|
7 | 6 |
|
8 | 7 | def exec(application_id, group_ids)
|
9 |
| - application_groups = ApplicationGroup.where(application_id: application_id, |
10 |
| - group_id: group_ids) |
11 |
| - .preload(:group).to_a |
12 |
| - ag_group_ids = application_groups.collect{|ag| ag.group_id} |
| 8 | + outputs.application_groups = ApplicationGroup.where( |
| 9 | + application_id: application_id, group_id: group_ids |
| 10 | + ).to_a |
13 | 11 |
|
14 |
| - # There might be a way to make this more efficient |
15 |
| - group_ids.each do |group_id| |
16 |
| - unless ag_group_ids.include?(group_id) |
17 |
| - application_group = ApplicationGroup.create do |app_group| |
18 |
| - app_group.application_id = application_id |
19 |
| - app_group.group_id = group_id |
20 |
| - app_group.save! |
21 |
| - end |
22 |
| - application_groups << application_group |
23 |
| - end |
24 |
| - end |
| 12 | + missing_group_ids = group_ids - outputs.application_groups.map(&:group_id) |
| 13 | + return if missing_group_ids.empty? |
25 | 14 |
|
26 |
| - outputs[:application_groups] = application_groups |
27 |
| - end |
| 15 | + # Insert missing records |
| 16 | + # Returns newly-inserted records only |
| 17 | + # We could run this as the first query, but it would cause the id sequence to autoincrement |
| 18 | + # by the number of group_ids every time this routine is called |
| 19 | + # We can still do that if we switch the primary key to a uuid column |
| 20 | + new_records = ApplicationGroup.import( |
| 21 | + missing_group_ids.map do |group_id| |
| 22 | + ApplicationGroup.new(application_id: application_id, group_id: group_id) |
| 23 | + end, on_duplicate_key_ignore: true |
| 24 | + ).results |
| 25 | + outputs.application_groups += new_records |
28 | 26 |
|
| 27 | + existing_group_ids = missing_group_ids - new_records.map(&:group_id) |
| 28 | + return if existing_group_ids.empty? |
| 29 | + |
| 30 | + # Run the first query again in case another process or thread |
| 31 | + # inserted the missing records before us |
| 32 | + outputs.application_groups += ApplicationGroup.where( |
| 33 | + application_id: application_id, group_id: existing_group_ids |
| 34 | + ).to_a |
| 35 | + end |
29 | 36 | end
|
0 commit comments