Files
YKanBan/YKanBan/Storage/StorageExceptions.cs
T
yyc12345 31fc58d9c7 feat(m1): storage layer
- Shared SQLite plumbing: PRAGMAs (WAL/NORMAL/foreign_keys) and
  user_version migrations with typed SchemaVersionException
- Workspace folder: .ykanban initialization, empty schema with
  DDL-level constraints, preset column seeding (ResX-driven),
  exclusive lock file with holder diagnostics
- AppData folder: app.db workspace registry (injectable clock),
  app.json config store with kebab-case JSON names via explicit
  [JsonProperty]/[EnumMember], nested sections, corrupt-file backup
- ResX infrastructure under Assets/Locales (en + zh-Hans) with
  MSBuild strongly-typed public Resources class
- 54 unit tests: DDL constraints, migrations, PRAGMAs, lock
  exclusivity, config degradation, culture-aware presets
2026-10-01 18:17:47 +08:00

91 lines
3.5 KiB
C#

namespace YKanBan.Storage;
/// <summary>
/// Typed exceptions thrown by the YKanBan storage and application layers.
/// Exception messages are always English and never localized; the UI maps
/// exception types to localized resource keys instead.
/// </summary>
public abstract class YKanBanException : Exception
{
/// <summary>Creates an exception with an English diagnostic message.</summary>
protected YKanBanException(string message, Exception? innerException = null)
: base(message, innerException)
{
}
}
/// <summary>Signals that the workspace folder does not exist on disk.</summary>
public sealed class WorkspaceDirectoryMissingException : YKanBanException
{
/// <summary>The folder path that was expected to exist.</summary>
public string FolderPath { get; }
/// <summary>Creates an exception for a folder that is absent on disk.</summary>
public WorkspaceDirectoryMissingException(string folderPath)
: base($"The folder does not exist: {folderPath}")
{
FolderPath = folderPath;
}
}
/// <summary>Signals that the folder has no .ykanban structure yet.</summary>
public sealed class WorkspaceNotInitializedException : YKanBanException
{
/// <summary>The folder path that lacks the .ykanban structure.</summary>
public string FolderPath { get; }
/// <summary>Creates an exception for a folder without .ykanban.</summary>
public WorkspaceNotInitializedException(string folderPath)
: base($"The folder is not a YKanBan workspace (missing .ykanban): {folderPath}")
{
FolderPath = folderPath;
}
}
/// <summary>Signals that another instance holds the workspace lock.</summary>
public sealed class WorkspaceLockException : YKanBanException
{
/// <summary>The lock file that could not be acquired.</summary>
public string LockFilePath { get; }
/// <summary>Best-effort diagnostics (PID/machine/time) read from the lock file, if readable.</summary>
public string? HolderDiagnostics { get; }
/// <summary>Creates an exception for a failed lock acquisition.</summary>
public WorkspaceLockException(string lockFilePath, string? holderDiagnostics, Exception innerException)
: base(BuildMessage(lockFilePath, holderDiagnostics), innerException)
{
LockFilePath = lockFilePath;
HolderDiagnostics = holderDiagnostics;
}
/// <summary>Composes the message, including holder details when they were readable.</summary>
private static string BuildMessage(string lockFilePath, string? holderDiagnostics)
{
string message = $"The workspace is locked by another instance: {lockFilePath}";
if (!string.IsNullOrEmpty(holderDiagnostics))
{
message += $" Lock holder: {holderDiagnostics}";
}
return message;
}
}
/// <summary>Signals that the stored schema version is not manageable by this build.</summary>
public sealed class SchemaVersionException : YKanBanException
{
/// <summary>The user_version value found in the database.</summary>
public long StoredVersion { get; }
/// <summary>The latest schema version this build understands.</summary>
public int SupportedVersion { get; }
/// <summary>Creates an exception for an unmanageable schema version.</summary>
public SchemaVersionException(long storedVersion, int supportedVersion)
: base($"Database schema version {storedVersion} is newer than the latest supported version {supportedVersion}.")
{
StoredVersion = storedVersion;
SupportedVersion = supportedVersion;
}
}