240 lines
8.8 KiB
C#
240 lines
8.8 KiB
C#
using System.ComponentModel;
|
|
using trakker.Models;
|
|
|
|
namespace trakker.Data
|
|
{
|
|
/// <summary>
|
|
/// Provides data access methods for the <see cref="Models.Client"/> entity.
|
|
/// This class encapsulates database operations such as upsert, delete and ad-hoc
|
|
/// SQL execution for clients. It inherits from <see cref="DataAccess"/> which
|
|
/// provides connection management.
|
|
/// </summary>
|
|
internal class ClientData(string connectionString) : DataAccess(connectionString)
|
|
{
|
|
|
|
public BindingList<Client> Get(string? clientId = null)
|
|
{
|
|
var results = new BindingList<Client>();
|
|
|
|
string whereClause = "1 = 1";
|
|
if (clientId != null)
|
|
{
|
|
whereClause = "client_id = $client_id";
|
|
}
|
|
|
|
string sql = $@"
|
|
SELECT
|
|
client_id,
|
|
name,
|
|
company,
|
|
email,
|
|
phone,
|
|
address_street,
|
|
address_city,
|
|
address_state,
|
|
address_postal,
|
|
notes,
|
|
is_active,
|
|
created_at,
|
|
updated_at,
|
|
(SELECT COUNT(*) FROM projects x WHERE x.client_id = clients.client_id ) AS project_count
|
|
FROM
|
|
clients
|
|
WHERE
|
|
{whereClause}
|
|
ORDER BY
|
|
name ASC
|
|
;
|
|
";
|
|
|
|
|
|
using var conn = OpenConnection();
|
|
using var cmd = conn.CreateCommand();
|
|
cmd.CommandText = sql;
|
|
|
|
if (clientId != null)
|
|
{
|
|
cmd.Parameters.AddWithValue("$client_id", clientId);
|
|
}
|
|
using var reader = cmd.ExecuteReader();
|
|
|
|
var _var1 = reader.GetOrdinal("client_id");
|
|
var _var2 = reader.GetOrdinal("name");
|
|
var _var3 = reader.GetOrdinal("company");
|
|
var _var4 = reader.GetOrdinal("email");
|
|
var _var5 = reader.GetOrdinal("phone");
|
|
var _var6 = reader.GetOrdinal("address_street");
|
|
var _var7 = reader.GetOrdinal("address_city");
|
|
var _var8 = reader.GetOrdinal("address_state");
|
|
var _var9 = reader.GetOrdinal("address_postal");
|
|
var _var10 = reader.GetOrdinal("notes");
|
|
var _var11 = reader.GetOrdinal("is_active");
|
|
var _var12 = reader.GetOrdinal("project_count");
|
|
var _var13 = reader.GetOrdinal("created_at");
|
|
var _var14 = reader.GetOrdinal("updated_at");
|
|
|
|
while (reader.Read())
|
|
{
|
|
results.Add(new Client
|
|
{
|
|
ClientId = reader.GetString(_var1),
|
|
Name = reader.GetString(_var2),
|
|
Company = reader.GetString(_var3),
|
|
Email = reader.GetString(_var4),
|
|
Phone = reader.GetString(_var5),
|
|
AddressStreet = reader.GetString(_var6),
|
|
AddressCity = reader.GetString(_var7),
|
|
AddressState = reader.GetString(_var8),
|
|
AddressPostal = reader.GetString(_var9),
|
|
Notes = reader.GetString(_var10),
|
|
IsActive = reader.GetString(_var11),
|
|
ProjectCount = reader.GetInt32(_var12),
|
|
CreatedAt = reader.GetDateTime(_var13),
|
|
UpdatedAt = reader.GetDateTime(_var14),
|
|
});
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Inserts a new client record or updates an existing one (upsert) using
|
|
/// the provided <paramref name="client"/> model. This method executes
|
|
/// a single SQL statement inside a transaction and will commit on
|
|
/// success or roll back on failure.
|
|
/// </summary>
|
|
/// <param name="client">The <see cref="Client"/> model to insert or update. Must not be null.</param>
|
|
/// <remarks>
|
|
/// The SQL statement uses an ON CONFLICT clause to perform the update when a
|
|
/// matching <c>client_id</c> already exists. Parameter names correspond to the
|
|
/// client model property names.
|
|
/// </remarks>
|
|
public void Upsert(Client client)
|
|
{
|
|
const string sql = @"
|
|
INSERT INTO clients (
|
|
client_id,
|
|
name,
|
|
company,
|
|
email,
|
|
phone,
|
|
address_street,
|
|
address_city,
|
|
address_state,
|
|
address_postal,
|
|
notes,
|
|
is_active
|
|
)
|
|
VALUES (
|
|
$client_id,
|
|
$name,
|
|
$company,
|
|
$email,
|
|
$phone,
|
|
$address_street,
|
|
$address_city,
|
|
$address_state,
|
|
$address_postal,
|
|
$notes,
|
|
$is_active
|
|
)
|
|
ON CONFLICT(client_id) DO UPDATE SET
|
|
name = excluded.name,
|
|
company = excluded.company,
|
|
email = excluded.email,
|
|
phone = excluded.phone,
|
|
address_street = excluded.address_street,
|
|
address_city = excluded.address_city,
|
|
address_state = excluded.address_state,
|
|
address_postal = excluded.address_postal,
|
|
notes = excluded.notes,
|
|
is_active = excluded.is_active,
|
|
updated_at = CURRENT_TIMESTAMP;
|
|
";
|
|
|
|
using var conn = OpenConnection();
|
|
using var tx = conn.BeginTransaction();
|
|
|
|
try
|
|
{
|
|
using (var cmd = conn.CreateCommand())
|
|
{
|
|
cmd.Transaction = tx;
|
|
cmd.CommandText = sql;
|
|
cmd.Parameters.AddWithValue("$client_id", client.ClientId);
|
|
cmd.Parameters.AddWithValue("$name", client.Name);
|
|
cmd.Parameters.AddWithValue("$company", client.Company);
|
|
cmd.Parameters.AddWithValue("$email", client.Email);
|
|
cmd.Parameters.AddWithValue("$phone", client.Phone);
|
|
cmd.Parameters.AddWithValue("$address_street", client.AddressStreet);
|
|
cmd.Parameters.AddWithValue("$address_city", client.AddressCity);
|
|
cmd.Parameters.AddWithValue("$address_state", client.AddressState);
|
|
cmd.Parameters.AddWithValue("$address_postal", client.AddressPostal);
|
|
cmd.Parameters.AddWithValue("$notes", client.Notes);
|
|
cmd.Parameters.AddWithValue("$is_active", client.IsActive);
|
|
cmd.ExecuteNonQuery();
|
|
}
|
|
|
|
tx.Commit();
|
|
}
|
|
catch
|
|
{
|
|
tx.Rollback();
|
|
throw;
|
|
}
|
|
|
|
}
|
|
/// <summary>
|
|
/// Deletes the client with the specified <paramref name="clientId"/> from the
|
|
/// database.
|
|
/// </summary>
|
|
/// <param name="clientId">The identifier of the client to delete.</param>
|
|
/// <returns>An optional integer representing any scalar value returned by the
|
|
/// command executed after deletion (if applicable). May be null.</returns>
|
|
/// <remarks>
|
|
/// The method executes within a transaction. The current implementation attempts
|
|
/// to read a scalar value after the delete; that value depends on surrounding
|
|
/// database triggers or commands and may be null.
|
|
/// </remarks>
|
|
public int? Delete(string clientId)
|
|
{
|
|
const string sql = @"
|
|
DELETE FROM
|
|
clients
|
|
WHERE
|
|
client_id = $client_id
|
|
;
|
|
";
|
|
|
|
using var conn = OpenConnection();
|
|
using var tx = conn.BeginTransaction();
|
|
|
|
int? result = 0;
|
|
try
|
|
{
|
|
using (var cmd = conn.CreateCommand())
|
|
{
|
|
cmd.Transaction = tx;
|
|
cmd.CommandText = sql;
|
|
cmd.Parameters.AddWithValue("$client_id", clientId);
|
|
cmd.ExecuteNonQuery();
|
|
}
|
|
|
|
using var idCmd = conn.CreateCommand();
|
|
idCmd.Transaction = tx;
|
|
result = (int?)idCmd.ExecuteScalar() ;
|
|
|
|
tx.Commit();
|
|
}
|
|
catch
|
|
{
|
|
tx.Rollback();
|
|
throw;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
}
|
|
}
|