Skip to content

Rewrite DB layer to use a Dapper provider abstraction (MySQL + SQLite)#11

Merged
Ravid-A merged 17 commits into
mainfrom
feat/database-provider
Jun 5, 2026
Merged

Rewrite DB layer to use a Dapper provider abstraction (MySQL + SQLite)#11
Ravid-A merged 17 commits into
mainfrom
feat/database-provider

Conversation

@Ravid-A

@Ravid-A Ravid-A commented Jun 5, 2026

Copy link
Copy Markdown
Owner

Summary

Rewrites the plugin's database layer to use a provider abstraction over Dapper, with swappable MySQL/MariaDB and SQLite backends selected via config, and replaces the old callback/MySqlDataReader API with async/await + parameterized queries.

The old Database class (static, MySQL-only, interpolated SQL passed to callback delegates) is gone. SQL injection vectors from string interpolation are eliminated.

What changed

  • IDatabaseProvider + SqliteProvider / MySqlProvider — engine-specific connection creation and CREATE TABLE DDL only.
  • WeaponStore — engine-agnostic async, parameterized CRUD (InitializeAsync, GetUserAsync, CreateUserAsync, SaveUserAsync) over Dapper. SQL is written as C# """ raw string literals.
  • DatabaseProviderFactory — builds the provider from config; resolves relative SQLite paths against the plugin module directory.
  • Config — new Provider ("mysql" default / "sqlite") and SqlitePath fields with provider-branched IsValid().
  • Core / Utils — migrated to the async store with correct CounterStrikeSharp thread marshaling: SteamID/name read on the game thread, DB work on a Task.Run, results applied via Server.NextFrame. Disconnect-during-load and unauthorized-player races are guarded. Plugin unload flushes saves synchronously.
  • Tests — new xUnit project (11 tests) covering the SQLite provider, WeaponStore CRUD (incl. a SQL-injection safety test), and the factory/config validation.
  • CI — GitHub Actions workflow builds the plugin (Release) and runs the tests on push/PR.
  • Docs — README documents the Provider/SqlitePath config with MySQL and SQLite examples.

Also included: a couple of small robustness fixes surfaced in review (skip players before Steam auth completes; accept port 65535) and an unrelated RetakeCapability.cs null-check simplification.

Behavior parity

Weapon-index clamping, insert-on-first-seen, update-on-leave, and the give_awp int↔enum round trip are all preserved.

Testing

  • dotnet build RetakesAllocator.csproj -c Release → succeeds, 0 warnings.
  • dotnet test11/11 passing.
  • Not exercised in CI: live in-game behavior on a running CS2 server (requires the runtime).

Ravid-A and others added 17 commits June 5, 2026 15:33
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace static Database callbacks with WeaponStore async calls.
Core.InitializeDatabase uses DatabaseProviderFactory; Utils.AddPlayerToList
and RemovePlayerFromList use Task.Run + Server.NextFrame for threading safety.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Guards the Server.NextFrame callback in AddPlayerToList so weapon
preferences from an in-flight async DB load are not written into a
Player that already left (and whose slot may have been reused).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replaces concatenated string SQL with C# """ raw string literals in
WeaponStore CRUD and both providers' CREATE TABLE DDL. No behavior
change; verified by the existing SQLite provider + WeaponStore tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Collapse the if-null-throw block into a ?? throw expression when
assigning RetakesPluginEventSender.
…ng helper

Deletes Modules/Database.cs (fully superseded by WeaponStore + the
provider abstraction) and the now-unused Config.BuildConnectionString()
whose only caller was the old Database.Connect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- AddPlayerToList: skip players whose Steam authorization isn't ready
  yet (prevents an AuthorizedSteamID null deref during map start /
  hot reload); they are added later via OnClientAuthorized.
- ConnectionConfig.IsValid: accept port 65535 (was excluded by a
  strict < bound).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a GitHub Actions workflow that restores, builds the plugin in
Release, and runs the xUnit test suite on .NET 8.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Ravid-A
Ravid-A merged commit f36a88b into main Jun 5, 2026
2 checks passed
Ravid-A added a commit that referenced this pull request Jun 8, 2026
Rewrite DB layer to use a Dapper provider abstraction (MySQL + SQLite)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant