Files
BoxPacker3D/ItemDatabase.cs
T
2026-06-05 22:02:32 +02:00

193 lines
6.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Data.Sqlite;
namespace BoxPacker3D
{
/// <summary>
/// Persistent template of an item that can be re-used across packing sessions.
/// Stored in an on-disk SQLite database.
/// </summary>
public class ItemTemplate
{
public int Id { get; set; }
public string Name { get; set; } = "";
public double Width { get; set; }
public double Height { get; set; }
public double Depth { get; set; }
public override string ToString() =>
$"{Name} ({Width}×{Height}×{Depth} mm)";
}
/// <summary>
/// Simple SQLite-backed repository for <see cref="ItemTemplate"/>s.
/// Database schema is created on first use.
/// </summary>
public class ItemDatabase
{
private readonly string _connectionString;
public ItemDatabase(string dbPath)
{
// Ensure directory exists
var dir = Path.GetDirectoryName(dbPath);
if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
Directory.CreateDirectory(dir);
_connectionString = new SqliteConnectionStringBuilder
{
DataSource = dbPath,
Mode = SqliteOpenMode.ReadWriteCreate
}.ToString();
EnsureSchema();
}
private void EnsureSchema()
{
using var conn = Open();
using var cmd = conn.CreateCommand();
cmd.CommandText = @"
CREATE TABLE IF NOT EXISTS items (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Name TEXT NOT NULL UNIQUE COLLATE NOCASE,
Width REAL NOT NULL,
Height REAL NOT NULL,
Depth REAL NOT NULL
);";
cmd.ExecuteNonQuery();
}
private SqliteConnection Open()
{
var conn = new SqliteConnection(_connectionString);
conn.Open();
return conn;
}
/// <summary>Returns all templates ordered alphabetically by name.</summary>
public List<ItemTemplate> GetAll()
{
var list = new List<ItemTemplate>();
using var conn = Open();
using var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT Id, Name, Width, Height, Depth FROM items ORDER BY Name COLLATE NOCASE;";
using var rdr = cmd.ExecuteReader();
while (rdr.Read())
list.Add(new ItemTemplate
{
Id = rdr.GetInt32(0),
Name = rdr.GetString(1),
Width = rdr.GetDouble(2),
Height = rdr.GetDouble(3),
Depth = rdr.GetDouble(4)
});
return list;
}
/// <summary>Returns the template with the given name or null if none exists.</summary>
public ItemTemplate? FindByName(string name)
{
using var conn = Open();
using var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT Id, Name, Width, Height, Depth FROM items WHERE Name = $n COLLATE NOCASE LIMIT 1;";
cmd.Parameters.AddWithValue("$n", name);
using var rdr = cmd.ExecuteReader();
if (rdr.Read())
return new ItemTemplate
{
Id = rdr.GetInt32(0),
Name = rdr.GetString(1),
Width = rdr.GetDouble(2),
Height = rdr.GetDouble(3),
Depth = rdr.GetDouble(4)
};
return null;
}
/// <summary>Inserts or replaces a template (upsert by Name).</summary>
public void Upsert(ItemTemplate item)
{
using var conn = Open();
using var cmd = conn.CreateCommand();
cmd.CommandText = @"
INSERT INTO items (Name, Width, Height, Depth)
VALUES ($n, $w, $h, $d)
ON CONFLICT(Name) DO UPDATE SET
Width = excluded.Width,
Height = excluded.Height,
Depth = excluded.Depth;";
cmd.Parameters.AddWithValue("$n", item.Name);
cmd.Parameters.AddWithValue("$w", item.Width);
cmd.Parameters.AddWithValue("$h", item.Height);
cmd.Parameters.AddWithValue("$d", item.Depth);
cmd.ExecuteNonQuery();
}
public void DeleteByName(string name)
{
using var conn = Open();
using var cmd = conn.CreateCommand();
cmd.CommandText = "DELETE FROM items WHERE Name = $n COLLATE NOCASE;";
cmd.Parameters.AddWithValue("$n", name);
cmd.ExecuteNonQuery();
}
/// <summary>
/// Checks if a template with the same name or exact dimensions already exists.
/// Returns the existing template if found, null otherwise.
/// </summary>
public ItemTemplate? FindDuplicate(ItemTemplate item)
{
using var conn = Open();
using var cmd = conn.CreateCommand();
// Check for same name (case-insensitive)
cmd.CommandText = "SELECT Id, Name, Width, Height, Depth FROM items WHERE Name = $n COLLATE NOCASE LIMIT 1;";
cmd.Parameters.AddWithValue("$n", item.Name);
using (var rdr = cmd.ExecuteReader())
{
if (rdr.Read())
{
return new ItemTemplate
{
Id = rdr.GetInt32(0),
Name = rdr.GetString(1),
Width = rdr.GetDouble(2),
Height = rdr.GetDouble(3),
Depth = rdr.GetDouble(4)
};
}
}
// Check for same dimensions (exact match)
cmd.CommandText = @"
SELECT Id, Name, Width, Height, Depth FROM items
WHERE Width = $w AND Height = $h AND Depth = $d
LIMIT 1;";
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("$w", item.Width);
cmd.Parameters.AddWithValue("$h", item.Height);
cmd.Parameters.AddWithValue("$d", item.Depth);
using (var rdr = cmd.ExecuteReader())
{
if (rdr.Read())
{
return new ItemTemplate
{
Id = rdr.GetInt32(0),
Name = rdr.GetString(1),
Width = rdr.GetDouble(2),
Height = rdr.GetDouble(3),
Depth = rdr.GetDouble(4)
};
}
}
return null;
}
}
}