Add counts to Dashboard (#2)

Also refactored database parameters with a few extension methods; ready for profile view page
This commit is contained in:
2021-01-04 23:05:53 -05:00
parent fe3510b818
commit 97b3de1cea
15 changed files with 325 additions and 93 deletions

View File

@@ -103,5 +103,19 @@ namespace JobsJobsJobs.Server.Areas.Api.Controllers
await _db.OpenAsync();
return Ok(await _db.FindSkillsByCitizen(CurrentCitizenId));
}
[HttpGet("count")]
public async Task<IActionResult> GetProfileCount()
{
await _db.OpenAsync();
return Ok(new Count(await _db.CountProfiles()));
}
[HttpGet("skill-count")]
public async Task<IActionResult> GetSkillCount()
{
await _db.OpenAsync();
return Ok(new Count(await _db.CountSkills(CurrentCitizenId)));
}
}
}

View File

@@ -1,9 +1,5 @@
using JobsJobsJobs.Shared;
using Npgsql;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace JobsJobsJobs.Server.Data
@@ -31,13 +27,11 @@ namespace JobsJobsJobs.Server.Data
{
using var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT * FROM citizen WHERE na_user = @na_user";
cmd.Parameters.Add(new NpgsqlParameter("@na_user", naUser));
cmd.AddString("na_user", naUser);
using NpgsqlDataReader rdr = await cmd.ExecuteReaderAsync().ConfigureAwait(false);
if (await rdr.ReadAsync().ConfigureAwait(false))
{
return ToCitizen(rdr);
}
if (await rdr.ReadAsync().ConfigureAwait(false)) return ToCitizen(rdr);
return null;
}
@@ -54,12 +48,12 @@ namespace JobsJobsJobs.Server.Data
) VALUES(
@na_user, @display_name, @profile_url, @joined_on, @last_seen_on, @id
)";
cmd.Parameters.Add(new NpgsqlParameter("@id", citizen.Id.ToString()));
cmd.Parameters.Add(new NpgsqlParameter("@na_user", citizen.NaUser));
cmd.Parameters.Add(new NpgsqlParameter("@display_name", citizen.DisplayName));
cmd.Parameters.Add(new NpgsqlParameter("@profile_url", citizen.ProfileUrl));
cmd.Parameters.Add(new NpgsqlParameter("@joined_on", citizen.JoinedOn));
cmd.Parameters.Add(new NpgsqlParameter("@last_seen_on", citizen.LastSeenOn));
cmd.AddString("id", citizen.Id);
cmd.AddString("na_user", citizen.NaUser);
cmd.AddString("display_name", citizen.DisplayName);
cmd.AddString("profile_url", citizen.ProfileUrl);
cmd.AddInstant("joined_on", citizen.JoinedOn);
cmd.AddInstant("last_seen_on", citizen.LastSeenOn);
await cmd.ExecuteNonQueryAsync().ConfigureAwait(false);
}
@@ -76,9 +70,9 @@ namespace JobsJobsJobs.Server.Data
SET display_name = @display_name,
last_seen_on = @last_seen_on
WHERE id = @id";
cmd.Parameters.Add(new NpgsqlParameter("@id", citizen.Id.ToString()));
cmd.Parameters.Add(new NpgsqlParameter("@display_name", citizen.DisplayName));
cmd.Parameters.Add(new NpgsqlParameter("@last_seen_on", citizen.LastSeenOn));
cmd.AddString("id", citizen.Id);
cmd.AddString("display_name", citizen.DisplayName);
cmd.AddInstant("last_seen_on", citizen.LastSeenOn);
await cmd.ExecuteNonQueryAsync().ConfigureAwait(false);
}

View File

@@ -11,8 +11,10 @@ namespace JobsJobsJobs.Server.Data
/// <summary>
/// Extensions to the Npgsql data reader
/// </summary>
public static class NpgsqlDataReaderExtensions
public static class NpgsqlExtensions
{
#region Data Reader
/// <summary>
/// Get a boolean by its name
/// </summary>
@@ -48,5 +50,44 @@ namespace JobsJobsJobs.Server.Data
/// <param name="name">The name of the column to check</param>
/// <returns>True if the column is null, false if not</returns>
public static bool IsDBNull(this NpgsqlDataReader rdr, string name) => rdr.IsDBNull(rdr.GetOrdinal(name));
#endregion
#region Command
/// <summary>
/// Add a string parameter
/// </summary>
/// <param name="name">The name of the parameter</param>
/// <param name="value">The value of the parameter</param>
public static void AddString(this NpgsqlCommand cmd, string name, object value) =>
cmd.Parameters.Add(
new NpgsqlParameter<string>($"@{name}", value is string @val ? @val : value.ToString()!));
/// <summary>
/// Add a boolean parameter
/// </summary>
/// <param name="name">The name of the parameter</param>
/// <param name="value">The value of the parameter</param>
public static void AddBool(this NpgsqlCommand cmd, string name, bool value) =>
cmd.Parameters.Add(new NpgsqlParameter<bool>($"@{name}", value));
/// <summary>
/// Add an Instant parameter
/// </summary>
/// <param name="name">The name of the parameter</param>
/// <param name="value">The value of the parameter</param>
public static void AddInstant(this NpgsqlCommand cmd, string name, Instant value) =>
cmd.Parameters.Add(new NpgsqlParameter<Instant>($"@{name}", value));
/// <summary>
/// Add a parameter that may be null
/// </summary>
/// <param name="name">The name of the parameter</param>
/// <param name="value">The value of the parameter</param>
public static void AddMaybeNull(this NpgsqlCommand cmd, string name, object? value) =>
cmd.Parameters.Add(new NpgsqlParameter($"@{name}", value == null ? DBNull.Value : value));
#endregion
}
}

