/// <inheritdoc/> public async Task <UserSettings> GetAsync(string userId) { // If the user isn't logged in, use the default settings if (string.IsNullOrEmpty(userId)) { return(new UserSettings()); } var userSettings = new UserSettings(); var parameters = new Dictionary <string, object> { { "@UserId", userId }, }; const string GetUserSettingsCommandText = @" SELECT SettingId, SettingValue FROM UserSettings WHERE UserId = @UserId"; using (var command = this.databaseCommandFactory.Create( GetUserSettingsCommandText, parameters)) using (var reader = await command.ExecuteReaderAsync()) { while (reader.Read()) { var settingId = Convert.ToByte(reader["SettingId"]); var settingValue = reader["SettingValue"].ToString(); switch (settingId) { case UserSettingsConstants.PlayStyle: userSettings.PlayStyle = Enum.TryParse <PlayStyle>(settingValue, out var playStyle) ? new PlayStyle?(playStyle) : null; break; case UserSettingsConstants.UseScientificNotation: userSettings.UseScientificNotation = bool.TryParse(settingValue, out var useScientificNotation) ? new bool?(useScientificNotation) : null; break; case UserSettingsConstants.ScientificNotationThreshold: userSettings.ScientificNotationThreshold = int.TryParse(settingValue, out var scientificNotationThreshold) ? new int?(scientificNotationThreshold) : null; break; case UserSettingsConstants.UseLogarithmicGraphScale: userSettings.UseLogarithmicGraphScale = bool.TryParse(settingValue, out var useLogarithmicGraphScale) ? new bool?(useLogarithmicGraphScale) : null; break; case UserSettingsConstants.LogarithmicGraphScaleThreshold: userSettings.LogarithmicGraphScaleThreshold = int.TryParse(settingValue, out var logarithmicGraphScaleThreshold) ? new int?(logarithmicGraphScaleThreshold) : null; break; case UserSettingsConstants.HybridRatio: userSettings.HybridRatio = double.TryParse(settingValue, out var hybridRatio) ? new double?(hybridRatio) : null; break; case UserSettingsConstants.Theme: userSettings.Theme = Enum.TryParse <SiteThemeType>(settingValue, out var theme) ? new SiteThemeType?(theme) : null; break; case UserSettingsConstants.ShouldLevelSkillAncients: userSettings.ShouldLevelSkillAncients = bool.TryParse(settingValue, out var shouldLevelSkillAncients) ? new bool?(shouldLevelSkillAncients) : null; break; case UserSettingsConstants.SkillAncientBaseAncient: userSettings.SkillAncientBaseAncient = int.TryParse(settingValue, out var skillAncientBaseAncient) ? new int?(skillAncientBaseAncient) : null; break; case UserSettingsConstants.SkillAncientLevelDiff: userSettings.SkillAncientLevelDiff = int.TryParse(settingValue, out var skillAncientLevelDiff) ? new int?(skillAncientLevelDiff) : null; break; case UserSettingsConstants.GraphSpacingType: userSettings.GraphSpacingType = Enum.TryParse <GraphSpacingType>(settingValue, out var graphSpacingType) ? new GraphSpacingType?(graphSpacingType) : null; break; } } } return(userSettings); }
/// <inheritdoc/> public async Task PatchAsync(string userId, UserSettings userSettings) { if (string.IsNullOrEmpty(userId)) { throw new ArgumentNullException(nameof(userId)); } if (userSettings == null) { throw new ArgumentNullException(nameof(userSettings)); } /* Build a query that looks like this: * MERGE INTO UserSettings WITH (HOLDLOCK) * USING * (VALUES (@UserId, 1, @Value1), (@UserId, 2, @Value2), ... ) * AS Input(UserId, SettingId, SettingValue) * ON UserSettings.UserId = Input.UserId * AND UserSettings.SettingId = Input.SettingId * WHEN MATCHED THEN * UPDATE * SET * SettingValue = Input.SettingValue * WHEN NOT MATCHED THEN * INSERT (UserId, SettingId, SettingValue) * VALUES (Input.UserId, Input.SettingId, Input.SettingValue);"); */ var setUserSettingsCommandText = new StringBuilder(); var parameters = new Dictionary <string, object>() { { "@UserId", userId }, }; var isFirst = true; setUserSettingsCommandText.Append(@" MERGE INTO UserSettings WITH (HOLDLOCK) USING ( VALUES "); void AppendSetting(byte settingId, string settingValue) { if (string.IsNullOrEmpty(settingValue)) { return; } if (!isFirst) { setUserSettingsCommandText.Append(","); } // No need to sanitize settingId as it's just a number setUserSettingsCommandText.Append("(@UserId,"); setUserSettingsCommandText.Append(settingId); setUserSettingsCommandText.Append(",@Value"); setUserSettingsCommandText.Append(settingId); setUserSettingsCommandText.Append(")"); parameters.Add("@Value" + settingId, settingValue); isFirst = false; } AppendSetting(UserSettingsConstants.PlayStyle, userSettings.PlayStyle?.ToString()); AppendSetting(UserSettingsConstants.UseScientificNotation, userSettings.UseScientificNotation?.ToString()); AppendSetting(UserSettingsConstants.ScientificNotationThreshold, userSettings.ScientificNotationThreshold?.ToString()); AppendSetting(UserSettingsConstants.UseLogarithmicGraphScale, userSettings.UseLogarithmicGraphScale?.ToString()); AppendSetting(UserSettingsConstants.LogarithmicGraphScaleThreshold, userSettings.LogarithmicGraphScaleThreshold?.ToString()); AppendSetting(UserSettingsConstants.HybridRatio, userSettings.HybridRatio?.ToString()); AppendSetting(UserSettingsConstants.Theme, userSettings.Theme?.ToString()); AppendSetting(UserSettingsConstants.ShouldLevelSkillAncients, userSettings.ShouldLevelSkillAncients?.ToString()); AppendSetting(UserSettingsConstants.SkillAncientBaseAncient, userSettings.SkillAncientBaseAncient?.ToString()); AppendSetting(UserSettingsConstants.SkillAncientLevelDiff, userSettings.SkillAncientLevelDiff?.ToString()); AppendSetting(UserSettingsConstants.GraphSpacingType, userSettings.GraphSpacingType?.ToString()); // If no settings were appended, just short-circuit. if (isFirst) { return; } setUserSettingsCommandText.Append(@" ) AS Input(UserId, SettingId, SettingValue) ON UserSettings.UserId = Input.UserId AND UserSettings.SettingId = Input.SettingId WHEN MATCHED THEN UPDATE SET SettingValue = Input.SettingValue WHEN NOT MATCHED THEN INSERT (UserId, SettingId, SettingValue) VALUES (Input.UserId, Input.SettingId, Input.SettingValue);"); using (var command = this.databaseCommandFactory.Create( setUserSettingsCommandText.ToString(), parameters)) { await command.ExecuteNonQueryAsync(); } }