2025-01-25 00:27:02 +01:00

253 lines
9.6 KiB
C#

using Microsoft.Data.Sqlite;
namespace WheresMyMoney.Maui.Core;
public class Repository
{
private static Repository? _instance;
public static Repository Instance
{
get
{
if (_instance is not null) return _instance;
string dbPath = Path.Combine(FileSystem.AppDataDirectory, "wheresmymoney.db");
_instance = new Repository(new SqliteConnection($"Data Source={dbPath};"));
return _instance;
}
}
private readonly SqliteConnection _connection;
private Repository(SqliteConnection connection)
{
_connection = connection;
_connection.Open();
CreateTables();
}
~Repository()
{
_connection.Close();
}
public void CreateTables()
{
using var command = _connection.CreateCommand();
command.CommandText = """
CREATE TABLE IF NOT EXISTS planned_payment (
id INTEGER PRIMARY KEY AUTOINCREMENT,
amount INTEGER NOT NULL,
name TEXT NOT NULL,
date_start TEXT NOT NULL,
date_end TEXT NULL,
is_subscription BOOLEAN NOT NULL,
reoccurences INTEGER NULL,
reoccurence_type INTEGER NULL CHECK(CASE reoccurences IS NOT NULL AND reoccurence_type IS NOT NULL WHEN TRUE THEN is_subscription ELSE NOT is_subscription END)
);
CREATE TABLE IF NOT EXISTS balance (
id INTEGER PRIMARY KEY AUTOINCREMENT,
amount INTEGER NOT NULL,
date TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS settings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
payday TINYINT NOT NULL CHECK(payday BETWEEN 1 AND 31)
);
""";
command.ExecuteNonQuery();
}
public void InsertPlannedPayment(decimal amount, string name, DateTime dateStart, DateTime? dateEnd,
bool isSubscription,
int? reoccurences, ReoccurenceType? reoccurenceType)
{
using var command = _connection.CreateCommand();
command.CommandText = """
INSERT INTO planned_payment (amount, name, date_start, date_end, is_subscription, reoccurences, reoccurence_type)
VALUES (@amount, @name, @date_start, @date_end, @is_subscription, @reoccurences, @reoccurence_type);
""";
command.Parameters.AddWithValue("@amount", (int)(amount * 100));
command.Parameters.AddWithValue("@name", name);
command.Parameters.AddWithValue("@date_start", dateStart);
command.Parameters.AddWithValue("@date_end", dateEnd.HasValue ? dateEnd.Value : DBNull.Value);
command.Parameters.AddWithValue("@is_subscription", isSubscription);
command.Parameters.AddWithValue("@reoccurences", reoccurences is null ? DBNull.Value : reoccurences.Value);
command.Parameters.AddWithValue("@reoccurence_type",
reoccurenceType is null ? DBNull.Value : (int)reoccurenceType.Value);
command.ExecuteNonQuery();
DataChanged(this, EventArgs.Empty);
}
public void InsertBalance(decimal amount, DateTime date)
{
using var command = _connection.CreateCommand();
command.CommandText = """
INSERT INTO balance (amount, date)
VALUES (@amount, @date);
""";
command.Parameters.AddWithValue("@amount", (int)(amount * 100));
command.Parameters.AddWithValue("@date", date);
command.ExecuteNonQuery();
DataChanged(this, EventArgs.Empty);
}
public decimal GetNewestBalance()
{
using var command = _connection.CreateCommand();
command.CommandText = @"SELECT amount FROM balance ORDER BY date DESC LIMIT 1;";
var result = command.ExecuteScalar();
return result != null ? Convert.ToDecimal(result) / 100m : 0m;
}
public List<Balance> GetAllBalances()
{
var balances = new List<Balance>();
using var command = _connection.CreateCommand();
command.CommandText = @"SELECT id, amount, date FROM balance ORDER BY date;";
using var reader = command.ExecuteReader();
while (reader.Read())
{
balances.Add(new Balance(
reader.GetInt32(0),
reader.GetDecimal(1) / 100m,
reader.GetDateTime(2)
));
}
return balances;
}
public byte GetPayday()
{
using var command = _connection.CreateCommand();
command.CommandText = "SELECT payday FROM settings LIMIT 1;";
var result = command.ExecuteScalar();
return result != null ? Convert.ToByte(result) : (byte)10;
}
public void ReplacePayday(byte newPayday)
{
using var command = _connection.CreateCommand();
command.CommandText = """
INSERT INTO settings (id, payday)
VALUES (1, @payday)
ON CONFLICT(id) DO UPDATE SET payday = excluded.payday;
""";
command.Parameters.AddWithValue("@payday", newPayday);
command.ExecuteNonQuery();
DataChanged(this, EventArgs.Empty);
}
public List<PlannedPayment> GetAllPlannedPayments()
{
var payments = new List<PlannedPayment>();
using var command = _connection.CreateCommand();
command.CommandText =
"SELECT id, amount, name, date_start, date_end, is_subscription, reoccurences, reoccurence_type FROM planned_payment ORDER BY DATETIME(date_start);";
using var reader = command.ExecuteReader();
while (reader.Read())
{
payments.Add(new PlannedPayment(
reader.GetInt32(0),
reader.GetDecimal(1) / 100m,
reader.GetString(2),
reader.GetDateTime(3),
reader.IsDBNull(4) ? null : reader.GetDateTime(4),
reader.GetBoolean(5),
reader.IsDBNull(6) ? null : reader.GetInt32(6),
reader.IsDBNull(7) ? null : (ReoccurenceType)reader.GetInt32(7)
));
}
return payments;
}
public List<PlannedPayment> GetFilteredPlannedPayments()
{
var filteredPayments = new List<PlannedPayment>();
var now = DateTime.Now;
var nearestPayday = GetNearestPayday(now);
using var command = _connection.CreateCommand();
command.CommandText = """
SELECT id, amount, name, date_start, date_end, is_subscription, reoccurences, reoccurence_type
FROM planned_payment
WHERE (
(is_subscription = 0 AND DATETIME(date_start) >= DATETIME(@currentDate) AND DATETIME(date_start) <= DATETIME(@nearestPayday)) OR
(is_subscription = 1 AND (date_end IS NULL OR DATETIME(date_end) >= DATETIME(@currentDate)) AND DATETIME(date_start) <= DATETIME(@nearestPayday))
)
ORDER BY DATETIME(date_start);
""";
command.Parameters.AddWithValue("@currentDate", now);
command.Parameters.AddWithValue("@nearestPayday", nearestPayday);
using var reader = command.ExecuteReader();
while (reader.Read())
{
filteredPayments.Add(new PlannedPayment(
reader.GetInt32(0),
reader.GetDecimal(1) / 100m,
reader.GetString(2),
reader.GetDateTime(3),
reader.IsDBNull(4) ? null : reader.GetDateTime(4),
reader.GetBoolean(5),
reader.IsDBNull(6) ? null : reader.GetInt32(6),
reader.IsDBNull(7) ? null : (ReoccurenceType)reader.GetInt32(7)
));
}
return filteredPayments;
}
public DateTime GetNearestPayday(DateTime now)
{
var payday = GetPayday();
var nearestPayday =
new DateOnly(now.Year, now.Month,
payday > DateTime.DaysInMonth(now.Year, now.Month)
? DateTime.DaysInMonth(now.Year, now.Month)
: payday)
.ToDateTime(TimeOnly.MinValue);
if (now.Day <= payday) return nearestPayday;
var newDate = new DateOnly(now.Year, now.Month, DateTime.DaysInMonth(now.Year, now.Month)).AddDays(1);
nearestPayday =
new DateOnly(newDate.Year, newDate.Month,
payday > DateTime.DaysInMonth(newDate.Year, newDate.Month)
? DateTime.DaysInMonth(newDate.Year, newDate.Month)
: payday).ToDateTime(TimeOnly.MinValue);
return nearestPayday;
}
public void RemovePlannedPayment(int id)
{
using var command = _connection.CreateCommand();
command.CommandText = """
DELETE FROM planned_payment
WHERE id = @id;
""";
command.Parameters.AddWithValue("@id", id);
command.ExecuteNonQuery();
DataChanged(this, EventArgs.Empty);
}
public event EventHandler DataChanged;
}