View File

@@ -1,6 +1,5 @@
using JobsJobsJobs.Shared;
using Npgsql;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -9,7 +8,7 @@ using System.Threading.Tasks;
namespace JobsJobsJobs.Server.Data
{
/// <summary>
/// Extensions to the NpgsqlConnection type to support manipulation of profiles
/// Extensions to the Connection type to support manipulation of profiles
/// </summary>
public static class ProfileExtensions
{
@@ -53,7 +52,7 @@ namespace JobsJobsJobs.Server.Data
FROM profile p
INNER JOIN continent c ON p.continent_id = c.id
WHERE citizen_id = @id";
cmd.Parameters.Add(new NpgsqlParameter("@id", citizen.Id.ToString()));
cmd.AddString("id", citizen.Id);
using var rdr = await cmd.ExecuteReaderAsync().ConfigureAwait(false);
return await rdr.ReadAsync().ConfigureAwait(false) ? ToProfile(rdr) : null;
@@ -84,17 +83,16 @@ namespace JobsJobsJobs.Server.Data
last_updated_on = @last_updated_on,
experience = @experience
WHERE profile.citizen_id = excluded.citizen_id";
cmd.Parameters.Add(new NpgsqlParameter("@citizen_id", profile.Id.ToString()));
cmd.Parameters.Add(new NpgsqlParameter("@seeking_employment", profile.SeekingEmployment));
cmd.Parameters.Add(new NpgsqlParameter("@is_public", profile.IsPublic));
cmd.Parameters.Add(new NpgsqlParameter("@continent_id", profile.ContinentId.ToString()));
cmd.Parameters.Add(new NpgsqlParameter("@region", profile.Region));
cmd.Parameters.Add(new NpgsqlParameter("@remote_work", profile.RemoteWork));
cmd.Parameters.Add(new NpgsqlParameter("@full_time", profile.FullTime));
cmd.Parameters.Add(new NpgsqlParameter("@biography", profile.Biography.Text));
cmd.Parameters.Add(new NpgsqlParameter("@last_updated_on", profile.LastUpdatedOn));
cmd.Parameters.Add(new NpgsqlParameter("@experience",
profile.Experience == null ? DBNull.Value : profile.Experience.Text));
cmd.AddString("citizen_id", profile.Id);
cmd.AddBool("seeking_employment", profile.SeekingEmployment);
cmd.AddBool("is_public", profile.IsPublic);
cmd.AddString("continent_id", profile.ContinentId);
cmd.AddString("region", profile.Region);
cmd.AddBool("remote_work", profile.RemoteWork);
cmd.AddBool("full_time", profile.FullTime);
cmd.AddString("biography", profile.Biography.Text);
cmd.AddInstant("last_updated_on", profile.LastUpdatedOn);
cmd.AddMaybeNull("experience", profile.Experience);
await cmd.ExecuteNonQueryAsync().ConfigureAwait(false);
}
@@ -109,7 +107,7 @@ namespace JobsJobsJobs.Server.Data
{
using var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT * FROM skill WHERE citizen_id = @citizen_id";
cmd.Parameters.Add(new NpgsqlParameter("citizen_id", citizenId.ToString()));
cmd.AddString("citizen_id", citizenId);
var result = new List<Skill>();
using var rdr = await cmd.ExecuteReaderAsync().ConfigureAwait(false);
@@ -137,10 +135,10 @@ namespace JobsJobsJobs.Server.Data
SET skill = @skill,
notes = @notes
WHERE skill.id = excluded.id";
cmd.Parameters.Add(new NpgsqlParameter("id", skill.Id.ToString()));
cmd.Parameters.Add(new NpgsqlParameter("citizen_id", skill.CitizenId.ToString()));
cmd.Parameters.Add(new NpgsqlParameter("skill", skill.Description));
cmd.Parameters.Add(new NpgsqlParameter("notes", skill.Notes == null ? DBNull.Value : skill.Notes));
cmd.AddString("id", skill.Id);
cmd.AddString("citizen_id", skill.CitizenId);
cmd.AddString("skill", skill.Description);
cmd.AddMaybeNull("notes", skill.Notes);
await cmd.ExecuteNonQueryAsync().ConfigureAwait(false);
}
@@ -161,11 +159,39 @@ namespace JobsJobsJobs.Server.Data
.Append(string.Join(", ", ids.Select(_ => $"@id{count++}").ToArray()))
.Append(')')
.ToString();
cmd.Parameters.Add(new NpgsqlParameter("citizen_id", citizenId.ToString()));
cmd.AddString("citizen_id", citizenId);
count = 0;
foreach (var id in ids) cmd.Parameters.Add(new NpgsqlParameter($"id{count++}", id.ToString()));
foreach (var id in ids) cmd.AddString($"id{count++}", id);
await cmd.ExecuteNonQueryAsync().ConfigureAwait(false);
}
/// <summary>
/// Get a count of the citizens with profiles
/// </summary>
/// <returns>The number of citizens with profiles</returns>
public static async Task<long> CountProfiles(this NpgsqlConnection conn)
{
using var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT COUNT(citizen_id) FROM profile";
var result = await cmd.ExecuteScalarAsync().ConfigureAwait(false);
return result == null ? 0L : (long)result;
}
/// <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<long> CountSkills(this NpgsqlConnection conn, CitizenId citizenId)
{
using var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT COUNT(id) FROM skill WHERE citizen_id = @citizen_id";
cmd.AddString("citizen_id", citizenId);
var result = await cmd.ExecuteScalarAsync().ConfigureAwait(false);
return result == null ? 0L : (long)result;
}
}
}