.
This commit is contained in:
parent
86aa0f856c
commit
0801ceee6a
310 changed files with 6712 additions and 418 deletions
234
src/Scry.Core/Data/CardHashDatabase.cs
Normal file
234
src/Scry.Core/Data/CardHashDatabase.cs
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
using Microsoft.Data.Sqlite;
|
||||
using Scry.Core.Models;
|
||||
|
||||
namespace Scry.Core.Data;
|
||||
|
||||
public class CardHashDatabase : IDisposable
|
||||
{
|
||||
private readonly SqliteConnection _connection;
|
||||
private readonly string _dbPath;
|
||||
|
||||
public CardHashDatabase(string dbPath)
|
||||
{
|
||||
_dbPath = dbPath;
|
||||
_connection = new SqliteConnection($"Data Source={dbPath}");
|
||||
_connection.Open();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
using var cmd = _connection.CreateCommand();
|
||||
cmd.CommandText = """
|
||||
CREATE TABLE IF NOT EXISTS card_hashes (
|
||||
card_id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
set_code TEXT NOT NULL,
|
||||
collector_number TEXT,
|
||||
hash BLOB NOT NULL,
|
||||
image_uri TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_card_hashes_name ON card_hashes(name);
|
||||
CREATE INDEX IF NOT EXISTS idx_card_hashes_set ON card_hashes(set_code);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS metadata (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL
|
||||
);
|
||||
""";
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
public async Task<string?> GetMetadataAsync(string key, CancellationToken ct = default)
|
||||
{
|
||||
await using var cmd = _connection.CreateCommand();
|
||||
cmd.CommandText = "SELECT value FROM metadata WHERE key = $key";
|
||||
cmd.Parameters.AddWithValue("$key", key);
|
||||
|
||||
var result = await cmd.ExecuteScalarAsync(ct);
|
||||
return result as string;
|
||||
}
|
||||
|
||||
public async Task SetMetadataAsync(string key, string value, CancellationToken ct = default)
|
||||
{
|
||||
await using var cmd = _connection.CreateCommand();
|
||||
cmd.CommandText = """
|
||||
INSERT OR REPLACE INTO metadata (key, value) VALUES ($key, $value)
|
||||
""";
|
||||
cmd.Parameters.AddWithValue("$key", key);
|
||||
cmd.Parameters.AddWithValue("$value", value);
|
||||
await cmd.ExecuteNonQueryAsync(ct);
|
||||
}
|
||||
|
||||
public async Task InsertHashAsync(CardHash hash, CancellationToken ct = default)
|
||||
{
|
||||
await using var cmd = _connection.CreateCommand();
|
||||
cmd.CommandText = """
|
||||
INSERT OR REPLACE INTO card_hashes
|
||||
(card_id, name, set_code, collector_number, hash, image_uri)
|
||||
VALUES ($card_id, $name, $set_code, $collector_number, $hash, $image_uri)
|
||||
""";
|
||||
cmd.Parameters.AddWithValue("$card_id", hash.CardId);
|
||||
cmd.Parameters.AddWithValue("$name", hash.Name);
|
||||
cmd.Parameters.AddWithValue("$set_code", hash.SetCode);
|
||||
cmd.Parameters.AddWithValue("$collector_number", hash.CollectorNumber ?? (object)DBNull.Value);
|
||||
cmd.Parameters.AddWithValue("$hash", hash.Hash);
|
||||
cmd.Parameters.AddWithValue("$image_uri", hash.ImageUri ?? (object)DBNull.Value);
|
||||
|
||||
await cmd.ExecuteNonQueryAsync(ct);
|
||||
}
|
||||
|
||||
public async Task InsertHashBatchAsync(IEnumerable<CardHash> hashes, CancellationToken ct = default)
|
||||
{
|
||||
await using var transaction = await _connection.BeginTransactionAsync(ct);
|
||||
|
||||
try
|
||||
{
|
||||
await using var cmd = _connection.CreateCommand();
|
||||
cmd.CommandText = """
|
||||
INSERT OR REPLACE INTO card_hashes
|
||||
(card_id, name, set_code, collector_number, hash, image_uri)
|
||||
VALUES ($card_id, $name, $set_code, $collector_number, $hash, $image_uri)
|
||||
""";
|
||||
|
||||
var cardIdParam = cmd.Parameters.Add("$card_id", SqliteType.Text);
|
||||
var nameParam = cmd.Parameters.Add("$name", SqliteType.Text);
|
||||
var setCodeParam = cmd.Parameters.Add("$set_code", SqliteType.Text);
|
||||
var collectorNumberParam = cmd.Parameters.Add("$collector_number", SqliteType.Text);
|
||||
var hashParam = cmd.Parameters.Add("$hash", SqliteType.Blob);
|
||||
var imageUriParam = cmd.Parameters.Add("$image_uri", SqliteType.Text);
|
||||
|
||||
foreach (var hash in hashes)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
cardIdParam.Value = hash.CardId;
|
||||
nameParam.Value = hash.Name;
|
||||
setCodeParam.Value = hash.SetCode;
|
||||
collectorNumberParam.Value = hash.CollectorNumber ?? (object)DBNull.Value;
|
||||
hashParam.Value = hash.Hash;
|
||||
imageUriParam.Value = hash.ImageUri ?? (object)DBNull.Value;
|
||||
|
||||
await cmd.ExecuteNonQueryAsync(ct);
|
||||
}
|
||||
|
||||
await transaction.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await transaction.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<CardHash>> GetAllHashesAsync(CancellationToken ct = default)
|
||||
{
|
||||
var hashes = new List<CardHash>();
|
||||
|
||||
await using var cmd = _connection.CreateCommand();
|
||||
cmd.CommandText = "SELECT card_id, name, set_code, collector_number, hash, image_uri FROM card_hashes";
|
||||
|
||||
await using var reader = await cmd.ExecuteReaderAsync(ct);
|
||||
while (await reader.ReadAsync(ct))
|
||||
{
|
||||
hashes.Add(new CardHash
|
||||
{
|
||||
CardId = reader.GetString(0),
|
||||
Name = reader.GetString(1),
|
||||
SetCode = reader.GetString(2),
|
||||
CollectorNumber = reader.IsDBNull(3) ? null : reader.GetString(3),
|
||||
Hash = (byte[])reader.GetValue(4),
|
||||
ImageUri = reader.IsDBNull(5) ? null : reader.GetString(5)
|
||||
});
|
||||
}
|
||||
|
||||
return hashes;
|
||||
}
|
||||
|
||||
public async Task<int> GetHashCountAsync(CancellationToken ct = default)
|
||||
{
|
||||
await using var cmd = _connection.CreateCommand();
|
||||
cmd.CommandText = "SELECT COUNT(*) FROM card_hashes";
|
||||
var result = await cmd.ExecuteScalarAsync(ct);
|
||||
return Convert.ToInt32(result);
|
||||
}
|
||||
|
||||
public async Task<CardHash?> GetHashByIdAsync(string cardId, CancellationToken ct = default)
|
||||
{
|
||||
await using var cmd = _connection.CreateCommand();
|
||||
cmd.CommandText = """
|
||||
SELECT card_id, name, set_code, collector_number, hash, image_uri
|
||||
FROM card_hashes WHERE card_id = $card_id
|
||||
""";
|
||||
cmd.Parameters.AddWithValue("$card_id", cardId);
|
||||
|
||||
await using var reader = await cmd.ExecuteReaderAsync(ct);
|
||||
if (await reader.ReadAsync(ct))
|
||||
{
|
||||
return new CardHash
|
||||
{
|
||||
CardId = reader.GetString(0),
|
||||
Name = reader.GetString(1),
|
||||
SetCode = reader.GetString(2),
|
||||
CollectorNumber = reader.IsDBNull(3) ? null : reader.GetString(3),
|
||||
Hash = (byte[])reader.GetValue(4),
|
||||
ImageUri = reader.IsDBNull(5) ? null : reader.GetString(5)
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<HashSet<string>> GetExistingCardIdsAsync(CancellationToken ct = default)
|
||||
{
|
||||
var ids = new HashSet<string>();
|
||||
|
||||
await using var cmd = _connection.CreateCommand();
|
||||
cmd.CommandText = "SELECT card_id FROM card_hashes";
|
||||
|
||||
await using var reader = await cmd.ExecuteReaderAsync(ct);
|
||||
while (await reader.ReadAsync(ct))
|
||||
{
|
||||
ids.Add(reader.GetString(0));
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
public async Task<HashSet<string>> GetExistingCardNamesAsync(CancellationToken ct = default)
|
||||
{
|
||||
var names = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
await using var cmd = _connection.CreateCommand();
|
||||
cmd.CommandText = "SELECT DISTINCT name FROM card_hashes";
|
||||
|
||||
await using var reader = await cmd.ExecuteReaderAsync(ct);
|
||||
while (await reader.ReadAsync(ct))
|
||||
{
|
||||
names.Add(reader.GetString(0));
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
public async Task DeleteByCardIdAsync(string cardId, CancellationToken ct = default)
|
||||
{
|
||||
await using var cmd = _connection.CreateCommand();
|
||||
cmd.CommandText = "DELETE FROM card_hashes WHERE card_id = $card_id";
|
||||
cmd.Parameters.AddWithValue("$card_id", cardId);
|
||||
await cmd.ExecuteNonQueryAsync(ct);
|
||||
}
|
||||
|
||||
public async Task ClearAsync(CancellationToken ct = default)
|
||||
{
|
||||
await using var cmd = _connection.CreateCommand();
|
||||
cmd.CommandText = "DELETE FROM card_hashes";
|
||||
await cmd.ExecuteNonQueryAsync(ct);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_connection.Dispose();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue