using JobsJobsJobs.Shared; using Microsoft.EntityFrameworkCore; using Npgsql; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace JobsJobsJobs.Server.Data { /// <summary> /// Extensions to JobsDbContext to support manipulation of profiles /// </summary> public static class ProfileExtensions { /// <summary> /// Retrieve an employment profile by a citizen ID /// </summary> /// <param name="citizenId">The ID of the citizen whose profile should be retrieved</param> /// <returns>The profile, or null if it does not exist</returns> public static async Task<Profile?> FindProfileByCitizen(this JobsDbContext db, CitizenId citizenId) { var profile = await db.Profiles.AsNoTracking() .SingleOrDefaultAsync(p => p.Id == citizenId) .ConfigureAwait(false); if (profile != null) { return profile with { Continent = await db.FindContinentById(profile.ContinentId).ConfigureAwait(false), Skills = (await db.FindSkillsByCitizen(citizenId).ConfigureAwait(false)).ToArray() }; } return null; } /// <summary> /// Save a profile /// </summary> /// <param name="profile">The profile to be saved</param> public static async Task SaveProfile(this JobsDbContext db, Profile profile) { if (await db.Profiles.CountAsync(p => p.Id == profile.Id).ConfigureAwait(false) == 0) { await db.AddAsync(profile).ConfigureAwait(false); } else { db.Entry(profile).State = EntityState.Modified; } } /// <summary> /// Retrieve all skills for the given citizen /// </summary> /// <param name="citizenId">The ID of the citizen whose skills should be retrieved</param> /// <returns>The skills defined for this citizen</returns> public static async Task<IEnumerable<Skill>> FindSkillsByCitizen(this JobsDbContext db, CitizenId citizenId) => await db.Skills.AsNoTracking() .Where(s => s.CitizenId == citizenId) .ToListAsync().ConfigureAwait(false); /// <summary> /// Save a skill /// </summary> /// <param name="skill">The skill to be saved</param> public static async Task SaveSkill(this JobsDbContext db, Skill skill) { if (await db.Skills.CountAsync(s => s.Id == skill.Id).ConfigureAwait(false) == 0) { await db.Skills.AddAsync(skill).ConfigureAwait(false); } else { db.Entry(skill).State = EntityState.Modified; } } /// <summary> /// Delete any skills that are not in the list of current skill IDs /// </summary> /// <param name="citizenId">The ID of the citizen to whom the skills belong</param> /// <param name="ids">The IDs of their current skills</param> public static async Task DeleteMissingSkills(this JobsDbContext db, CitizenId citizenId, IEnumerable<SkillId> ids) { if (!ids.Any()) return; db.Skills.RemoveRange(await db.Skills.AsNoTracking() .Where(s => !ids.Contains(s.Id)).ToListAsync() .ConfigureAwait(false)); } /// <summary> /// Get a count of the citizens with profiles /// </summary> /// <returns>The number of citizens with profiles</returns> public static async Task<int> CountProfiles(this JobsDbContext db) => await db.Profiles.CountAsync().ConfigureAwait(false); /// <summary> /// Count the skills for the given citizen /// </summary> /// <param name="citizenId">The ID of the citizen whose skills should be counted</param> /// <returns>The count of skills for the given citizen</returns> public static async Task<int> CountSkillsByCitizen(this JobsDbContext db, CitizenId citizenId) => await db.Skills.CountAsync(s => s.CitizenId == citizenId).ConfigureAwait(false); } }