Import switches
- ImportSystem builds a mapping of data file HID to current system HID - Switches in a data file are reconciled with system members' actual IDs using this mapping - SwitchStore provides a RegisterSwitches method to register multiple switches - RegisterSwitches only imports a switch if one does not exist with the same timestamp - The number of switches created is logged
This commit is contained in:
		| @@ -1,8 +1,10 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
| using Newtonsoft.Json; | ||||
| using NodaTime; | ||||
| using NodaTime.Text; | ||||
| using Serilog; | ||||
|  | ||||
| namespace PluralKit.Bot | ||||
| @@ -73,6 +75,7 @@ namespace PluralKit.Bot | ||||
|             // which probably means refactoring SystemStore.Save and friends etc | ||||
|              | ||||
|             var result = new ImportResult {AddedNames = new List<string>(), ModifiedNames = new List<string>()}; | ||||
|             var hidMapping = new Dictionary<string, PKMember>(); | ||||
|  | ||||
|             // If we don't already have a system to save to, create one | ||||
|             if (system == null) system = await _systems.Create(data.Name); | ||||
| @@ -116,6 +119,10 @@ namespace PluralKit.Bot | ||||
|                     result.ModifiedNames.Add(dataMember.Name); | ||||
|                 } | ||||
|  | ||||
|                 // Keep track of what the data file's member ID maps to for switch import | ||||
|                 if (!hidMapping.ContainsKey(dataMember.Id)) | ||||
|                     hidMapping.Add(dataMember.Id, member); | ||||
|  | ||||
|                 // Apply member info | ||||
|                 member.Name = dataMember.Name; | ||||
|                 if (dataMember.DisplayName != null) member.DisplayName = dataMember.DisplayName; | ||||
| @@ -136,10 +143,22 @@ namespace PluralKit.Bot | ||||
|  | ||||
|                 await _members.Save(member); | ||||
|             } | ||||
|              | ||||
|             _logger.Information("Imported system {System}", system.Id); | ||||
|  | ||||
|             // TODO: import switches, too? | ||||
|             // Re-map the switch members in the likely case IDs have changed | ||||
|             var mappedSwitches = new List<Tuple<Instant, ICollection<PKMember>>>(); | ||||
|             foreach (var sw in data.Switches) | ||||
|             { | ||||
|                 var timestamp = InstantPattern.ExtendedIso.Parse(sw.Timestamp).Value; | ||||
|                 var swMembers = new List<PKMember>(); | ||||
|                 swMembers.AddRange(sw.Members.Select(x => | ||||
|                     hidMapping.FirstOrDefault(y => y.Key.Equals(x)).Value)); | ||||
|                 var mapped = new Tuple<Instant, ICollection<PKMember>>(timestamp, swMembers); | ||||
|                 mappedSwitches.Add(mapped); | ||||
|             } | ||||
|             // Import switches | ||||
|             await _switches.RegisterSwitches(system, mappedSwitches); | ||||
|  | ||||
|             _logger.Information("Imported system {System}", system.Id); | ||||
|  | ||||
|             result.System = system; | ||||
|             return result; | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
| @@ -294,6 +295,40 @@ namespace PluralKit { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public async Task RegisterSwitches(PKSystem system, ICollection<Tuple<Instant, ICollection<PKMember>>> switches) | ||||
|         { | ||||
|             // Use a transaction here since we're doing multiple executed commands in one | ||||
|             using (var conn = await _conn.Obtain()) | ||||
|             using (var tx = conn.BeginTransaction()) | ||||
|             { | ||||
|                 foreach (var s in switches) | ||||
|                 { | ||||
|                     // First, we insert the switch itself | ||||
|                     var sw = await conn.QueryFirstOrDefaultAsync<PKSwitch>( | ||||
|                             @"insert into switches(system, timestamp) | ||||
|                             select @System, @Timestamp | ||||
|                             where not exists ( | ||||
|                                 select * from switches | ||||
|                                 where system = @System and timestamp::timestamp(0) = @Timestamp | ||||
|                                 limit 1 | ||||
|                             ) | ||||
|                             returning *", | ||||
|                         new { System = system.Id, Timestamp = s.Item1 }); | ||||
|  | ||||
|                     // If we inserted a switch, also insert each member in the switch in the switch_members table | ||||
|                     if (sw != null && s.Item2.Any()) | ||||
|                         await conn.ExecuteAsync( | ||||
|                             "insert into switch_members(switch, member) select @Switch, * FROM unnest(@Members)", | ||||
|                             new { Switch = sw.Id, Members = s.Item2.Select(x => x.Id).ToArray() }); | ||||
|                 } | ||||
|  | ||||
|                 // Finally we commit the tx, since the using block will otherwise rollback it | ||||
|                 tx.Commit(); | ||||
|  | ||||
|                 _logger.Information("Registered {SwitchCount} switches in system {System}", switches.Count, system.Id); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public async Task<IEnumerable<PKSwitch>> GetSwitches(PKSystem system, int count = 9999999) | ||||
|         { | ||||
|             // TODO: refactor the PKSwitch data structure to somehow include a hydrated member list | ||||
|   | ||||
		Reference in New Issue
	
	Block a user